Unix Technical Forum

Fix for msdosfs panic

This is a discussion on Fix for msdosfs panic within the lucky.openbsd.tech forums, part of the OpenBSD category; --> Executive summary: There's a diff at the end that stops some corrupt msdos filesystems from causing a panic() at ...


Go Back   Unix Technical Forum > Unix Operating Systems > OpenBSD > lucky.openbsd.tech

FAQ Members List Calendar Search Today's Posts Mark Forums Read
  #1 (permalink)  
Old 02-22-2008, 12:19 PM
Tom Cosgrove
 
Posts: n/a
Default Fix for msdosfs panic

Executive summary:

There's a diff at the end that stops some corrupt msdos filesystems from
causing a panic() at mount. If you can test, please check that it does
not prevent you from mounting any valid filesystems, and report back to
me.


Long version (including successful tests of this diff with the six msdos
filesystems I have to hand for camera cards/flash drives/mp3 players):

Mark sent me an MS-DOS filesystem which causes our msdosfs code to
panic:

uvm_fault(xxx) -> d
kernel: page fault trap, code=0
Stopped at fillinusemap+0xd7: movzbl 0(%esi,%eax,1),%edx

This is probably not the best way do discover that you have a corrupt
filesystem.

And the filesystem in question really is hosed. hexdump -C:

