bcachefs: Fix pool->alloc NULL pointer dereference
authorAlan Huang <mmpgouride@gmail.com>
Sun, 15 Jun 2025 05:41:22 +0000 (13:41 +0800)
committerKent Overstreet <kent.overstreet@linux.dev>
Mon, 16 Jun 2025 23:03:52 +0000 (19:03 -0400)
btree_interior_update_pool has not been initialized before the
filesystem becomes read-write, thus mempool_alloc in bch2_btree_update_start
will trigger pool->alloc NULL pointer dereference in mempool_alloc_noprof

Reported-by: syzbot+2f3859bd28f20fa682e6@syzkaller.appspotmail.com
Signed-off-by: Alan Huang <mmpgouride@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/bcachefs.h
fs/bcachefs/chardev.c

index 5a1cede2febf5e3d070cfa5eee097203219317b9..8043943cdf6ac591a5ee8ecf40b30da1f3c44d77 100644 (file)
@@ -767,7 +767,8 @@ struct btree_trans_buf {
        x(sysfs)                                                        \
        x(btree_write_buffer)                                           \
        x(btree_node_scrub)                                             \
-       x(async_recovery_passes)
+       x(async_recovery_passes)                                        \
+       x(ioctl_data)
 
 enum bch_write_ref {
 #define x(n) BCH_WRITE_REF_##n,
index fde3c2380e28e79f22b189577256517dc26f92eb..5ea89aa2b0c42ab935bd60d4db96f23bf38089c0 100644 (file)
@@ -319,6 +319,7 @@ static int bch2_data_thread(void *arg)
                ctx->stats.ret = BCH_IOCTL_DATA_EVENT_RET_done;
                ctx->stats.data_type = (int) DATA_PROGRESS_DATA_TYPE_done;
        }
+       enumerated_ref_put(&ctx->c->writes, BCH_WRITE_REF_ioctl_data);
        return 0;
 }
 
@@ -378,15 +379,24 @@ static long bch2_ioctl_data(struct bch_fs *c,
        struct bch_data_ctx *ctx;
        int ret;
 
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
+       if (!enumerated_ref_tryget(&c->writes, BCH_WRITE_REF_ioctl_data))
+               return -EROFS;
 
-       if (arg.op >= BCH_DATA_OP_NR || arg.flags)
-               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN)) {
+               ret = -EPERM;
+               goto put_ref;
+       }
+
+       if (arg.op >= BCH_DATA_OP_NR || arg.flags) {
+               ret = -EINVAL;
+               goto put_ref;
+       }
 
        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-       if (!ctx)
-               return -ENOMEM;
+       if (!ctx) {
+               ret = -ENOMEM;
+               goto put_ref;
+       }
 
        ctx->c = c;
        ctx->arg = arg;
@@ -395,7 +405,12 @@ static long bch2_ioctl_data(struct bch_fs *c,
                        &bcachefs_data_ops,
                        bch2_data_thread);
        if (ret < 0)
-               kfree(ctx);
+               goto cleanup;
+       return ret;
+cleanup:
+       kfree(ctx);
+put_ref:
+       enumerated_ref_put(&c->writes, BCH_WRITE_REF_ioctl_data);
        return ret;
 }