From 70d9e384aa7df681cfffd65947af72b22e86690e Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Tue, 6 Jul 2010 00:50:58 -0400 Subject: omfs: fix memory leak In the error path of omfs_fill_super(), the FS super block info (sbi) is not being freed. Correct this. Signed-off-by: Davidlohr Bueso Signed-off-by: Bob Copeland diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index 089839a..b5d6380 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c @@ -529,6 +529,8 @@ out_brelse_bh2: out_brelse_bh: brelse(bh); end: + if (ret) + kfree(sbi); return ret; } -- cgit v0.10.2 From f068272cb2f134a194b93e94a8e0672bfce48cd8 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sat, 6 Sep 2008 17:51:53 -0400 Subject: omfs: check bounds on block numbers before passing to sb_bread In case of filesystem corruption, passing unchecked block numbers into sb_bread can result in an infinite loop in __getblk(). Introduce a wrapper function omfs_sbread() to check the block numbers and to also perform the clus_to_blk() scaling. Signed-off-by: Bob Copeland diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c index b42d624..393f3f6 100644 --- a/fs/omfs/dir.c +++ b/fs/omfs/dir.c @@ -25,11 +25,10 @@ static struct buffer_head *omfs_get_bucket(struct inode *dir, const char *name, int namelen, int *ofs) { int nbuckets = (dir->i_size - OMFS_DIR_START)/8; - int block = clus_to_blk(OMFS_SB(dir->i_sb), dir->i_ino); int bucket = omfs_hash(name, namelen, nbuckets); *ofs = OMFS_DIR_START + bucket * 8; - return sb_bread(dir->i_sb, block); + return omfs_bread(dir->i_sb, dir->i_ino); } static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block, @@ -42,8 +41,7 @@ static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block, *prev_block = ~0; while (block != ~0) { - bh = sb_bread(dir->i_sb, - clus_to_blk(OMFS_SB(dir->i_sb), block)); + bh = omfs_bread(dir->i_sb, block); if (!bh) { err = -EIO; goto err; @@ -86,11 +84,10 @@ static struct buffer_head *omfs_find_entry(struct inode *dir, int omfs_make_empty(struct inode *inode, struct super_block *sb) { struct omfs_sb_info *sbi = OMFS_SB(sb); - int block = clus_to_blk(sbi, inode->i_ino); struct buffer_head *bh; struct omfs_inode *oi; - bh = sb_bread(sb, block); + bh = omfs_bread(sb, inode->i_ino); if (!bh) return -ENOMEM; @@ -134,7 +131,7 @@ static int omfs_add_link(struct dentry *dentry, struct inode *inode) brelse(bh); /* now set the sibling and parent pointers on the new inode */ - bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), inode->i_ino)); + bh = omfs_bread(dir->i_sb, inode->i_ino); if (!bh) goto out; @@ -190,8 +187,7 @@ static int omfs_delete_entry(struct dentry *dentry) if (prev != ~0) { /* found in middle of list, get list ptr */ brelse(bh); - bh = sb_bread(dir->i_sb, - clus_to_blk(OMFS_SB(dir->i_sb), prev)); + bh = omfs_bread(dir->i_sb, prev); if (!bh) goto out; @@ -224,8 +220,7 @@ static int omfs_dir_is_empty(struct inode *inode) u64 *ptr; int i; - bh = sb_bread(inode->i_sb, clus_to_blk(OMFS_SB(inode->i_sb), - inode->i_ino)); + bh = omfs_bread(inode->i_sb, inode->i_ino); if (!bh) return 0; @@ -353,8 +348,7 @@ static int omfs_fill_chain(struct file *filp, void *dirent, filldir_t filldir, /* follow chain in this bucket */ while (fsblock != ~0) { - bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), - fsblock)); + bh = omfs_bread(dir->i_sb, fsblock); if (!bh) goto out; @@ -466,7 +460,7 @@ static int omfs_readdir(struct file *filp, void *dirent, filldir_t filldir) hchain = (filp->f_pos >> 20) - 1; hindex = filp->f_pos & 0xfffff; - bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), dir->i_ino)); + bh = omfs_bread(dir->i_sb, dir->i_ino); if (!bh) goto out; diff --git a/fs/omfs/file.c b/fs/omfs/file.c index 6e7a329..76bc21b 100644 --- a/fs/omfs/file.c +++ b/fs/omfs/file.c @@ -50,7 +50,7 @@ int omfs_shrink_inode(struct inode *inode) if (inode->i_size != 0) goto out; - bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next)); + bh = omfs_bread(inode->i_sb, next); if (!bh) goto out; @@ -90,7 +90,7 @@ int omfs_shrink_inode(struct inode *inode) if (next == ~0) break; - bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next)); + bh = omfs_bread(inode->i_sb, next); if (!bh) goto out; oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]); @@ -232,7 +232,7 @@ static int omfs_get_block(struct inode *inode, sector_t block, int remain; ret = -EIO; - bh = sb_bread(inode->i_sb, clus_to_blk(sbi, inode->i_ino)); + bh = omfs_bread(inode->i_sb, inode->i_ino); if (!bh) goto out; @@ -265,7 +265,7 @@ static int omfs_get_block(struct inode *inode, sector_t block, break; brelse(bh); - bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next)); + bh = omfs_bread(inode->i_sb, next); if (!bh) goto out; oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]); diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index b5d6380..bd4bf75 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c @@ -19,6 +19,15 @@ MODULE_AUTHOR("Bob Copeland "); MODULE_DESCRIPTION("OMFS (ReplayTV/Karma) Filesystem for Linux"); MODULE_LICENSE("GPL"); +struct buffer_head *omfs_bread(struct super_block *sb, sector_t block) +{ + struct omfs_sb_info *sbi = OMFS_SB(sb); + if (block >= sbi->s_num_blocks) + return NULL; + + return sb_bread(sb, clus_to_blk(sbi, block)); +} + struct inode *omfs_new_inode(struct inode *dir, int mode) { struct inode *inode; @@ -93,15 +102,13 @@ static int __omfs_write_inode(struct inode *inode, int wait) struct omfs_inode *oi; struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb); struct buffer_head *bh, *bh2; - unsigned int block; u64 ctime; int i; int ret = -EIO; int sync_failed = 0; /* get current inode since we may have written sibling ptrs etc. */ - block = clus_to_blk(sbi, inode->i_ino); - bh = sb_bread(inode->i_sb, block); + bh = omfs_bread(inode->i_sb, inode->i_ino); if (!bh) goto out; @@ -140,8 +147,7 @@ static int __omfs_write_inode(struct inode *inode, int wait) /* if mirroring writes, copy to next fsblock */ for (i = 1; i < sbi->s_mirrors; i++) { - bh2 = sb_bread(inode->i_sb, block + i * - (sbi->s_blocksize / sbi->s_sys_blocksize)); + bh2 = omfs_bread(inode->i_sb, inode->i_ino + i); if (!bh2) goto out_brelse; @@ -193,7 +199,6 @@ struct inode *omfs_iget(struct super_block *sb, ino_t ino) struct omfs_sb_info *sbi = OMFS_SB(sb); struct omfs_inode *oi; struct buffer_head *bh; - unsigned int block; u64 ctime; unsigned long nsecs; struct inode *inode; @@ -204,8 +209,7 @@ struct inode *omfs_iget(struct super_block *sb, ino_t ino) if (!(inode->i_state & I_NEW)) return inode; - block = clus_to_blk(sbi, ino); - bh = sb_bread(inode->i_sb, block); + bh = omfs_bread(inode->i_sb, ino); if (!bh) goto iget_failed; @@ -319,6 +323,9 @@ static int omfs_get_imap(struct super_block *sb) goto nomem; block = clus_to_blk(sbi, sbi->s_bitmap_ino); + if (block >= sbi->s_num_blocks) + goto nomem; + ptr = sbi->s_imap; for (count = bitmap_size; count > 0; count -= sb->s_blocksize) { bh = sb_bread(sb, block++); @@ -417,7 +424,6 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) struct omfs_root_block *omfs_rb; struct omfs_sb_info *sbi; struct inode *root; - sector_t start; int ret = -EINVAL; save_mount_options(sb, (char *) data); @@ -486,8 +492,7 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) sbi->s_block_shift = get_bitmask_order(sbi->s_blocksize) - get_bitmask_order(sbi->s_sys_blocksize); - start = clus_to_blk(sbi, be64_to_cpu(omfs_sb->s_root_block)); - bh2 = sb_bread(sb, start); + bh2 = omfs_bread(sb, be64_to_cpu(omfs_sb->s_root_block)); if (!bh2) goto out_brelse_bh; diff --git a/fs/omfs/omfs.h b/fs/omfs/omfs.h index ebe2fdb..7d414fe 100644 --- a/fs/omfs/omfs.h +++ b/fs/omfs/omfs.h @@ -58,6 +58,7 @@ extern void omfs_make_empty_table(struct buffer_head *bh, int offset); extern int omfs_shrink_inode(struct inode *inode); /* inode.c */ +extern struct buffer_head *omfs_bread(struct super_block *sb, sector_t block); extern struct inode *omfs_iget(struct super_block *sb, ino_t inode); extern struct inode *omfs_new_inode(struct inode *dir, int mode); extern int omfs_reserve_block(struct super_block *sb, sector_t block); -- cgit v0.10.2 From 9442e54f433eff9b6fbd0836611df4c1919df370 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Thu, 14 Aug 2008 18:43:59 -0400 Subject: omfs: refuse to mount if bitmap pointer is obviously wrong If the free space bitmap pointer is corrupted such that it lies outside of the number of blocks in the filesystem, print a message and fail the mount so the user can fix it offline. Signed-off-by: Bob Copeland diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index bd4bf75..0af5d0a 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c @@ -509,6 +509,15 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) goto out_brelse_bh2; } + if (sbi->s_bitmap_ino != ~0ULL && + sbi->s_bitmap_ino > sbi->s_num_blocks) { + printk(KERN_ERR "omfs: free space bitmap location is corrupt " + "(%llx, total blocks %llx)\n", + (unsigned long long) sbi->s_bitmap_ino, + (unsigned long long) sbi->s_num_blocks); + goto out_brelse_bh2; + } + ret = omfs_get_imap(sb); if (ret) goto out_brelse_bh2; -- cgit v0.10.2 From 8800a044c71a128633cf3febaf4780531a991334 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 6 Jul 2010 11:16:46 -0400 Subject: omfs: sanity check cluster size A corrupt filesystem could have a bad cluster size; this could result in the filesystem allocating too much space for files if too large, or getting stuck in omfs_allocate_block if too small. The proper range is 1-8 blocks. Reported-by: Eric Sesterhenn Signed-off-by: Bob Copeland diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index 0af5d0a..579d33f 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c @@ -517,6 +517,12 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) (unsigned long long) sbi->s_num_blocks); goto out_brelse_bh2; } + if (sbi->s_clustersize < 1 || + sbi->s_clustersize > OMFS_MAX_CLUSTER_SIZE) { + printk(KERN_ERR "omfs: cluster size out of range (%d)", + sbi->s_clustersize); + goto out_brelse_bh2; + } ret = omfs_get_imap(sb); if (ret) diff --git a/fs/omfs/omfs_fs.h b/fs/omfs/omfs_fs.h index 12cca24..ee5e432 100644 --- a/fs/omfs/omfs_fs.h +++ b/fs/omfs/omfs_fs.h @@ -17,6 +17,7 @@ #define OMFS_EXTENT_CONT 0x40 #define OMFS_XOR_COUNT 19 #define OMFS_MAX_BLOCK_SIZE 8192 +#define OMFS_MAX_CLUSTER_SIZE 8 struct omfs_super_block { char s_fill1[256]; -- cgit v0.10.2 From ffc18879903e55487bc5ac3c774b99a07de06029 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Tue, 3 Aug 2010 15:19:30 -0400 Subject: omfs: fix uninitialized variable warning quiet the warning: fs/omfs/file.c: In function 'omfs_get_block': fs/omfs/file.c:225: warning: 'new_block' may be used uninitialized in this function new_block is used properly by the call to omfs_grow_extent() Signed-off-by: Bill Pemberton Signed-off-by: Bob Copeland diff --git a/fs/omfs/file.c b/fs/omfs/file.c index 76bc21b..d821d46 100644 --- a/fs/omfs/file.c +++ b/fs/omfs/file.c @@ -222,7 +222,7 @@ static int omfs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh; sector_t next, offset; int ret; - u64 new_block; + u64 uninitialized_var(new_block); u32 max_extents; int extent_count; struct omfs_extent *oe; -- cgit v0.10.2