Commit 0be35e24 authored by Hirofumi Ogawa's avatar Hirofumi Ogawa Committed by Linus Torvalds

[PATCH] Add validity check of first FAT entry (2/5)

This patch makes detection of a FAT filesystem more exact by checking
the first FAT entry. 
parent b2e4b218
...@@ -34,16 +34,12 @@ int fat_bmap(struct inode *inode,int sector) ...@@ -34,16 +34,12 @@ int fat_bmap(struct inode *inode,int sector)
return MSDOS_SB(inode->i_sb)->cvf_format->cvf_bmap(inode,sector); return MSDOS_SB(inode->i_sb)->cvf_format->cvf_bmap(inode,sector);
} }
int default_fat_access(struct super_block *sb,int nr,int new_value) int __fat_access(struct super_block *sb, int nr, int new_value)
{ {
struct buffer_head *bh, *bh2, *c_bh, *c_bh2; struct buffer_head *bh, *bh2, *c_bh, *c_bh2;
unsigned char *p_first, *p_last; unsigned char *p_first, *p_last;
int copy, first, last, next, b; int copy, first, last, next, b;
if (nr < 2 || MSDOS_SB(sb)->clusters + 2 <= nr) {
fat_fs_panic(sb, "invalid access to FAT (entry 0x%08x)", nr);
return -EIO;
}
if (MSDOS_SB(sb)->fat_bits == 32) { if (MSDOS_SB(sb)->fat_bits == 32) {
first = last = nr*4; first = last = nr*4;
} else if (MSDOS_SB(sb)->fat_bits == 16) { } else if (MSDOS_SB(sb)->fat_bits == 16) {
...@@ -73,25 +69,17 @@ int default_fat_access(struct super_block *sb,int nr,int new_value) ...@@ -73,25 +69,17 @@ int default_fat_access(struct super_block *sb,int nr,int new_value)
(sb->s_blocksize - 1)) >> 2]); (sb->s_blocksize - 1)) >> 2]);
/* Fscking Microsoft marketing department. Their "32" is 28. */ /* Fscking Microsoft marketing department. Their "32" is 28. */
next &= 0x0fffffff; next &= 0x0fffffff;
if (next >= BAD_FAT32) next = FAT_ENT_EOF;
PRINTK(("fat_bread: 0x%x, nr=0x%x, first=0x%x, next=0x%x\n", b, nr, first, next));
} else if (MSDOS_SB(sb)->fat_bits == 16) { } else if (MSDOS_SB(sb)->fat_bits == 16) {
p_first = p_last = NULL; /* GCC needs that stuff */ p_first = p_last = NULL; /* GCC needs that stuff */
next = CF_LE_W(((__u16 *) bh->b_data)[(first & next = CF_LE_W(((__u16 *) bh->b_data)[(first &
(sb->s_blocksize - 1)) >> 1]); (sb->s_blocksize - 1)) >> 1]);
if (next >= BAD_FAT16) next = FAT_ENT_EOF;
} else { } else {
p_first = &((__u8 *)bh->b_data)[first & (sb->s_blocksize - 1)]; p_first = &((__u8 *)bh->b_data)[first & (sb->s_blocksize - 1)];
p_last = &((__u8 *)bh2->b_data)[(first + 1) & (sb->s_blocksize - 1)]; p_last = &((__u8 *)bh2->b_data)[(first + 1) & (sb->s_blocksize - 1)];
if (nr & 1) next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff; if (nr & 1) next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff;
else next = (*p_first+(*p_last << 8)) & 0xfff; else next = (*p_first+(*p_last << 8)) & 0xfff;
if (next >= BAD_FAT12) next = FAT_ENT_EOF;
} }
if (new_value != -1) { if (new_value != -1) {
if (next == FAT_ENT_EOF)
next = EOF_FAT(sb);
if (MSDOS_SB(sb)->fat_bits == 32) { if (MSDOS_SB(sb)->fat_bits == 32) {
((__u32 *)bh->b_data)[(first & (sb->s_blocksize - 1)) >> 2] ((__u32 *)bh->b_data)[(first & (sb->s_blocksize - 1)) >> 2]
= CT_LE_L(new_value); = CT_LE_L(new_value);
...@@ -135,6 +123,27 @@ int default_fat_access(struct super_block *sb,int nr,int new_value) ...@@ -135,6 +123,27 @@ int default_fat_access(struct super_block *sb,int nr,int new_value)
return next; return next;
} }
int default_fat_access(struct super_block *sb, int nr, int new_value)
{
int next;
next = -EIO;
if (nr < 2 || MSDOS_SB(sb)->clusters + 2 <= nr) {
fat_fs_panic(sb, "invalid access to FAT (entry 0x%08x)", nr);
goto out;
}
if (new_value == FAT_ENT_EOF)
new_value = EOF_FAT(sb);
next = __fat_access(sb, nr, new_value);
if (next < 0)
goto out;
if (next >= BAD_FAT(sb))
next = FAT_ENT_EOF;
out:
return next;
}
void fat_cache_init(void) void fat_cache_init(void)
{ {
static int initialized = 0; static int initialized = 0;
......
...@@ -591,8 +591,9 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, ...@@ -591,8 +591,9 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
struct buffer_head *bh; struct buffer_head *bh;
struct fat_boot_sector *b; struct fat_boot_sector *b;
struct msdos_sb_info *sbi; struct msdos_sb_info *sbi;
int logical_sector_size, fat_clusters, debug, cp; int logical_sector_size, fat_clusters, debug, cp, first;
unsigned int total_sectors, rootdir_sectors; unsigned int total_sectors, rootdir_sectors;
unsigned char media;
long error = -EIO; long error = -EIO;
char buf[50]; char buf[50];
int i; int i;
...@@ -655,6 +656,13 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, ...@@ -655,6 +656,13 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
brelse(bh); brelse(bh);
goto out_invalid; goto out_invalid;
} }
media = b->media;
if (!FAT_VALID_MEDIA(media)) {
if (!silent)
printk("FAT: invalid media value (0x%02x)\n", media);
brelse(bh);
goto out_invalid;
}
logical_sector_size = logical_sector_size =
CF_LE_W(get_unaligned((unsigned short *) &b->sector_size)); CF_LE_W(get_unaligned((unsigned short *) &b->sector_size));
if (!logical_sector_size if (!logical_sector_size
...@@ -777,6 +785,21 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, ...@@ -777,6 +785,21 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
brelse(bh); brelse(bh);
/* validity check of FAT */
first = __fat_access(sb, 0, -1);
if (first < 0) {
error = first;
goto out_fail;
}
if (FAT_FIRST_ENT(sb, media) != first) {
if (!silent) {
printk("FAT: invalid first entry of FAT "
"(0x%x != 0x%x)\n",
FAT_FIRST_ENT(sb, media), first);
}
goto out_invalid;
}
if (!strcmp(cvf_format, "none")) if (!strcmp(cvf_format, "none"))
i = -1; i = -1;
else else
......
...@@ -54,6 +54,11 @@ ...@@ -54,6 +54,11 @@
#define MSDOS_FAT12 4084 /* maximum number of clusters in a 12 bit FAT */ #define MSDOS_FAT12 4084 /* maximum number of clusters in a 12 bit FAT */
/* media of boot sector */
#define FAT_VALID_MEDIA(x) ((0xF8 <= (x) && (x) <= 0xFF) || (x) == 0xF0)
#define FAT_FIRST_ENT(s, x) ((MSDOS_SB(s)->fat_bits == 32 ? 0x0FFFFF00 : \
MSDOS_SB(s)->fat_bits == 16 ? 0xFF00 : 0xF00) | (x))
/* bad cluster mark */ /* bad cluster mark */
#define BAD_FAT12 0xFF7 #define BAD_FAT12 0xFF7
#define BAD_FAT16 0xFFF7 #define BAD_FAT16 0xFFF7
...@@ -114,7 +119,7 @@ struct fat_boot_sector { ...@@ -114,7 +119,7 @@ struct fat_boot_sector {
__u8 fats; /* number of FATs */ __u8 fats; /* number of FATs */
__u8 dir_entries[2]; /* root directory entries */ __u8 dir_entries[2]; /* root directory entries */
__u8 sectors[2]; /* number of sectors */ __u8 sectors[2]; /* number of sectors */
__u8 media; /* media code (unused) */ __u8 media; /* media code */
__u16 fat_length; /* sectors/FAT */ __u16 fat_length; /* sectors/FAT */
__u16 secs_track; /* sectors per track */ __u16 secs_track; /* sectors per track */
__u16 heads; /* number of heads */ __u16 heads; /* number of heads */
...@@ -242,6 +247,7 @@ extern void fat_ll_rw_block(struct super_block *sb, int opr, int nbreq, ...@@ -242,6 +247,7 @@ extern void fat_ll_rw_block(struct super_block *sb, int opr, int nbreq,
/* fat/cache.c */ /* fat/cache.c */
extern int fat_access(struct super_block *sb, int nr, int new_value); extern int fat_access(struct super_block *sb, int nr, int new_value);
extern int __fat_access(struct super_block *sb, int nr, int new_value);
extern int fat_bmap(struct inode *inode, int sector); extern int fat_bmap(struct inode *inode, int sector);
extern void fat_cache_init(void); extern void fat_cache_init(void);
extern void fat_cache_lookup(struct inode *inode, int cluster, int *f_clu, extern void fat_cache_lookup(struct inode *inode, int cluster, int *f_clu,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment