vxfs fix
From: Linus Torvalds <[email protected]>
On Wed, 1 Aug 2001 [email protected] wrote:
>
> When mount continues to try all types, it may try V7. > That always succeeds, there is no test for magic or so, > and after garbage has been mounted as a V7 filesystem, > the kernel crashes or hangs or fails in other sad ways.
Even on filesystems that have bad (limited or non-existent)
magic numbers, the read_super() function should really be able
to do a fair amount of sanity-checking. If nothing else, then things like verifying that the root inode really is a directory with a proper size, for example.
Added.
From: Christoph Hellwig
I'd like to propose:
s_nfree <= V7_NICFREE, s_ninode <= V7_NICINOD, s_time != 0
Added.
From: Al Viro
It shouldn't crash the box, though - I'll look into that.
Good!
From: Alan
Alternatively pass a flag to the mount command saying "this is a guesswork special" then V7 fs can just return 'not me'
Parse failure.
Below a patch.
Andries
fs/sysv/super.c renamed from linux-2.4.7/linux/fs/sysv/super.c +32 -12
@@ -197,6 +197,8 @@ sb->sv_bytesex =BYTESEX_BE ; else return 0; + +/* BUG? no endian conversion on s_time? */ if (sbd->s_time <JAN_1_1980 ) {/* this is likely to happen on SystemV2 FS */ if (sbd->s_type >3 || sbd->s_type <1 )
@@ -294,7 +296,8 @@ sb->sv_toobig_block =10 + bsize_4 * (1 + bsize_4 * (1 + bsize_4)); sb->sv_ind_per_block_bits = n_bits-2 ; - sb->sv_ninodes = (sb->sv_firstdatazone - sb->sv_firstinodezone) << sb->sv_inodes_per_block_bits; + sb->sv_ninodes = (sb->sv_firstdatazone - sb->sv_firstinodezone) + << sb->sv_inodes_per_block_bits; sb->s_blocksize = bsize; sb->s_blocksize_bits = n_bits;
@@ -346,13 +349,10 @@ sb->sv_block_base =0 ;for (i =0 ; i <sizeof (flavours)/sizeof (flavours[0 ]) && !size; i++) { -struct buffer_head *next_bh; - next_bh =bread (dev, flavours[i].block,BLOCK_SIZE ); -if (!next_bh) -continue ;brelse (bh); - bh = next_bh; - + bh =bread (dev, flavours[i].block,BLOCK_SIZE ); +if (!bh) +continue ; size = flavours[i].test (sb, bh); }
@@ -411,8 +411,10 @@static struct super_block *v7_read_super (struct super_block *sb,void *data,int silent) { -struct buffer_head *bh; +struct buffer_head *bh, *bh2 =NULL ;kdev_t dev = sb->s_dev; +struct v7_super_block *v7sb; +struct sysv_inode *v7i;if (440 !=sizeof (struct v7_super_block ))panic ("V7 FS: bad super-block size" );
@@ -422,23 +424,41 @@ sb->sv_type =FSTYPE_V7 ; sb->sv_bytesex =BYTESEX_PDP ; -set_blocksize (dev,512 ); +set_blocksize (dev,512 );if ((bh =bread (dev,1 ,512 )) ==NULL ) {if (!silent) -printk ("VFS: unable to read V7 FS superblock on device " -"%s.\n" ,bdevname (dev)); +printk ("VFS: unable to read V7 FS superblock on " +"device %s.\n" ,bdevname (dev)); goto failed; } +/* plausibility check on superblock */ + v7sb = (struct v7_super_block *) bh->b_data; +if (fs16_to_cpu (sb,v7sb->s_nfree) >V7_NICFREE || +fs16_to_cpu (sb,v7sb->s_ninode) >V7_NICINOD || +fs32_to_cpu (sb,v7sb->s_time) ==0 ) + goto failed; + +/* plausibility check on root inode: it is a directory, +with a nonzero size that is a multiple of 16 */ +if ((bh2 =bread (dev,2 ,512 )) ==NULL ) + goto failed; + v7i = (struct sysv_inode *)(bh2->b_data +64 ); +if ((fs16_to_cpu (sb,v7i->i_mode) & ~0777 ) !=S_IFDIR || + (fs32_to_cpu (sb,v7i->i_size) ==0 ) || + (fs32_to_cpu (sb,v7i->i_size) &017 ) !=0 ) + goto failed; +brelse (bh2); sb->sv_bh1 = bh; sb->sv_bh2 = bh;if (complete_read_super (sb, silent,1 ))return sb; -brelse (bh); failed: +brelse (bh2); +brelse (bh);return NULL ; }