From: Karel Zak Date: Wed, 20 Jan 2010 22:30:20 +0000 (+0100) Subject: libblkid: add sanity checks for FAT to DOS PT parser X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2b09166ddac2cd671ca28111a25e342304d6223f;p=util-linux libblkid: add sanity checks for FAT to DOS PT parser Signed-off-by: Karel Zak --- diff --git a/shlibs/blkid/src/Makefile.am b/shlibs/blkid/src/Makefile.am index 90ce9bfc..2d798b6a 100644 --- a/shlibs/blkid/src/Makefile.am +++ b/shlibs/blkid/src/Makefile.am @@ -25,7 +25,7 @@ usrlib_exec_LTLIBRARIES = libblkid.la libblkid_la_SOURCES = cache.c dev.c devname.c devno.c getsize.c llseek.c \ probe.c read.c resolve.c save.c tag.c version.c verify.c \ encode.c list.h blkidP.h superblocks/superblocks.h \ - config.c evaluate.c \ + config.c evaluate.c fat.h \ $(blkidinc_HEADERS) \ $(top_srcdir)/lib/blkdev.c \ $(top_srcdir)/lib/linux_version.c \ diff --git a/shlibs/blkid/src/fat.h b/shlibs/blkid/src/fat.h new file mode 100644 index 00000000..b3664641 --- /dev/null +++ b/shlibs/blkid/src/fat.h @@ -0,0 +1,90 @@ +#ifndef _BLKID_FAT_H +#define _BLKID_FAT_H + +/* This FAT superblock is required for: + * + * superblocks/vfat.c + * partitions/dos.c + */ + +/* Yucky misaligned values */ +struct vfat_super_block { +/* 00*/ unsigned char vs_ignored[3]; +/* 03*/ unsigned char vs_sysid[8]; +/* 0b*/ unsigned char vs_sector_size[2]; +/* 0d*/ uint8_t vs_cluster_size; +/* 0e*/ uint16_t vs_reserved; +/* 10*/ uint8_t vs_fats; +/* 11*/ unsigned char vs_dir_entries[2]; +/* 13*/ unsigned char vs_sectors[2]; +/* 15*/ unsigned char vs_media; +/* 16*/ uint16_t vs_fat_length; +/* 18*/ uint16_t vs_secs_track; +/* 1a*/ uint16_t vs_heads; +/* 1c*/ uint32_t vs_hidden; +/* 20*/ uint32_t vs_total_sect; +/* 24*/ uint32_t vs_fat32_length; +/* 28*/ uint16_t vs_flags; +/* 2a*/ uint8_t vs_version[2]; +/* 2c*/ uint32_t vs_root_cluster; +/* 30*/ uint16_t vs_fsinfo_sector; +/* 32*/ uint16_t vs_backup_boot; +/* 34*/ uint16_t vs_reserved2[6]; +/* 40*/ unsigned char vs_unknown[3]; +/* 43*/ unsigned char vs_serno[4]; +/* 47*/ unsigned char vs_label[11]; +/* 52*/ unsigned char vs_magic[8]; +/* 5a*/ unsigned char vs_dummy2[0x1fe - 0x5a]; +/*1fe*/ unsigned char vs_pmagic[2]; +} __attribute__((packed)); + +/* Yucky misaligned values */ +struct msdos_super_block { +/* 00*/ unsigned char ms_ignored[3]; +/* 03*/ unsigned char ms_sysid[8]; +/* 0b*/ unsigned char ms_sector_size[2]; +/* 0d*/ uint8_t ms_cluster_size; +/* 0e*/ uint16_t ms_reserved; +/* 10*/ uint8_t ms_fats; +/* 11*/ unsigned char ms_dir_entries[2]; +/* 13*/ unsigned char ms_sectors[2]; /* =0 iff V3 or later */ +/* 15*/ unsigned char ms_media; +/* 16*/ uint16_t ms_fat_length; /* Sectors per FAT */ +/* 18*/ uint16_t ms_secs_track; +/* 1a*/ uint16_t ms_heads; +/* 1c*/ uint32_t ms_hidden; +/* V3 BPB */ +/* 20*/ uint32_t ms_total_sect; /* iff ms_sectors == 0 */ +/* V4 BPB */ +/* 24*/ unsigned char ms_unknown[3]; /* Phys drive no., resvd, V4 sig (0x29) */ +/* 27*/ unsigned char ms_serno[4]; +/* 2b*/ unsigned char ms_label[11]; +/* 36*/ unsigned char ms_magic[8]; +/* 3e*/ unsigned char ms_dummy2[0x1fe - 0x3e]; +/*1fe*/ unsigned char ms_pmagic[2]; +} __attribute__((packed)); + + +static inline int blkid_fat_valid_media(struct msdos_super_block *ms) +{ + return 0xf8 <= ms->ms_media || ms->ms_media == 0xf0; +} + +static inline int blkid_fat_valid_sectorsize( + struct msdos_super_block *ms, + uint16_t *sector_size) +{ + unsigned char *tmp = (unsigned char *) &ms->ms_sector_size; + uint16_t ssz; + + ssz = tmp[0] + (tmp[1] << 8); + + if (ssz != 0x200 && ssz != 0x400 && ssz != 0x800 && ssz != 0x1000) + return 0; + if (sector_size) + *sector_size = ssz; + return 1; +} + + +#endif /* _BLKID_FAT_H */ diff --git a/shlibs/blkid/src/partitions/dos.c b/shlibs/blkid/src/partitions/dos.c index 21728a5a..ec2ca1eb 100644 --- a/shlibs/blkid/src/partitions/dos.c +++ b/shlibs/blkid/src/partitions/dos.c @@ -16,6 +16,7 @@ #include "partitions.h" #include "dos.h" #include "aix.h" +#include "fat.h" static const struct dos_subtypes { unsigned char type; @@ -139,18 +140,30 @@ static int probe_dos_pt(blkid_probe pr, const struct blkid_idmag *mag) if (memcmp(data, BLKID_AIX_MAGIC_STRING, BLKID_AIX_MAGIC_STRLEN) == 0) goto nothing; - p0 = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET); - /* * Now that the 55aa signature is present, this is probably * either the boot sector of a FAT filesystem or a DOS-type - * partition table. Reject this in case the boot indicator - * is not 0 or 0x80. + * partition table. */ - for (p = p0, i = 0; i < 4; i++, p++) { + { + struct msdos_super_block *ms = + (struct msdos_super_block *) data; + + if (ms->ms_fats && ms->ms_reserved && + ms->ms_cluster_size && + blkid_fat_valid_media(ms) && + blkid_fat_valid_sectorsize(ms, NULL)) + goto nothing; /* FAT */ + } + + p0 = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET); + + /* + * Reject PT where boot indicator is not 0 or 0x80. + */ + for (p = p0, i = 0; i < 4; i++, p++) if (p->boot_ind != 0 && p->boot_ind != 0x80) goto nothing; - } /* * GPT uses valid MBR diff --git a/shlibs/blkid/src/superblocks/vfat.c b/shlibs/blkid/src/superblocks/vfat.c index 71c0fbcb..b24f6075 100644 --- a/shlibs/blkid/src/superblocks/vfat.c +++ b/shlibs/blkid/src/superblocks/vfat.c @@ -18,62 +18,8 @@ #include "superblocks.h" -/* Yucky misaligned values */ -struct vfat_super_block { -/* 00*/ unsigned char vs_ignored[3]; -/* 03*/ unsigned char vs_sysid[8]; -/* 0b*/ unsigned char vs_sector_size[2]; -/* 0d*/ uint8_t vs_cluster_size; -/* 0e*/ uint16_t vs_reserved; -/* 10*/ uint8_t vs_fats; -/* 11*/ unsigned char vs_dir_entries[2]; -/* 13*/ unsigned char vs_sectors[2]; -/* 15*/ unsigned char vs_media; -/* 16*/ uint16_t vs_fat_length; -/* 18*/ uint16_t vs_secs_track; -/* 1a*/ uint16_t vs_heads; -/* 1c*/ uint32_t vs_hidden; -/* 20*/ uint32_t vs_total_sect; -/* 24*/ uint32_t vs_fat32_length; -/* 28*/ uint16_t vs_flags; -/* 2a*/ uint8_t vs_version[2]; -/* 2c*/ uint32_t vs_root_cluster; -/* 30*/ uint16_t vs_fsinfo_sector; -/* 32*/ uint16_t vs_backup_boot; -/* 34*/ uint16_t vs_reserved2[6]; -/* 40*/ unsigned char vs_unknown[3]; -/* 43*/ unsigned char vs_serno[4]; -/* 47*/ unsigned char vs_label[11]; -/* 52*/ unsigned char vs_magic[8]; -/* 5a*/ unsigned char vs_dummy2[0x1fe - 0x5a]; -/*1fe*/ unsigned char vs_pmagic[2]; -} __attribute__((packed)); - -/* Yucky misaligned values */ -struct msdos_super_block { -/* 00*/ unsigned char ms_ignored[3]; -/* 03*/ unsigned char ms_sysid[8]; -/* 0b*/ unsigned char ms_sector_size[2]; -/* 0d*/ uint8_t ms_cluster_size; -/* 0e*/ uint16_t ms_reserved; -/* 10*/ uint8_t ms_fats; -/* 11*/ unsigned char ms_dir_entries[2]; -/* 13*/ unsigned char ms_sectors[2]; /* =0 iff V3 or later */ -/* 15*/ unsigned char ms_media; -/* 16*/ uint16_t ms_fat_length; /* Sectors per FAT */ -/* 18*/ uint16_t ms_secs_track; -/* 1a*/ uint16_t ms_heads; -/* 1c*/ uint32_t ms_hidden; -/* V3 BPB */ -/* 20*/ uint32_t ms_total_sect; /* iff ms_sectors == 0 */ -/* V4 BPB */ -/* 24*/ unsigned char ms_unknown[3]; /* Phys drive no., resvd, V4 sig (0x29) */ -/* 27*/ unsigned char ms_serno[4]; -/* 2b*/ unsigned char ms_label[11]; -/* 36*/ unsigned char ms_magic[8]; -/* 3e*/ unsigned char ms_dummy2[0x1fe - 0x3e]; -/*1fe*/ unsigned char ms_pmagic[2]; -} __attribute__((packed)); +/* {msdos,vfat}_super_block is defined in ../fat.h */ +#include "fat.h" struct vfat_dir_entry { uint8_t name[11]; @@ -193,7 +139,7 @@ static int probe_fat_nomagic(blkid_probe pr, const struct blkid_idmag *mag) return 1; /* media check */ - if (ms->ms_media < 0xf8 && ms->ms_media != 0xf0) + if (!blkid_fat_valid_media(ms)) return 1; /* fat counts(Linux kernel expects at least 1 FAT table) */ @@ -230,8 +176,6 @@ static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag) uint32_t buf_size, start_data_sect, next, root_start, root_dir_entries; const char *version = NULL; - - /* non-standard magic strings */ if (mag->len <= 2 && probe_fat_nomagic(pr, mag) != 0) return 1; @@ -245,10 +189,7 @@ static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag) return -1; /* sector size check */ - tmp = (unsigned char *) &ms->ms_sector_size; - sector_size = tmp[0] + (tmp[1] << 8); - if (sector_size != 0x200 && sector_size != 0x400 && - sector_size != 0x800 && sector_size != 0x1000) + if (!blkid_fat_valid_sectorsize(ms, §or_size)) return 1; tmp = (unsigned char *) &ms->ms_dir_entries;