/* basquiat's lovely winter riot */: a unique and beautiful snowflake in your heart's lovely winter riot

Limerick

There once was a message to test
Repeated unto being a pest
    While marked to ignore
    It was seen more and more
Until other begged, “Give it a rest!”

Darren Chandler auf OpenBSD-misc als Reaktion auf die allseits beliebten Fernfunktionsevaluationen hochfrequentierter Mailinglisten.

1803 Klicks

Virtualisierung als Sicherheitsfeature?

Eine Diskussion zu Xen und OpenBSD samt der scheu hervorgebrachten Meinung »Virtualization seems to have a lot of security benefits« provozierte einmal mehr einen weiteren Grundsatzerguss Theo de Raadts auf der öffentlichen Mailingliste des selbsternannt proaktiven Betriebssystems - in bekanntem Tonfall:

»You’ve been smoking something really mind altering, and I think you should share it. x86 virtualization is about basically placing another nearly full kernel, full of new bugs, on top of a nasty x86 architecture which barely has correct page protection. Then running your operating system on the other side of this brand new pile of shit. You are absolutely deluded, if not stupid, if you think that a worldwide collection of software engineers who can’t write operating systems or applications without security holes, can then turn around and suddenly write virtualization layers without security holes. You’ve seen something on the shelf, and it has all sorts of pretty colours, and you’ve bought it. That’s all x86 virtualization is.«

Diesem Kontext sei “An Empirical Study into the Security Exposure to Hosts on Hostile Virtualized Environments” zum Geleit gegeben. Das wenig überraschende Fazit: Auch virtuelle Maschinen möchten abgesichert und regelmäßig gepflegt sein. Unfehlbar sind sie nicht.

2364 Klicks

My first OpenBSD kernelbug

Mit ‘pf’, ‘pfsync’ und ‘CARP’ bietet OpenBSD eine vergleichsweise einfach zu administrierende, leistungsfähige Infrastruktur für das Failover redundant aufgesetzter Firewalls. Neben dem essentiellen Paketfilter ‘pf’ kümmert sich ’pfsync’ in diesem Kontext um das synchrone Statehandling der verschiedenen Nodes, um bei einem Wechsel des aktiven Firewallrechners im Cluster bestehende Netzwerkverbindungen aufrecht erhalten zu können. Der Einsatz des Common Address Redundancy Protocols CARP erledigt auf OSI-Schicht 2 und 3 dabei das eigentliche Procedere zur Hochverfügbarkeit, bei dem es klassischerweise zwischen MASTER- und BACKUP-Rollen auf Interface-Ebene unterscheidet. Eine detailreichere doch kurz gehaltene Übersicht bietet der Artikel “Firewall Failover with pfsync and CARP”.

Mit dem lange überfälligen Upgrade eines schon etwas in die Jahre gekommenen OpenBSD 3.7 Clusters auf Release 4.1 erhielt ich die einmalige Chance, meinen ersten OpenBSD-Kernelbug - wenn auch eher unfreiwillig in gewohnt unpassendster Situation - zu entdecken; das sequentielle Neuladen der Regeln des auf zwei Clusternodes verteilten Paketfilters führte nach wenigen Iterationen regelmäßig zum Absturz des Systems:

kernel: page fault trap, code = 0
Stopped at	pfsync_insert_net_state+0x472:	movl	0(%eax,%edx,4),%edx

Für Neulinge unter den digitalen Kammerjägern beschreibt die Kurzanleitung “How to debug kernel crashes” das Erstellen verwertbarer Bugreports für die Entwickler - in der Regel sollte man das fehlerhafte Verhalten jedoch zuerst unter Einsatz unmodifizierter GENERIC-Kernel reproduzieren können. Gesagt, getan; nun folgend das übersetzte Kochrezept.

