Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fuse: Support fuse filesystems outside of init_user_ns

In order to support mounts from namespaces other than init_user_ns, fuse
must translate uids and gids to/from the userns of the process servicing
requests on /dev/fuse. This patch does that, with a couple of restrictions
on the namespace:

- The userns for the fuse connection is fixed to the namespace
from which /dev/fuse is opened.

- The namespace must be the same as s_user_ns.

These restrictions simplify the implementation by avoiding the need to pass
around userns references and by allowing fuse to rely on the checks in
setattr_prepare for ownership changes. Either restriction could be relaxed
in the future if needed.

For cuse the userns used is the opener of /dev/cuse. Semantically the cuse
support does not appear safe for unprivileged users. Practically the
permissions on /dev/cuse only make it accessible to the global root user.
If something slips through the cracks in a user namespace the only users
who will be able to use the cuse device are those users mapped into the
user namespace.

Translation in the posix acl is updated to use the uuser namespace of the
filesystem. Avoiding cases which might bypass this translation is handled
in a following change.

This change is stronlgy based on a similar change from Seth Forshee and
Dongsu Park.

Cc: Seth Forshee <seth.forshee@canonical.com>
Cc: Dongsu Park <dongsu@kinvolk.io>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>

authored by

Eric W. Biederman and committed by
Miklos Szeredi
8cb08329 c9582eb0

