Hi,

our guard pages just told me that writefat is vulnerable to an off by one
for FAT12 filesystems.  They shouldn't be that common anymore, but better
be safe than sorry.

The diff looks confusing at first, but this default-block is just split
into two cluster blocks, as it's done in readfat (line 176).

This diff has an effect on variable p, but from my point of view, it's no
issue because it's not used after for-loop anymore -- and the for-loop
will stop if "cl + 1 < boot->NumClusters".

Enough talk, here's how to trigger it (i386, 1M iso triggers it for me):

Create a 1M filesystem:
# dd if=/dev/zero of=poc.iso bs=1M count=1
# vnconfig vnd0c poc.iso
# newfs_msdos vnd0c

Break FAT and try to repair
# dd if=/dev/zero of=poc.iso conv=notrunc bs=1 count=1 seek=512
# fsck_msdos vnd0c

Output:
** /dev/rvnd0c (vnd0c)
** Phase 1 - Read and Compare FATs
FAT starts with odd byte sequence (00ffff)
Correct? [Fyn] y
** Phase 2 - Check Cluster Chains
Segmentation fault (core dumped)
# _


Tobias

Index: fat.c
===================================================================
RCS file: /cvs/src/sbin/fsck_msdos/fat.c,v
retrieving revision 1.19
diff -u -p -r1.19 fat.c
--- fat.c       9 Jun 2014 09:13:33 -0000       1.19
+++ fat.c       9 Jun 2014 19:06:26 -0000
@@ -471,13 +471,15 @@ writefat(int fs, struct bootblock *boot,
                default:
                        if (fat[cl].next == CLUST_FREE)
                                boot->NumFree++;
-                       if (cl + 1 < boot->NumClusters
-                           && fat[cl + 1].next == CLUST_FREE)
-                               boot->NumFree++;
                        *p++ = (u_char)fat[cl].next;
-                       *p++ = (u_char)((fat[cl].next >> 8) & 0xf)
-                              |(u_char)(fat[cl+1].next << 4);
-                       *p++ = (u_char)(fat[++cl].next >> 4);
+                       *p++ = (u_char)((fat[cl].next >> 8) & 0xf);
+                       cl++;
+                       if (cl >= boot->NumClusters)
+                               break;
+                       if (fat[cl].next == CLUST_FREE)
+                               boot->NumFree++;
+                       *p |= (u_char)(fat[cl + 1].next << 4);
+                       *p++ = (u_char)(fat[cl + 1].next >> 4);
                        break;
                }
        }

Reply via email to