Sec, blogmal! - rev-eng - cryptoloop-problems

Categories:

Everything

Mai '17

FrFrFrFrFrFrFr
1234567
891011121314
15161718192021
22232425262728
2930311234

Archive:

Thu, 19 Jan 2006

Probleme mit Cryptoloop und Suse

Eigentlich gehört das in die Kategorie Das glaubt mir doch eh keiner.

Gestern hat ein Kollege hier seinen Laptop unvorsichtigerweise lang genug ohne Strom stehen lassen, und plötzlich war er aus. Nunja, ärgerlich weil vermeidbar, aber an sich kein Problem, man hat ja schliesslich ein journaling Filesystem.

Denkste.

Beim Booten weigert sich das Teil hartnäckig die Filesysteme wieder zu mounten. Die erste Befürchtung, daß er die Passphrase vergessen hat, läßt sich noch recht einfach zerstreuen:

 kiste:~# losetup -e twofish256 /dev/loop0 /data/crypt5
 Password:
 kiste:~# file -s /dev/loop0
 /dev/sda2: Linux rev 1.0 ext3 filesystem data (needs journal recovery)

Lang hält die Freude nicht an, denn mounten lässt es sich nicht. Das Journal hat irgendwelche interessanten Fehler…

 kiste:~# fsck /dev/loop0
 fsck 1.34 (25-Jul-2003)
 e2fsck 1.34 (25-Jul-2003)
 Superblock has a bad ext3 journal (inode 8).
 Clear<y>? yes
*** ext3 journal has been deleted - filesystem is now ext2 only ***

 Superblock doesn't have has_journal flag, but has ext3 journal inode.
 Clear<y>? yes

Und fährt dann dann fort, das FS komplett zu schreddern. Nicht gut.

Und wenn man es als ext2fs mounten will, bekommt man das im syslog:

 Jan 17 15:13:30 kiste kernel: EXT2-fs: loop(7,0): \
 couldn't mount because of unsupported optional features (4).

(Was ist denn das für eine Schizophrenie? Entweder optional, oder nicht!)

Unter FreeBSD hab ich dem ext2fs-kernelmodul mal zum Testen so gepatcht, daß es das Mounten trotzdem erlaubt, und siehe da, man sah einen Grossteil der Files. Leider konnte man aber nur einen kleinen Teil davon lesen…

Nun, mit debugfs kann man das journal zwar löschen, aber mounten kann mans nachher immer noch nicht. Damn. - Schauen wir uns nochmal genauer an, was fsck noch so alles sagt:

 Inode count in superblock is 640002, should be 640000.
 Fix<y>? yes

Hm. Strange. Ein Offset von 2 Inodes? Keine Ahnung wie sowas passieren kann…

 /dev/loop0 was not cleanly unmounted, check forced.
 Pass 1: Checking inodes, blocks, and sizes
 Group 0's block bitmap at 10 conflicts with some other fs block.
 Relocate<y>? 

Irgendwie klingt das ungesund. Was ist da wohl passiert?

Naja, nachdem auch schon der inode count kaputt ist, habe ich mir mal den Superblock-Inhalt angeschaut:

 kiste:~# debugfs /dev/loop0
 debugfs 1.34 (25-Jul-2003)
 debugfs: stats
 [...]

Die Werte sahen eigentlich alle gut aus… bis auf das da:

 Group  0: block bitmap at 10, inode bitmap at 3, inode table at 4
           4 free blocks, 15959 free inodes, 2 used directories

Die block bitmap (ja, die über die der fsck meckert) ist at 10. In den anderen Groups siehts so aus:

 Group  1: block bitmap at 32770, inode bitmap at 32771, inode table at 32772
           0 free blocks, 15793 free inodes, 85 used directories
 Group  2: block bitmap at 65536, inode bitmap at 65537, inode table at 65538
           0 free blocks, 15323 free inodes, 92 used directories

Da ist sie also genau immer eins vor der inode bitmap.

Da mir so langsam die Ideen ausgegangen sind, hab' ich mal ein bisschen in einem Hexdump des Filesystems rumgesucht:

 kiste:~# dd if=/dev/loop0 bs=512 count=20 of=t
 kiste:~# xxd <t >t.xxd
 kiste:~# vim t.xxd

<such such, fündig bei 0×1000>

 0001000: 0a00 0000 0300 0000 0400 0000 0400 573e  ...........…W>

genau die 3 Zahlen der Group 0 von oben. Machen wir also aus dem 0a ein 02, und schreiben es zurück:

 kiste:~# xxd -r <t.xxd >t.neu
 kiste:~# dd if=t.neu bs=512 of=/dev/loop0 conv=notrunc

und schmeissen den fsck nochmal an. Der sagt jetzt:

 Group 16's block bitmap at 524297 conflicts with some other fs block.
 Relocate<y>?