+43 -27
+2 -2
fs/fuse/acl.c
··· 34 34 return ERR_PTR(-ENOMEM); 35 35 size = fuse_getxattr(inode, name, value, PAGE_SIZE); 36 36 if (size > 0) 37 - acl = posix_acl_from_xattr(&init_user_ns, value, size); 37 + acl = posix_acl_from_xattr(fc->user_ns, value, size); 38 38 else if ((size == 0) || (size == -ENODATA) || 39 39 (size == -EOPNOTSUPP && fc->no_getxattr)) 40 40 acl = NULL; ··· 81 81 if (!value) 82 82 return -ENOMEM; 83 83 84 - ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); 84 + ret = posix_acl_to_xattr(fc->user_ns, acl, value, size); 85 85 if (ret < 0) { 86 86 kfree(value); 87 87 return ret;
+6 -1
fs/fuse/cuse.c
··· 48 48 #include <linux/stat.h> 49 49 #include <linux/module.h> 50 50 #include <linux/uio.h> 51 + #include <linux/user_namespace.h> 51 52 52 53 #include "fuse_i.h" 53 54 ··· 499 498 if (!cc) 500 499 return -ENOMEM; 501 500 502 - fuse_conn_init(&cc->fc); 501 + /* 502 + * Limit the cuse channel to requests that can 503 + * be represented in file->f_cred->user_ns. 504 + */ 505 + fuse_conn_init(&cc->fc, file->f_cred->user_ns); 503 506 504 507 fud = fuse_dev_alloc(&cc->fc); 505 508 if (!fud) {
+4 -4
fs/fuse/dev.c
··· 156 156 goto out; 157 157 } 158 158 159 - req->in.h.uid = from_kuid(&init_user_ns, current_fsuid()); 160 - req->in.h.gid = from_kgid(&init_user_ns, current_fsgid()); 159 + req->in.h.uid = from_kuid(fc->user_ns, current_fsuid()); 160 + req->in.h.gid = from_kgid(fc->user_ns, current_fsgid()); 161 161 req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns); 162 162 163 163 __set_bit(FR_WAITING, &req->flags); ··· 257 257 if (!req) 258 258 req = get_reserved_req(fc, file); 259 259 260 - req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid()); 261 - req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid()); 260 + req->in.h.uid = from_kuid_munged(fc->user_ns, current_fsuid()); 261 + req->in.h.gid = from_kgid_munged(fc->user_ns, current_fsgid()); 262 262 req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns); 263 263 264 264 __set_bit(FR_WAITING, &req->flags);
+7 -7
fs/fuse/dir.c
··· 858 858 stat->ino = attr->ino; 859 859 stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); 860 860 stat->nlink = attr->nlink; 861 - stat->uid = make_kuid(&init_user_ns, attr->uid); 862 - stat->gid = make_kgid(&init_user_ns, attr->gid); 861 + stat->uid = make_kuid(fc->user_ns, attr->uid); 862 + stat->gid = make_kgid(fc->user_ns, attr->gid); 863 863 stat->rdev = inode->i_rdev; 864 864 stat->atime.tv_sec = attr->atime; 865 865 stat->atime.tv_nsec = attr->atimensec; ··· 1475 1475 return true; 1476 1476 } 1477 1477 1478 - static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg, 1479 - bool trust_local_cmtime) 1478 + static void iattr_to_fattr(struct fuse_conn *fc, struct iattr *iattr, 1479 + struct fuse_setattr_in *arg, bool trust_local_cmtime) 1480 1480 { 1481 1481 unsigned ivalid = iattr->ia_valid; 1482 1482 1483 1483 if (ivalid & ATTR_MODE) 1484 1484 arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode; 1485 1485 if (ivalid & ATTR_UID) 1486 - arg->valid |= FATTR_UID, arg->uid = from_kuid(&init_user_ns, iattr->ia_uid); 1486 + arg->valid |= FATTR_UID, arg->uid = from_kuid(fc->user_ns, iattr->ia_uid); 1487 1487 if (ivalid & ATTR_GID) 1488 - arg->valid |= FATTR_GID, arg->gid = from_kgid(&init_user_ns, iattr->ia_gid); 1488 + arg->valid |= FATTR_GID, arg->gid = from_kgid(fc->user_ns, iattr->ia_gid); 1489 1489 if (ivalid & ATTR_SIZE) 1490 1490 arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size; 1491 1491 if (ivalid & ATTR_ATIME) { ··· 1657 1657 1658 1658 memset(&inarg, 0, sizeof(inarg)); 1659 1659 memset(&outarg, 0, sizeof(outarg)); 1660 - iattr_to_fattr(attr, &inarg, trust_local_cmtime); 1660 + iattr_to_fattr(fc, attr, &inarg, trust_local_cmtime); 1661 1661 if (file) { 1662 1662 struct fuse_file *ff = file->private_data; 1663 1663 inarg.valid |= FATTR_FH;
+5 -1
fs/fuse/fuse_i.h
··· 26 26 #include <linux/xattr.h> 27 27 #include <linux/pid_namespace.h> 28 28 #include <linux/refcount.h> 29 + #include <linux/user_namespace.h> 29 30 30 31 /** Max number of pages that can be used in a single read request */ 31 32 #define FUSE_MAX_PAGES_PER_REQ 32 ··· 467 466 /** The pid namespace for this mount */ 468 467 struct pid_namespace *pid_ns; 469 468 469 + /** The user namespace for this mount */ 470 + struct user_namespace *user_ns; 471 + 470 472 /** Maximum read size */ 471 473 unsigned max_read; 472 474 ··· 880 876 /** 881 877 * Initialize fuse_conn 882 878 */ 883 - void fuse_conn_init(struct fuse_conn *fc); 879 + void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns); 884 880 885 881 /** 886 882 * Release reference to fuse_conn
+19 -12
fs/fuse/inode.c
··· 171 171 inode->i_ino = fuse_squash_ino(attr->ino); 172 172 inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); 173 173 set_nlink(inode, attr->nlink); 174 - inode->i_uid = make_kuid(&init_user_ns, attr->uid); 175 - inode->i_gid = make_kgid(&init_user_ns, attr->gid); 174 + inode->i_uid = make_kuid(fc->user_ns, attr->uid); 175 + inode->i_gid = make_kgid(fc->user_ns, attr->gid); 176 176 inode->i_blocks = attr->blocks; 177 177 inode->i_atime.tv_sec = attr->atime; 178 178 inode->i_atime.tv_nsec = attr->atimensec; ··· 477 477 return err; 478 478 } 479 479 480 - static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev) 480 + static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev, 481 + struct user_namespace *user_ns) 481 482 { 482 483 char *p; 483 484 memset(d, 0, sizeof(struct fuse_mount_data)); ··· 514 513 case OPT_USER_ID: 515 514 if (fuse_match_uint(&args[0], &uv)) 516 515 return 0; 517 - d->user_id = make_kuid(current_user_ns(), uv); 516 + d->user_id = make_kuid(user_ns, uv); 518 517 if (!uid_valid(d->user_id)) 519 518 return 0; 520 519 d->user_id_present = 1; ··· 523 522 case OPT_GROUP_ID: 524 523 if (fuse_match_uint(&args[0], &uv)) 525 524 return 0; 526 - d->group_id = make_kgid(current_user_ns(), uv); 525 + d->group_id = make_kgid(user_ns, uv); 527 526 if (!gid_valid(d->group_id)) 528 527 return 0; 529 528 d->group_id_present = 1; ··· 566 565 struct super_block *sb = root->d_sb; 567 566 struct fuse_conn *fc = get_fuse_conn_super(sb); 568 567 569 - seq_printf(m, ",user_id=%u", from_kuid_munged(&init_user_ns, fc->user_id)); 570 - seq_printf(m, ",group_id=%u", from_kgid_munged(&init_user_ns, fc->group_id)); 568 + seq_printf(m, ",user_id=%u", from_kuid_munged(fc->user_ns, fc->user_id)); 569 + seq_printf(m, ",group_id=%u", from_kgid_munged(fc->user_ns, fc->group_id)); 571 570 if (fc->default_permissions) 572 571 seq_puts(m, ",default_permissions"); 573 572 if (fc->allow_other) ··· 598 597 fpq->connected = 1; 599 598 } 600 599 601 - void fuse_conn_init(struct fuse_conn *fc) 600 + void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns) 602 601 { 603 602 memset(fc, 0, sizeof(*fc)); 604 603 spin_lock_init(&fc->lock); ··· 622 621 fc->attr_version = 1; 623 622 get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); 624 623 fc->pid_ns = get_pid_ns(task_active_pid_ns(current)); 624 + fc->user_ns = get_user_ns(user_ns); 625 625 } 626 626 EXPORT_SYMBOL_GPL(fuse_conn_init); 627 627 ··· 632 630 if (fc->destroy_req) 633 631 fuse_request_free(fc->destroy_req); 634 632 put_pid_ns(fc->pid_ns); 633 + put_user_ns(fc->user_ns); 635 634 fc->release(fc); 636 635 } 637 636 } ··· 1067 1064 1068 1065 sb->s_flags &= ~(SB_NOSEC | SB_I_VERSION); 1069 1066 1070 - if (!parse_fuse_opt(data, &d, is_bdev)) 1067 + if (!parse_fuse_opt(data, &d, is_bdev, sb->s_user_ns)) 1071 1068 goto err; 1072 1069 1073 1070 if (is_bdev) { ··· 1092 1089 if (!file) 1093 1090 goto err; 1094 1091 1095 - if ((file->f_op != &fuse_dev_operations) || 1096 - (file->f_cred->user_ns != &init_user_ns)) 1092 + /* 1093 + * Require mount to happen from the same user namespace which 1094 + * opened /dev/fuse to prevent potential attacks. 1095 + */ 1096 + if (file->f_op != &fuse_dev_operations || 1097 + file->f_cred->user_ns != sb->s_user_ns) 1097 1098 goto err_fput; 1098 1099 1099 1100 fc = kmalloc(sizeof(*fc), GFP_KERNEL); ··· 1105 1098 if (!fc) 1106 1099 goto err_fput; 1107 1100 1108 - fuse_conn_init(fc); 1101 + fuse_conn_init(fc, sb->s_user_ns); 1109 1102 fc->release = fuse_free_conn; 1110 1103 1111 1104 fud = fuse_dev_alloc(fc);