]> www.infradead.org Git - linux.git/commitdiff
bcachefs: support idmap mounts
authorHongbo Li <lihongbo22@huawei.com>
Sat, 24 Aug 2024 01:27:24 +0000 (09:27 +0800)
committerKent Overstreet <kent.overstreet@linux.dev>
Mon, 9 Sep 2024 13:41:49 +0000 (09:41 -0400)
We enable idmapped mounts for bcachefs. Here, we just pass down
the user_namespace argument from the VFS methods to the relevant
helpers.

The idmap test in bcachefs is as following:

```
1. losetup /dev/loop1 bcachefs.img
2. ./bcachefs format /dev/loop1
3. mount -t bcachefs /dev/loop1 /mnt/bcachefs/
4. ./mount-idmapped --map-mount b:0:1000:1 /mnt/bcachefs /mnt/idmapped1/

ll /mnt/bcachefs
total 2
drwx------. 2 root root    0 Jun 14 14:10 lost+found
-rw-r--r--. 1 root root 1945 Jun 14 14:12 profile

ll /mnt/idmapped1/

total 2
drwx------. 2 1000 1000    0 Jun 14 14:10 lost+found
-rw-r--r--. 1 1000 1000 1945 Jun 14 14:12 profile

Signed-off-by: Hongbo Li <lihongbo22@huawei.com>
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/fs.c

index 2de776d31b52f8a1dc56abb2dd8e9995c0891aec..866ce1f1a6d1828f7ded58ed386a0712e310119e 100644 (file)
@@ -385,6 +385,8 @@ __bch2_create(struct mnt_idmap *idmap,
        subvol_inum inum;
        struct bch_subvolume subvol;
        u64 journal_seq = 0;
+       kuid_t kuid;
+       kgid_t kgid;
        int ret;
 
        /*
@@ -411,13 +413,15 @@ __bch2_create(struct mnt_idmap *idmap,
 retry:
        bch2_trans_begin(trans);
 
+       kuid = mapped_fsuid(idmap, i_user_ns(&dir->v));
+       kgid = mapped_fsgid(idmap, i_user_ns(&dir->v));
        ret   = bch2_subvol_is_ro_trans(trans, dir->ei_inum.subvol) ?:
                bch2_create_trans(trans,
                                  inode_inum(dir), &dir_u, &inode_u,
                                  !(flags & BCH_CREATE_TMPFILE)
                                  ? &dentry->d_name : NULL,
-                                 from_kuid(i_user_ns(&dir->v), current_fsuid()),
-                                 from_kgid(i_user_ns(&dir->v), current_fsgid()),
+                                 from_kuid(i_user_ns(&dir->v), kuid),
+                                 from_kgid(i_user_ns(&dir->v), kgid),
                                  mode, rdev,
                                  default_acl, acl, snapshot_src, flags) ?:
                bch2_quota_acct(c, bch_qid(&inode_u), Q_INO, 1,
@@ -840,11 +844,17 @@ static void bch2_setattr_copy(struct mnt_idmap *idmap,
 {
        struct bch_fs *c = inode->v.i_sb->s_fs_info;
        unsigned int ia_valid = attr->ia_valid;
+       kuid_t kuid;
+       kgid_t kgid;
 
-       if (ia_valid & ATTR_UID)
-               bi->bi_uid = from_kuid(i_user_ns(&inode->v), attr->ia_uid);
-       if (ia_valid & ATTR_GID)
-               bi->bi_gid = from_kgid(i_user_ns(&inode->v), attr->ia_gid);
+       if (ia_valid & ATTR_UID) {
+               kuid = from_vfsuid(idmap, i_user_ns(&inode->v), attr->ia_vfsuid);
+               bi->bi_uid = from_kuid(i_user_ns(&inode->v), kuid);
+       }
+       if (ia_valid & ATTR_GID) {
+               kgid = from_vfsgid(idmap, i_user_ns(&inode->v), attr->ia_vfsgid);
+               bi->bi_gid = from_kgid(i_user_ns(&inode->v), kgid);
+       }
 
        if (ia_valid & ATTR_SIZE)
                bi->bi_size = attr->ia_size;
@@ -859,11 +869,11 @@ static void bch2_setattr_copy(struct mnt_idmap *idmap,
        if (ia_valid & ATTR_MODE) {
                umode_t mode = attr->ia_mode;
                kgid_t gid = ia_valid & ATTR_GID
-                       ? attr->ia_gid
+                       ? kgid
                        : inode->v.i_gid;
 
-               if (!in_group_p(gid) &&
-                   !capable_wrt_inode_uidgid(idmap, &inode->v, CAP_FSETID))
+               if (!in_group_or_capable(idmap, &inode->v,
+                       make_vfsgid(idmap, i_user_ns(&inode->v), gid)))
                        mode &= ~S_ISGID;
                bi->bi_mode = mode;
        }
@@ -879,17 +889,23 @@ int bch2_setattr_nonsize(struct mnt_idmap *idmap,
        struct btree_iter inode_iter = { NULL };
        struct bch_inode_unpacked inode_u;
        struct posix_acl *acl = NULL;
+       kuid_t kuid;
+       kgid_t kgid;
        int ret;
 
        mutex_lock(&inode->ei_update_lock);
 
        qid = inode->ei_qid;
 
-       if (attr->ia_valid & ATTR_UID)
-               qid.q[QTYP_USR] = from_kuid(i_user_ns(&inode->v), attr->ia_uid);
+       if (attr->ia_valid & ATTR_UID) {
+               kuid = from_vfsuid(idmap, i_user_ns(&inode->v), attr->ia_vfsuid);
+               qid.q[QTYP_USR] = from_kuid(i_user_ns(&inode->v), kuid);
+       }
 
-       if (attr->ia_valid & ATTR_GID)
-               qid.q[QTYP_GRP] = from_kgid(i_user_ns(&inode->v), attr->ia_gid);
+       if (attr->ia_valid & ATTR_GID) {
+               kgid = from_vfsgid(idmap, i_user_ns(&inode->v), attr->ia_vfsgid);
+               qid.q[QTYP_GRP] = from_kgid(i_user_ns(&inode->v), kgid);
+       }
 
        ret = bch2_fs_quota_transfer(c, inode, qid, ~0,
                                     KEY_TYPE_QUOTA_PREALLOC);
@@ -945,13 +961,15 @@ static int bch2_getattr(struct mnt_idmap *idmap,
 {
        struct bch_inode_info *inode = to_bch_ei(d_inode(path->dentry));
        struct bch_fs *c = inode->v.i_sb->s_fs_info;
+       vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, &inode->v);
+       vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, &inode->v);
 
        stat->dev       = inode->v.i_sb->s_dev;
        stat->ino       = inode->v.i_ino;
        stat->mode      = inode->v.i_mode;
        stat->nlink     = inode->v.i_nlink;
-       stat->uid       = inode->v.i_uid;
-       stat->gid       = inode->v.i_gid;
+       stat->uid       = vfsuid_into_kuid(vfsuid);
+       stat->gid       = vfsgid_into_kgid(vfsgid);
        stat->rdev      = inode->v.i_rdev;
        stat->size      = i_size_read(&inode->v);
        stat->atime     = inode_get_atime(&inode->v);
@@ -2225,7 +2243,7 @@ static struct file_system_type bcache_fs_type = {
        .name                   = "bcachefs",
        .init_fs_context        = bch2_init_fs_context,
        .kill_sb                = bch2_kill_sb,
-       .fs_flags               = FS_REQUIRES_DEV,
+       .fs_flags               = FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
 };
 
 MODULE_ALIAS_FS("bcachefs");