Message ID | d482652ab340257c111ec50e8d4ec28c71333585.1668121036.git.yuxuan.luo@canonical.com |
---|---|
State | New |
Headers | show |
Series | [SRU,F,1/2] nilfs2: use a more common logging style | expand |
On 11.11.22 19:56, Yuxuan Luo wrote: > From: Ryusuke Konishi <konishi.ryusuke@gmail.com> > > If the beginning of the inode bitmap area is corrupted on disk, an inode > with the same inode number as the root inode can be allocated and fail > soon after. In this case, the subsequent call to nilfs_clear_inode() on > that bogus root inode will wrongly decrement the reference counter of > struct nilfs_root, and this will erroneously free struct nilfs_root, > causing kernel oopses. > > This fixes the problem by changing nilfs_new_inode() to skip reserved > inode numbers while repairing the inode bitmap. > > Link: https://lkml.kernel.org/r/20221003150519.39789-1-konishi.ryusuke@gmail.com > Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com> > Reported-by: syzbot+b8c672b0e22615c80fe0@syzkaller.appspotmail.com > Reported-by: Khalid Masum <khalid.masum.92@gmail.com> > Tested-by: Ryusuke Konishi <konishi.ryusuke@gmail.com> > Cc: <stable@vger.kernel.org> > Signed-off-by: Andrew Morton <akpm@linux-foundation.org> > (cherry picked from commit d325dc6eb763c10f591c239550b8c7e5466a5d09) > CVE-2022-3649 > Signed-off-by: Yuxuan Luo <yuxuan.luo@canonical.com> > --- This should be a thread with a cover email which indicates all target series. -Stefan > fs/nilfs2/inode.c | 17 ++++++++++++++++- > 1 file changed, 16 insertions(+), 1 deletion(-) > > diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c > index bfc7ae219a8d..cd959f4378bc 100644 > --- a/fs/nilfs2/inode.c > +++ b/fs/nilfs2/inode.c > @@ -340,6 +340,7 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) > struct inode *inode; > struct nilfs_inode_info *ii; > struct nilfs_root *root; > + struct buffer_head *bh; > int err = -ENOMEM; > ino_t ino; > > @@ -355,11 +356,25 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) > ii->i_state = BIT(NILFS_I_NEW); > ii->i_root = root; > > - err = nilfs_ifile_create_inode(root->ifile, &ino, &ii->i_bh); > + err = nilfs_ifile_create_inode(root->ifile, &ino, &bh); > if (unlikely(err)) > goto failed_ifile_create_inode; > /* reference count of i_bh inherits from nilfs_mdt_read_block() */ > > + if (unlikely(ino < NILFS_USER_INO)) { > + nilfs_warn(sb, > + "inode bitmap is inconsistent for reserved inodes"); > + do { > + brelse(bh); > + err = nilfs_ifile_create_inode(root->ifile, &ino, &bh); > + if (unlikely(err)) > + goto failed_ifile_create_inode; > + } while (ino < NILFS_USER_INO); > + > + nilfs_info(sb, "repaired inode bitmap for reserved inodes"); > + } > + ii->i_bh = bh; > + > atomic64_inc(&root->inodes_count); > inode_init_owner(inode, dir, mode); > inode->i_ino = ino;
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index bfc7ae219a8d..cd959f4378bc 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -340,6 +340,7 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) struct inode *inode; struct nilfs_inode_info *ii; struct nilfs_root *root; + struct buffer_head *bh; int err = -ENOMEM; ino_t ino; @@ -355,11 +356,25 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) ii->i_state = BIT(NILFS_I_NEW); ii->i_root = root; - err = nilfs_ifile_create_inode(root->ifile, &ino, &ii->i_bh); + err = nilfs_ifile_create_inode(root->ifile, &ino, &bh); if (unlikely(err)) goto failed_ifile_create_inode; /* reference count of i_bh inherits from nilfs_mdt_read_block() */ + if (unlikely(ino < NILFS_USER_INO)) { + nilfs_warn(sb, + "inode bitmap is inconsistent for reserved inodes"); + do { + brelse(bh); + err = nilfs_ifile_create_inode(root->ifile, &ino, &bh); + if (unlikely(err)) + goto failed_ifile_create_inode; + } while (ino < NILFS_USER_INO); + + nilfs_info(sb, "repaired inode bitmap for reserved inodes"); + } + ii->i_bh = bh; + atomic64_inc(&root->inodes_count); inode_init_owner(inode, dir, mode); inode->i_ino = ino;