Commit 6becdb60 authored by Miklos Szeredi's avatar Miklos Szeredi

fuse: fix control dir setup and teardown

syzbot is reporting NULL pointer dereference at fuse_ctl_remove_conn() [1].
Since fc->ctl_ndents is incremented by fuse_ctl_add_conn() when new_inode()
failed, fuse_ctl_remove_conn() reaches an inode-less dentry and tries to
clear d_inode(dentry)->i_private field.

Fix by only adding the dentry to the array after being fully set up.

When tearing down the control directory, do d_invalidate() on it to get rid
of any mounts that might have been added.

[1] https://syzkaller.appspot.com/bug?id=f396d863067238959c91c0b7cfc10b163638cac6Reported-by: default avatarsyzbot <syzbot+32c236387d66c4516827@syzkaller.appspotmail.com>
Fixes: bafa9654 ("[PATCH] fuse: add control filesystem")
Cc: <stable@vger.kernel.org> # v2.6.18
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent 8a301eb1
...@@ -211,10 +211,11 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent, ...@@ -211,10 +211,11 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent,
if (!dentry) if (!dentry)
return NULL; return NULL;
fc->ctl_dentry[fc->ctl_ndents++] = dentry;
inode = new_inode(fuse_control_sb); inode = new_inode(fuse_control_sb);
if (!inode) if (!inode) {
dput(dentry);
return NULL; return NULL;
}
inode->i_ino = get_next_ino(); inode->i_ino = get_next_ino();
inode->i_mode = mode; inode->i_mode = mode;
...@@ -228,6 +229,9 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent, ...@@ -228,6 +229,9 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent,
set_nlink(inode, nlink); set_nlink(inode, nlink);
inode->i_private = fc; inode->i_private = fc;
d_add(dentry, inode); d_add(dentry, inode);
fc->ctl_dentry[fc->ctl_ndents++] = dentry;
return dentry; return dentry;
} }
...@@ -284,7 +288,10 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc) ...@@ -284,7 +288,10 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc)
for (i = fc->ctl_ndents - 1; i >= 0; i--) { for (i = fc->ctl_ndents - 1; i >= 0; i--) {
struct dentry *dentry = fc->ctl_dentry[i]; struct dentry *dentry = fc->ctl_dentry[i];
d_inode(dentry)->i_private = NULL; d_inode(dentry)->i_private = NULL;
d_drop(dentry); if (!i) {
/* Get rid of submounts: */
d_invalidate(dentry);
}
dput(dentry); dput(dentry);
} }
drop_nlink(d_inode(fuse_control_sb->s_root)); drop_nlink(d_inode(fuse_control_sb->s_root));
......
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