]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
blkid: don't read past end of FAT32 cluster chain
authorJohn Lindgren <john.lindgren@tds.net>
Wed, 11 May 2011 18:32:18 +0000 (14:32 -0400)
committerKarel Zak <kzak@redhat.com>
Wed, 11 May 2011 22:20:56 +0000 (00:20 +0200)
When looking for a volume label on a FAT32 filesystem, blkid does not
correctly handle special cluster values in the range 0x0FFFFFF8 to
0x0FFFFFFF, which mark the last cluster in a chain. As a result, it
begins to read [what it treats as] FAT entries from past the end of the
FAT. Depending on the data read, it may then try to parse random data
from the filesystem (including user files, free space, and other
directories) as though it were part of the root directory.

Because parsing stops early when a volume label is found, the problem
only occurs on filesystems without a volume label. When it occurs, it
may result in a long sequence of lseek and read calls; on an older IDE
drive with a 2 GB FAT32 partition, this amounted to around 3 seconds of
disk I/O.

After patching, blkid stop parsing as soon as it reaches a cluster value
greater than or equal to the number of entries in the FAT.

[kzak@redhat.com: - add le32_to_cpu()]

Signed-off-by: John Lindgren <john.lindgren@tds.net>
shlibs/blkid/src/superblocks/vfat.c

index 782bc143be2d8ad3bd1ff5aefd76212f801e8f96..1584efae952f9613b1b4ad891c559d7259de4810 100644 (file)
@@ -326,9 +326,11 @@ static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag)
                /* Search the FAT32 root dir for the label attribute */
                uint32_t buf_size = vs->vs_cluster_size * sector_size;
                uint32_t start_data_sect = reserved + fat_size;
+               uint32_t entries = le32_to_cpu(vs->vs_fat32_length) *
+                                       sector_size / sizeof(uint32_t);
                uint32_t next = le32_to_cpu(vs->vs_root_cluster);
 
-               while (next && --maxloop) {
+               while (next && next < entries && --maxloop) {
                        uint32_t next_sect_off;
                        uint64_t next_off, fat_entry_off;
                        int count;