Skip to content

Commit

Permalink
fuse: fix UAF in rcu pathwalks
Browse files Browse the repository at this point in the history
->permission(), ->get_link() and ->inode_get_acl() might dereference
->s_fs_info (and, in case of ->permission(), ->s_fs_info->fc->user_ns
as well) when called from rcu pathwalk.

Freeing ->s_fs_info->fc is rcu-delayed; we need to make freeing ->s_fs_info
and dropping ->user_ns rcu-delayed too.

Signed-off-by: Al Viro <[email protected]>
  • Loading branch information
Al Viro committed Feb 25, 2024
1 parent e31f0a5 commit 053fc4f
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 6 deletions.
3 changes: 1 addition & 2 deletions fs/fuse/cuse.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,8 +474,7 @@ static int cuse_send_init(struct cuse_conn *cc)

static void cuse_fc_release(struct fuse_conn *fc)
{
struct cuse_conn *cc = fc_to_cc(fc);
kfree_rcu(cc, fc.rcu);
kfree(fc_to_cc(fc));
}

/**
Expand Down
1 change: 1 addition & 0 deletions fs/fuse/fuse_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,7 @@ struct fuse_mount {

/* Entry on fc->mounts */
struct list_head fc_entry;
struct rcu_head rcu;
};

static inline struct fuse_mount *get_fuse_mount_super(struct super_block *sb)
Expand Down
15 changes: 11 additions & 4 deletions fs/fuse/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,14 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm,
}
EXPORT_SYMBOL_GPL(fuse_conn_init);

static void delayed_release(struct rcu_head *p)
{
struct fuse_conn *fc = container_of(p, struct fuse_conn, rcu);

put_user_ns(fc->user_ns);
fc->release(fc);
}

void fuse_conn_put(struct fuse_conn *fc)
{
if (refcount_dec_and_test(&fc->count)) {
Expand All @@ -941,13 +949,12 @@ void fuse_conn_put(struct fuse_conn *fc)
if (fiq->ops->release)
fiq->ops->release(fiq);
put_pid_ns(fc->pid_ns);
put_user_ns(fc->user_ns);
bucket = rcu_dereference_protected(fc->curr_bucket, 1);
if (bucket) {
WARN_ON(atomic_read(&bucket->count) != 1);
kfree(bucket);
}
fc->release(fc);
call_rcu(&fc->rcu, delayed_release);
}
}
EXPORT_SYMBOL_GPL(fuse_conn_put);
Expand Down Expand Up @@ -1366,7 +1373,7 @@ EXPORT_SYMBOL_GPL(fuse_send_init);
void fuse_free_conn(struct fuse_conn *fc)
{
WARN_ON(!list_empty(&fc->devices));
kfree_rcu(fc, rcu);
kfree(fc);
}
EXPORT_SYMBOL_GPL(fuse_free_conn);

Expand Down Expand Up @@ -1902,7 +1909,7 @@ static void fuse_sb_destroy(struct super_block *sb)
void fuse_mount_destroy(struct fuse_mount *fm)
{
fuse_conn_put(fm->fc);
kfree(fm);
kfree_rcu(fm, rcu);
}
EXPORT_SYMBOL(fuse_mount_destroy);

Expand Down

0 comments on commit 053fc4f

Please sign in to comment.