summaryrefslogtreecommitdiff
path: root/fs/fat
diff options
context:
space:
mode:
authorChristian Taedcke <christian.taedcke@weidmueller.com>2023-11-15 13:44:20 +0100
committerTom Rini <trini@konsulko.com>2023-11-28 20:10:25 -0500
commitc489937a6f08af019f5478455ddb4e0b8ecaf6ce (patch)
tree7fab58ac6367834cecbe7972fba9426f73ac31be /fs/fat
parent33daef49b072f4aa7564fbbb80e7cab3629beecd (diff)
downloadu-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.c53
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 */