diff options
author | Christian Taedcke <christian.taedcke@weidmueller.com> | 2023-11-15 13:44:20 +0100 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2023-11-28 20:10:25 -0500 |
commit | c489937a6f08af019f5478455ddb4e0b8ecaf6ce (patch) | |
tree | 7fab58ac6367834cecbe7972fba9426f73ac31be /fs/fat | |
parent | 33daef49b072f4aa7564fbbb80e7cab3629beecd (diff) | |
download | u-boot-c489937a6f08af019f5478455ddb4e0b8ecaf6ce.tar.gz u-boot-c489937a6f08af019f5478455ddb4e0b8ecaf6ce.tar.bz2 u-boot-c489937a6f08af019f5478455ddb4e0b8ecaf6ce.zip |
fs: fat: add bootsector validity check
The performed checks are similar to the checks performed by the Linux
kernel in the function fat_read_bpb() in the file fs/fat/inode.c.
Signed-off-by: Christian Taedcke <christian.taedcke@weidmueller.com>
Diffstat (limited to 'fs/fat')
-rw-r--r-- | fs/fat/fat.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 77f225ccd8..14e53cf2d5 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -25,6 +25,7 @@ #include <asm/cache.h> #include <linux/compiler.h> #include <linux/ctype.h> +#include <linux/log2.h> /* maximum number of clusters for FAT12 */ #define MAX_FAT12 0xFF4 @@ -509,6 +510,52 @@ static int determine_legacy_fat_bits(const boot_sector *bs) } /* + * Determines if the boot sector's media field is valid + * + * Based on fat_valid_media() from Linux kernel's include/linux/msdos_fs.h + */ +static int fat_valid_media(u8 media) +{ + return media >= 0xf8 || media == 0xf0; +} + +/* + * Determines if the given boot sector is valid + * + * Based on fat_read_bpb() from the Linux kernel's fs/fat/inode.c + */ +static int is_bootsector_valid(const boot_sector *bs) +{ + u16 sector_size = get_unaligned_le16(bs->sector_size); + u16 dir_per_block = sector_size / sizeof(dir_entry); + + if (!bs->reserved) + return 0; + + if (!bs->fats) + return 0; + + if (!fat_valid_media(bs->media)) + return 0; + + if (!is_power_of_2(sector_size) || + sector_size < 512 || + sector_size > 4096) + return 0; + + if (!is_power_of_2(bs->cluster_size)) + return 0; + + if (!bs->fat_length && !bs->fat32_length) + return 0; + + if (get_unaligned_le16(bs->dir_entries) & (dir_per_block - 1)) + return 0; + + return 1; +} + +/* * Read boot sector and volume info from a FAT filesystem */ static int @@ -542,6 +589,12 @@ read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) bs->heads = FAT2CPU16(bs->heads); bs->total_sect = FAT2CPU32(bs->total_sect); + if (!is_bootsector_valid(bs)) { + debug("Error: bootsector is invalid\n"); + ret = -1; + goto out_free; + } + /* FAT32 entries */ if (!bs->fat_length && bs->fat32_length) { /* Assume FAT32 */ |