Mit der Analyse des Trace-Outputs (im OpenBSD-Kerneldebugger ’ddb’ per ‘trace’ aufgerufen) kann die betreffende Funktion erkannt und im Quellcode schnell lokalisiert werden. Im Falle des gestorbenen Firewallnodes lässt folgende Ausgabe das Problem auf das Sourcefile ‘sys/net/if_pfsync.c’ zurückführen:

pfsync_insert_net_state(e34d4038,1,8,e34d4038) at pfsync_insert_net_state+0x472

pfsync_input(e3486a00,14,0,0,d0d1a034) at pfsync_input+0xa21
ipv4_input(e3486a00,d0d0e900,0,d08ab000,30) at ipv4_input+0x4f1
ipintr(d0640058,d30010,d08a0010,d08a0010,d08ab000) at ipintr+0x70
Bad frame pointer: 0xd08ace24
Erneut mit Debuginformationen kompiliert und disassembliert finden wir per ‘grep’ die fehlerhafte Funktion und addieren der dort angegebenen Speicheradresse den Offset aus unserem Trace-Output hinzu:
# grep “<pfsync_insert_net_state>” if_pfsync.dis
> 000002f4 <pfsync_insert_net_state>

Adam Riese addiert die Hexadezimalzahlen 0x2f4 + 0x472 zu 0x766 - genau in jener Zeile sollte sich innerhalb unseres disassemblierten Codes die Instruktion aus unserem Kerneltrap finden, und siehe da:

/usr/src/sys/net/if_pfsync.c:248
      756:       a1 b4 04 00 00          mov    0x4b4,%eax
      757:       R_386_32   pf_main_anchor
      75b:       66 c1 ca 08             ror    $0x8,%dx
      75f:       c1 ca 10                ror    $0x10,%edx
      762:       66 c1 ca 08             ror    $0x8,%dx
      766:       8b 14 90                mov    (%eax,%edx,4),%edx
      769:       89 55 ec                mov    %edx,0xffffffec(%ebp)
      76c:       e9 e5 fb ff ff          jmp    356 <pfsync_insert_net_state+0x62>
      771:       8d 76 00                lea    0x0(%esi),%esi

Damit haben wir die genaue Zeilenangabe des betreffenden Codeteils innerhalb der Funktion ‘pfsync_insert_net_state’ gewonnen, welche wir schon im Sourcefile ‘sys/net/if_pfsync.c’ festmachen konnten. Mit etwas Kontext sprechen also alle Indizien das folgende Konstrukt schuldig:

/*
* If the ruleset checksums match, it’s safe to associate the state
* with the rule of that number.
*/
if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && chksum_flag)
        r = pf_main_ruleset.rules[
            PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)];
else
        r = &pf_default_rule;

Tiefer bewanderte Kerneldeveloper identifizieren hier eine Racecondition zwischen den Ruleset-Reloads beider Maschinen und stellen - keine 24 Stunden nach Meldung des Bugs - den ersten Patch zur Evaluation, der mittlerweile mit Revision 1.83 im CVS des MAIN-Branches enthalten ist - und auch hier erfolgreich unter Stress gesetzt wurde:

/*
* If the ruleset checksums match, it’s safe to associate the state
* with the rule of that number.
*/
if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && chksum_flag &&
    ntohl(sp->rule) <
    pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount)
        r = pf_main_ruleset.rules[
            PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)];
else
        r = &pf_default_rule;

Das Fazit: Selbst durchaus unerfreuliche Vorkommnisse bieten bei Verfügbarkeit des Quellcodes das Potential, ungekannte Hintergründe zu verstehen und von Ihnen manchesmal Neues zu erlernen. Die Kommunikation mit den Entwicklern freier Software lässt darüber hinaus das gute Gefühl entstehen, selbst als einfacher Bote einer schlechten Nachricht beim Prozess der stetigen Verbesserung der quelloffenen Produkte positiv mitwirken zu können. Denn auch gerade davon lebt Open Source - den ausführlichen Bugreports dankbarer User.

1713 Klicks