aboutsummaryrefslogtreecommitdiffstats
path: root/fs/minix
diff options
context:
space:
mode:
authorJosh Boyer <jwboyer@redhat.com>2011-08-19 14:50:26 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2011-11-19 11:13:26 -0500
commit016e8d44bc06dd3322f26712bdd3f3a6973592d0 (patch)
tree3e237994b81e284ad58acc75f37b4c8d4aefbdf3 /fs/minix
parentd633180c20271d3b7c1fabbccbc7c5b30ad12be4 (diff)
fs/minix: Verify bitmap block counts before mounting
Newer versions of MINIX can create filesystems that allocate an extra bitmap block. Mounting of this succeeds, but doing a statfs call will result in an oops in count_free because of a negative number being used for the bh index. Avoid this by verifying the number of allocated blocks at mount time, erroring out if there are not enough and make statfs ignore the extras if there are too many. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=18792 Signed-off-by: Josh Boyer <jwboyer@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/minix')
-rw-r--r--fs/minix/bitmap.c18
-rw-r--r--fs/minix/inode.c25
-rw-r--r--fs/minix/minix.h9
3 files changed, 42 insertions, 10 deletions
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index 3f32bcb0d9b..7c82c29429d 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -20,10 +20,11 @@ static const int nibblemap[] = { 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 };
20 20
21static DEFINE_SPINLOCK(bitmap_lock); 21static DEFINE_SPINLOCK(bitmap_lock);
22 22
23static unsigned long count_free(struct buffer_head *map[], unsigned numblocks, __u32 numbits) 23static unsigned long count_free(struct buffer_head *map[], unsigned blocksize, __u32 numbits)
24{ 24{
25 unsigned i, j, sum = 0; 25 unsigned i, j, sum = 0;
26 struct buffer_head *bh; 26 struct buffer_head *bh;
27 unsigned numblocks = minix_blocks_needed(numbits, blocksize);
27 28
28 for (i=0; i<numblocks-1; i++) { 29 for (i=0; i<numblocks-1; i++) {
29 if (!(bh=map[i])) 30 if (!(bh=map[i]))
@@ -105,10 +106,12 @@ int minix_new_block(struct inode * inode)
105 return 0; 106 return 0;
106} 107}
107 108
108unsigned long minix_count_free_blocks(struct minix_sb_info *sbi) 109unsigned long minix_count_free_blocks(struct super_block *sb)
109{ 110{
110 return (count_free(sbi->s_zmap, sbi->s_zmap_blocks, 111 struct minix_sb_info *sbi = minix_sb(sb);
111 sbi->s_nzones - sbi->s_firstdatazone + 1) 112 u32 bits = sbi->s_nzones - (sbi->s_firstdatazone + 1);
113
114 return (count_free(sbi->s_zmap, sb->s_blocksize, bits)
112 << sbi->s_log_zone_size); 115 << sbi->s_log_zone_size);
113} 116}
114 117
@@ -273,7 +276,10 @@ struct inode *minix_new_inode(const struct inode *dir, int mode, int *error)
273 return inode; 276 return inode;
274} 277}
275 278
276unsigned long minix_count_free_inodes(struct minix_sb_info *sbi) 279unsigned long minix_count_free_inodes(struct super_block *sb)
277{ 280{
278 return count_free(sbi->s_imap, sbi->s_imap_blocks, sbi->s_ninodes + 1); 281 struct minix_sb_info *sbi = minix_sb(sb);
282 u32 bits = sbi->s_ninodes + 1;
283
284 return count_free(sbi->s_imap, sb->s_blocksize, bits);
279} 285}
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 64cdcd662ff..1d9e33966db 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -279,6 +279,27 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
279 else if (sbi->s_mount_state & MINIX_ERROR_FS) 279 else if (sbi->s_mount_state & MINIX_ERROR_FS)
280 printk("MINIX-fs: mounting file system with errors, " 280 printk("MINIX-fs: mounting file system with errors, "
281 "running fsck is recommended\n"); 281 "running fsck is recommended\n");
282
283 /* Apparently minix can create filesystems that allocate more blocks for
284 * the bitmaps than needed. We simply ignore that, but verify it didn't
285 * create one with not enough blocks and bail out if so.
286 */
287 block = minix_blocks_needed(sbi->s_ninodes, s->s_blocksize);
288 if (sbi->s_imap_blocks < block) {
289 printk("MINIX-fs: file system does not have enough "
290 "imap blocks allocated. Refusing to mount\n");
291 goto out_iput;
292 }
293
294 block = minix_blocks_needed(
295 (sbi->s_nzones - (sbi->s_firstdatazone + 1)),
296 s->s_blocksize);
297 if (sbi->s_zmap_blocks < block) {
298 printk("MINIX-fs: file system does not have enough "
299 "zmap blocks allocated. Refusing to mount.\n");
300 goto out_iput;
301 }
302
282 return 0; 303 return 0;
283 304
284out_iput: 305out_iput:
@@ -339,10 +360,10 @@ static int minix_statfs(struct dentry *dentry, struct kstatfs *buf)
339 buf->f_type = sb->s_magic; 360 buf->f_type = sb->s_magic;
340 buf->f_bsize = sb->s_blocksize; 361 buf->f_bsize = sb->s_blocksize;
341 buf->f_blocks = (sbi->s_nzones - sbi->s_firstdatazone) << sbi->s_log_zone_size; 362 buf->f_blocks = (sbi->s_nzones - sbi->s_firstdatazone) << sbi->s_log_zone_size;
342 buf->f_bfree = minix_count_free_blocks(sbi); 363 buf->f_bfree = minix_count_free_blocks(sb);
343 buf->f_bavail = buf->f_bfree; 364 buf->f_bavail = buf->f_bfree;
344 buf->f_files = sbi->s_ninodes; 365 buf->f_files = sbi->s_ninodes;
345 buf->f_ffree = minix_count_free_inodes(sbi); 366 buf->f_ffree = minix_count_free_inodes(sb);
346 buf->f_namelen = sbi->s_namelen; 367 buf->f_namelen = sbi->s_namelen;
347 buf->f_fsid.val[0] = (u32)id; 368 buf->f_fsid.val[0] = (u32)id;
348 buf->f_fsid.val[1] = (u32)(id >> 32); 369 buf->f_fsid.val[1] = (u32)(id >> 32);
diff --git a/fs/minix/minix.h b/fs/minix/minix.h
index 341e2122879..6415fe0d238 100644
--- a/fs/minix/minix.h
+++ b/fs/minix/minix.h
@@ -48,10 +48,10 @@ extern struct minix_inode * minix_V1_raw_inode(struct super_block *, ino_t, stru
48extern struct minix2_inode * minix_V2_raw_inode(struct super_block *, ino_t, struct buffer_head **); 48extern struct minix2_inode * minix_V2_raw_inode(struct super_block *, ino_t, struct buffer_head **);
49extern struct inode * minix_new_inode(const struct inode *, int, int *); 49extern struct inode * minix_new_inode(const struct inode *, int, int *);
50extern void minix_free_inode(struct inode * inode); 50extern void minix_free_inode(struct inode * inode);
51extern unsigned long minix_count_free_inodes(struct minix_sb_info *sbi); 51extern unsigned long minix_count_free_inodes(struct super_block *sb);
52extern int minix_new_block(struct inode * inode); 52extern int minix_new_block(struct inode * inode);
53extern void minix_free_block(struct inode *inode, unsigned long block); 53extern void minix_free_block(struct inode *inode, unsigned long block);
54extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi); 54extern unsigned long minix_count_free_blocks(struct super_block *sb);
55extern int minix_getattr(struct vfsmount *, struct dentry *, struct kstat *); 55extern int minix_getattr(struct vfsmount *, struct dentry *, struct kstat *);
56extern int minix_prepare_chunk(struct page *page, loff_t pos, unsigned len); 56extern int minix_prepare_chunk(struct page *page, loff_t pos, unsigned len);
57 57
@@ -88,6 +88,11 @@ static inline struct minix_inode_info *minix_i(struct inode *inode)
88 return list_entry(inode, struct minix_inode_info, vfs_inode); 88 return list_entry(inode, struct minix_inode_info, vfs_inode);
89} 89}
90 90
91static inline unsigned minix_blocks_needed(unsigned bits, unsigned blocksize)
92{
93 return DIV_ROUND_UP(bits, blocksize * 8);
94}
95
91#if defined(CONFIG_MINIX_FS_NATIVE_ENDIAN) && \ 96#if defined(CONFIG_MINIX_FS_NATIVE_ENDIAN) && \
92 defined(CONFIG_MINIX_FS_BIG_ENDIAN_16BIT_INDEXED) 97 defined(CONFIG_MINIX_FS_BIG_ENDIAN_16BIT_INDEXED)
93 98