00000000 00 00 00 2b 24 6d 69 46 49 48 43 00 02 04 01 00 |...+$miFIHC.....|
00000010 02 00 02 00 00 f8 31 00 3f 00 20 00 3f 00 00 00 |.....x1.?. .?...|
00000020 5c d9 03 00 80 00 29 58 30 d5 12 4e 4f 20 4e 41 |\Y....)X0U.NO NA|
00000030 4d 45 20 20 20 20 46 41 54 31 36 20 20 20 00 00 |ME FAT16 ..|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000200 00 00 00 2b 24 6d 69 46 49 48 43 00 02 04 01 00 |...+$miFIHC.....|
00000210 02 00 02 00 00 f8 31 00 3f 00 20 00 3f 00 00 00 |.....x1.?. .?...|
00000220 5c d9 03 00 80 00 29 58 30 d5 12 4e 4f 20 4e 41 |\Y....)X0U.NO NA|
00000230 4d 45 20 20 20 20 46 41 54 31 36 20 20 20 00 00 |ME FAT16 ..|
00000240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000400 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ||
*
00078000 b5 b7 3c 9a 88 13 cf 8a 7d 1e 2c bb e8 c4 c1 0a |57<...O.}.,;hDA.|
00078010 36 bb 9b 5b a8 7e 92 26 e6 d4 bc fb 5b b1 f5 37 |6;.[(~.&fT<{[1u7|
00078020 d4 d3 25 9d 1e ba a3 ef 9e 36 20 8b 8f 43 a0 76 |TS%..:#o.6 ..C v|

i.e. the whole area where the FAT and root directory would be has been
overwritten with 0xFF bytes. No chance of recovery. (Sorry, Mark.)

The crash happens in msdosfs_fat.c:fillinusemap(), at the getushort()
call:

if (FAT32(pmp))
readcn = getulong(&bp->b_data[bo]);
else
HERE>>> readcn = getushort(&bp->b_data[bo]);
if (FAT12(pmp) && (cn & 1))
readcn >>= 4;
readcn &= pmp->pm_fatmask;

This is within a for() loop for cn from first cluster to last cluster.

Going back and looking at the filesystem header, we see:

Bytes per sector: 512
Sectors per cluster: 4
Reserved sectors: 1
Number of FATs: 2
Root Dir Entries: 512
Old Total Sectors: 0
Media indicator: F8
Sectors in a FAT: 49
Total sectors: 252,252

so we were heading to read information for up to 252,252/4 = 63,063
clusters, but the FAT allegedly only has 49 sectors in it, each of which
can hold information on 512/2 = 256 clusters, for a total of 49 * 256 =
12,544 clusters in the FAT. In my testing, it was actually when we
tried to get readcn for cluster 14,336 that we hit an unmapped page and
died.

Now, obviously this 49 sectors/FAT value is wrong, but since both
copies of the FAT have been trashed we can't begin to guess the correct
value.

But it would be great if we didn't try to read past the end of the FAT
at all. Therefore I propose the diff at the end. It will abort the
mount if there are not enough sectors in the FAT (according to the
filesystem header) to store information about all the clusters that
are in the filesystem.

It stops the panic on the corrupt filesystem Mark sent me, and does not
interfere with the operation of any of the valid filesystems I have to
hand.

zinc $ sudo vnconfig -c svnd0 /var/tmp/kettenis.fs
Password:
zinc $ sudo mount -t msdos /dev/svnd0c /mnt
msdosfs_mountfs(): FAT is too small
mount_msdos: /dev/svnd0c on /mnt: Inappropriate file type or format
zinc $ sudo vnconfig -u svnd0

zinc $ sudo mount /cf
zinc $ ls -l /cf
total 121822
-rwxr-xr-x 1 root wheel 1916782 Feb 15 22:12 dscf0261.jpg
-rwxr-xr-x 1 root wheel 1868876 Feb 15 22:12 dscf0263.jpg
-rwxr-xr-x 1 root wheel 1903796 Feb 15 22:12 dscf0279.jpg
-rwxr-xr-x 1 root wheel 1883124 Feb 15 22:11 dscf0282.jpg
-rwxr-xr-x 1 root wheel 1865769 Feb 15 22:10 dscf0347.jpg
-rwxr-xr-x 1 root wheel 1934449 Feb 15 22:10 dscf0349.jpg
-rwxr-xr-x 1 root wheel 1932140 Feb 15 22:09 dscf0389.jpg
-rwxr-xr-x 1 root wheel 1936589 Feb 15 22:08 dscf0392.jpg
-rwxr-xr-x 1 root wheel 1917505 Feb 15 22:08 dscf0408.jpg
-rwxr-xr-x 1 root wheel 1940802 Feb 15 22:06 dscf0420.jpg
-rwxr-xr-x 1 root wheel 2008697 Feb 15 22:06 dscf0473.jpg
-rwxr-xr-x 1 root wheel 1861787 Feb 15 22:06 dscf0482.jpg
-rwxr-xr-x 1 root wheel 1883828 Feb 15 22:05 dscf0521.jpg
-rwxr-xr-x 1 root wheel 1918612 Feb 15 22:04 dscf0524.jpg
-rwxr-xr-x 1 root wheel 1846415 Feb 15 22:04 dscf0540.jpg
-rwxr-xr-x 1 root wheel 1806521 Feb 15 22:03 dscf0544.jpg
-r-xr-xr-x 1 root wheel 2021258 Feb 15 22:02 dscf0631.jpg
-r-xr-xr-x 1 root wheel 1810664 Feb 15 22:02 dscf0636.jpg
-r-xr-xr-x 1 root wheel 1781688 Feb 15 22:01 dscf0645.jpg
-r-xr-xr-x 1 root wheel 1771589 Feb 15 22:00 dscf0647.jpg
-r-xr-xr-x 1 root wheel 1833478 Feb 15 22:00 dscf0650.jpg
-r-xr-xr-x 1 root wheel 1862033 Feb 15 21:59 dscf0668.jpg
-r-xr-xr-x 1 root wheel 1854509 Feb 15 21:59 dscf0706.jpg
-r-xr-xr-x 1 root wheel 1928003 Feb 15 21:58 dscf1237.jpg
-r-xr-xr-x 1 root wheel 1872838 Feb 15 21:57 dscf1269.jpg
-r-xr-xr-x 1 root wheel 1821897 Feb 15 21:57 dscf1273.jpg
-r-xr-xr-x 1 root wheel 1936066 Feb 15 21:56 dscf1311.jpg
-r-xr-xr-x 1 root wheel 1904162 Feb 15 21:55 dscf1320.jpg
-r-xr-xr-x 1 root wheel 1988093 Feb 15 21:55 dscf1350.jpg
-r-xr-xr-x 1 root wheel 1866264 Feb 15 21:54 dscf1372.jpg
-r-xr-xr-x 1 root wheel 1937037 Feb 15 21:53 dscf1396.jpg
-r-xr-xr-x 1 root wheel 1917175 Feb 15 21:53 dscf1398.jpg
-r-xr-xr-x 1 root wheel 1821700 Feb 15 21:52 dscf1404.jpg
zinc $ sudo umount /cf

zinc $ sudo mount /cf
zinc $ ls -l /cf
total 4
drwxr-xr-x 1 root wheel 2048 Feb 21 20:29 gill/
zinc $ sudo umount /cf

zinc $ sudo mount /cf
zinc $ ls -l /cf
total 10176
drwxr-xr-x 1 root wheel 4096 Feb 11 18:04 Win98-driver-P20/
-rwxr-xr-x 1 root wheel 5204066 Feb 11 18:03 Win98-driver-P20.zip
zinc $ sudo umount /cf

zinc $ sudo mount /cf
zinc $ ls -l /cf
total 96
drwxr-xr-x 1 root wheel 16384 Feb 23 11:16 01-FranzFerdinand/
drwxr-xr-x 1 root wheel 16384 Feb 23 11:11 02-TheEnid/
drwxr-xr-x 1 root wheel 16384 Feb 23 11:12 03-Various/
zinc $ sudo umount /cf

zinc $ sudo mount /cf
zinc $ ls -l /cf
zinc $ df -h /cf
Filesystem Size Used Avail Capacity Mounted on
/dev/sd0i 15.6M 0B 15.6M 0% /cf
zinc $ sudo umount /cf

zinc $ sudo mount /cf
zinc $ ls -l /cf
total 32
drwxr-xr-x 1 root wheel 16384 Dec 25 07:11 dcim/
zinc $ df -h /cf
Filesystem Size Used Avail Capacity Mounted on
/dev/sd0i 249M 19.6M 230M 8% /cf
zinc $ sudo umount /cf


dmesg during all this was as follows.

msdosfs_mountfs(): FAT is too small
umass0 at uhub0 port 1 configuration 1 interface 0
umass0: SMSC USB 2 Flash Media Device, rev 2.00/1.97, addr 2
umass0: using SCSI over Bulk-Only
scsibus0 at umass0: 2 targets
sd0 at scsibus0 targ 1 lun 0: <SMSC, USB 2 HS-CF, 1.97> SCSI0 0/direct removable
sd0: 62MB, 62 cyl, 64 head, 32 sec, 512 bytes/sec, 126976 sec total
sd1 at scsibus0 targ 1 lun 1: <SMSC, USB 2 HS-MS, 1.97> SCSI0 0/direct removable
sd1: drive offline
sd2 at scsibus0 targ 1 lun 2: <SMSC, USB 2 HS-SM, 1.97> SCSI0 0/direct removable
sd2: drive offline
sd3 at scsibus0 targ 1 lun 3: <SMSC, USB 2 HS-SD/MMC, 1.97> SCSI0 0/direct removable
sd3: drive offline
umass0: at uhub0 port 1 (addr 2) disconnected
sd0 detached
sd1 detached
sd2 detached
sd3 detached
scsibus0 detached
umass0 detached
umass0 at uhub0 port 1 configuration 1 interface 0
umass0: SMSC USB 2 Flash Media Device, rev 2.00/1.97, addr 2
umass0: using SCSI over Bulk-Only
scsibus0 at umass0: 2 targets
sd0 at scsibus0 targ 1 lun 0: <SMSC, USB 2 HS-CF, 1.97> SCSI0 0/direct removable
sd0: 122MB, 122 cyl, 64 head, 32 sec, 512 bytes/sec, 250368 sec total
sd1 at scsibus0 targ 1 lun 1: <SMSC, USB 2 HS-MS, 1.97> SCSI0 0/direct removable
sd1: drive offline
sd2 at scsibus0 targ 1 lun 2: <SMSC, USB 2 HS-SM, 1.97> SCSI0 0/direct removable
sd2: drive offline
sd3 at scsibus0 targ 1 lun 3: <SMSC, USB 2 HS-SD/MMC, 1.97> SCSI0 0/direct removable
sd3: drive offline
umass0: at uhub0 port 1 (addr 2) disconnected
sd0 detached
sd1 detached
sd2 detached
sd3 detached
scsibus0 detached
umass0 detached
umass0 at uhub0 port 1 configuration 1 interface 0
umass0: vendor 0x0d7d USB DISK 2.0, rev 2.00/0.50, addr 2
umass0: using SCSI over Bulk-Only
scsibus0 at umass0: 2 targets
sd0 at scsibus0 targ 1 lun 0: <, USB DISK 2.0, 1.16> SCSI0 0/direct removable
sd0: 248MB, 248 cyl, 64 head, 32 sec, 512 bytes/sec, 507904 sec total
umass0: at uhub0 port 1 (addr 2) disconnected
sd0 detached
scsibus0 detached
umass0 detached
umass0 at uhub0 port 1 configuration 1 interface 0
umass0: Creative Tech NOMAD MuVo NX, rev 1.10/0.01, addr 2
umass0: using SCSI over Bulk-Only
scsibus0 at umass0: 2 targets
sd0 at scsibus0 targ 1 lun 0: <CREATIVE, NOMAD MuVo NX, 0001> SCSI4 0/direct removable
sd0: 247MB, 247 cyl, 64 head, 32 sec, 512 bytes/sec, 505856 sec total
umass0: at uhub0 port 1 (addr 2) disconnected
sd0 detached
scsibus0 detached
umass0 detached
umass0 at uhub0 port 1 configuration 1 interface 0
umass0: Generic Mass Storage Device, rev 1.10/1.00, addr 2
umass0: using SCSI over Bulk-Only
scsibus0 at umass0: 2 targets
sd0 at scsibus0 targ 1 lun 0: <Generic, USB XD Reader, 1.05> SCSI0 0/direct removable
sd0: 15MB, 15 cyl, 64 head, 32 sec, 512 bytes/sec, 32000 sec total
umass0: at uhub0 port 1 (addr 2) disconnected
sd0 detached
scsibus0 detached
umass0 detached
umass0 at uhub0 port 1 configuration 1 interface 0
umass0: Generic Mass Storage Device, rev 1.10/1.00, addr 2
umass0: using SCSI over Bulk-Only
scsibus0 at umass0: 2 targets
sd0 at scsibus0 targ 1 lun 0: <Generic, USB XD Reader, 1.05> SCSI0 0/direct removable
sd0: 250MB, 250 cyl, 64 head, 32 sec, 512 bytes/sec, 512000 sec total
umass0: at uhub0 port 1 (addr 2) disconnected
sd0 detached
scsibus0 detached
umass0 detached


I'd really like people to test that that does not stop any currently-
working filesystems from working. Positive results (i.e. everything
still works, cases where corrupt filesystems stop panic()ing) to me;
negative results (it stops you mounting a valid filesystem) to the
list.

Thanks

Tom


Index: msdosfs_vfsops.c
================================================== =================
RCS file: /cvs/src/sys/msdosfs/msdosfs_vfsops.c,v
retrieving revision 1.36
diff -u -r1.36 msdosfs_vfsops.c
--- msdosfs_vfsops.c 2 Mar 2005 00:46:10 -0000 1.36
+++ msdosfs_vfsops.c 14 Mar 2005 23:11:19 -0000
@@ -273,6 +273,7 @@
int ronly, error;
int bsize = 0, dtype = 0, tmp;
uint32_t dirsperblk;
+ uint32_t maxclusters = 0;

/*
* Disallow multiple mounts of the same device.
@@ -511,6 +512,48 @@
*/
brelse(bp);
bp = NULL;
+
+ /*
+ * An additional sanity check:
+ * The number of sectors in the FAT must be enough to hold "next
+ * cluster" information for all of the clusters in the file system.
+ */
+ if (pmp->pm_fatmult != 0) {
+ /*
+ * Work out the max number of FAT entries in the FAT.
+ * This is the maximum number of clusters this filesystem
+ * can support.
+ *
+ * One sector can support (bytesPerSec * fatdiv / fatmult)
+ * clusters, so multiply by number of sectors in a FAT to
+ * get the total. Do it this way round to avoid rounding
+ * errors (in FAT12, one sector supports 341 1/3 clusters).
+ */
+ maxclusters = (pmp->pm_BytesPerSec * pmp->pm_fatdiv *
+ pmp->pm_FATsecs) / pmp->pm_fatmult;
+
+ /*
+ * In case the calculation above wraps around (since sectors
+ * per FAT is a 32-bit value), we work things out the other
+ * way, too: Even on FAT32, only 28 bits are used for the
+ * cluster number, so there is an absolute maximum of
+ * 0x10000000 clusters. Work out how big the FAT would need
+ * to be to store all of these (it's about 2 million sectors,
+ * or 1 GB). If we've got a FAT this big, we can support
+ * the max number of clusters we'll ever get on a FAT f/s.
+ * At least, on any of the ones we support at the moment.
+ */
+ if (pmp->pm_FATsecs >= 0x10000000 * 4 / pmp->pm_BytesPerSec)
+ maxclusters = 0x10000000;
+ }
+
+ if (maxclusters > 0 && pmp->pm_nmbrofclusters > maxclusters) {
+#ifdef DIAGNOSTIC
+ printf("msdosfs_mountfs(): FAT is too small\n");
+#endif
+ error = EFTYPE;
+ goto error_exit;
+ }

/*
* Check FSInfo

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Forum Jump


All times are GMT. The time now is 07:53 PM.


Powered by vBulletin® Version 3.6.5
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
www.UnixAdminTalk.com