Hm. debugfs sagt uns wieder:

 Group 16: block bitmap at 524297, inode bitmap at 524289, inode table at 524290
           10275 free blocks, 15858 free inodes, 6 used directories

dumpe2fs hat die gleiche Information, nur für unseren Fall schöner aufbereitet:

 Group 16: (Blocks 524288-557055)
   Block bitmap at 524297 (+9), Inode bitmap at 524289 (+1)
   Inode table at 524290-524789 (+2)

beim Durchsehen, fällt einem nochmal das gleiche Problem in Group 32 auf:

 Group 32: (Blocks 1048576-1081343)
   Block bitmap at 1048586 (+10), Inode bitmap at 1048577 (+1)
   Inode table at 1048578-1049077 (+2)

Ok, gleich nochmal in t.xxd rumspielen.

 0001200: 0900 0800 0100 0800 0200 0800 2328 f23d  ............#(.=

machen wir aus dem 09 ein 00 und

 0001400: 0a00 1000 0100 1000 0200 1000 0000 363e  ...........…6>

ändern wir das 0a in ein 00. Dann schreiben wir es (wie oben) zurück:

 kiste:~# xxd -r <t.xxd >t.neu
 kiste:~# dd if=t.neu bs=512 of=/dev/loop0 conv=notrunc

Aber leider selbst jetzt ist das Filesystem noch recht kaputt. Der Versuch mit debugfs rdump Daten rauszukopieren erzeugt immernoch recht viele Fehler ;-/

Aber!

Ist euch was aufgefallen? Ja?

Die drei Stellen an denen wir was editiert haben sind 0×1000, 0×1200, 0×1400 - verdammt regelmässig, oder?

Schauen wir nochmal genauer auf die Änderungen:

         War   Soll
 0×1000  0A     02
 0×1200  09     00
 0×1400  0A     00

Hm. Der Unterschied ist in allen drei Fällen ungefähr gleich groß. Schauen wir uns das binär an:

         War    Soll  War XOR Soll
 0×1000  1010b  0010b   1000b
 0×1200  1001b  0000b   1001b
 0×1400  1010b  0000b   1010b

He. Das sieht aus wie ein Zähler. Und 0×200 (512) ist genau eine übliche Blockgröße.

Ein paar prüfende Blicke in den Hexdump zeigen, daß in allen Blöcken die nur aus 0-Bytes bestehen, am Anfang genau die Blocknummer drinsteht. Dieser Verdacht reicht für einen Test. Schnell ein C-Programm zusammengehackt, das ein File in 512-Byte-Blöcken kopiert, und immer vorne die Blocknummer reinXORt.

Gut, ein kurzer Dämpfer, weil fread() auf dem Linux hier coredumpt weil das File größer als 2G ist, aber das läßt sich mit den passenden #defines hinbiegen.

Schnell den Ursprungszustand wieder herstellen:

 kiste:~# dd if=t bs=512 of=/dev/loop0 conv=notrunc
 kiste:~# losetup -d /dev/loop0

Das Programm mal drüberlaufen lassen:

 kiste:~# gcc -o xorme -Wall xorme.c
 kiste:~# ./xorme crypt5 crypt5.out
 sector: 9c4000: err(eof?) while reading

Und sehen was rauskommt:

 kiste:~# losetup /dev/loop0 crypt5.out
 kiste:~# fsck /dev/loop0
 fsck 1.34 (25-Jul-2003)
 e2fsck 1.34 (25-Jul-2003)
 /dev/loop0: recovering journal
 /dev/loop0: clean, 18990/640000 files, 1205770/1280000 blocks

Yay!

Ein Test mit mount liefert auch das befriedigende Ergebniss, daß alle Dateien wieder vorhanden, und auch lesbar sind. Das macht einen glücklichen Kollegen, ein paar Tafeln Schokolade für mich, und wieder was über die Interna von ext2fs/ext3fs gelernt.

Bleibt eigentlich nur noch die Frage, wie das passieren konnte. Der aktuelle Verdacht ist, daß durch irgendein SuSe-Update sich was an dem crypto-loop Treiber geändert hat und das erst durch den Reboot (und damit verbundene reattach/remount) aufgefallen ist. Wenn irgendeiner der Leser da mehr Ahnung hat, wäre ich für einen Hinweis natürlich dankbar.

– Sec

Update: Das Problem ist SuSE bekannt und dort beschrieben. (Dank an Nick)

Seufz


posted at: 10:48 | Category: /rev-eng | permanent link to this entry | 1 comment (trackback)
 

Your Comment
 
Name:
URL/Email: [http://... or mailto:you@wherever] (optional)
Title: (optional)
Comment:
Save my Name and URL/Email for next time
(Note that comments will be rejected unless you enter 42 in the following box: )

powered by blosxom
in 0.00 s