Merge tag 'vfs-6.11-rc1.fixes.3' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull vfs fixes from Christian Brauner:
"This contains two fixes for this merge window:

VFS:

- I noticed that it is possible for a privileged user to mount most
filesystems with a non-initial user namespace in sb->s_user_ns.

When fsopen() is called in a non-init namespace the caller's
namespace is recorded in fs_context->user_ns. If the returned file
descriptor is then passed to a process privileged in init_user_ns,
that process can call fsconfig(fd_fs, FSCONFIG_CMD_CREATE*),
creating a new superblock with sb->s_user_ns set to the namespace
of the process which called fsopen().

This is problematic as only filesystems that raise FS_USERNS_MOUNT
are known to be able to support a non-initial s_user_ns. Others may
suffer security issues, on-disk corruption or outright crash the
kernel. Prevent that by restricting such delegation to filesystems
that allow FS_USERNS_MOUNT.

Note, that this delegation requires a privileged process to
actually create the superblock so either the privileged process is
cooperaing or someone must have tricked a privileged process into
operating on a fscontext file descriptor whose origin it doesn't
know (a stupid idea).

The bug dates back to about 5 years afaict.

Misc:

- Fix hostfs parsing when the mount request comes in via the legacy
mount api.

In the legacy mount api hostfs allows to specify the host directory
mount without any key.

Restore that behavior"

* tag 'vfs-6.11-rc1.fixes.3' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
hostfs: fix the host directory parse when mounting.
fs: don't allow non-init s_user_ns for filesystems without FS_USERNS_MOUNT

+66 -10
+55 -10
fs/hostfs/hostfs_kern.c
··· 17 17 #include <linux/writeback.h> 18 18 #include <linux/mount.h> 19 19 #include <linux/fs_context.h> 20 + #include <linux/fs_parser.h> 20 21 #include <linux/namei.h> 21 22 #include "hostfs.h" 22 23 #include <init.h> ··· 930 929 static int hostfs_fill_super(struct super_block *sb, struct fs_context *fc) 931 930 { 932 931 struct hostfs_fs_info *fsi = sb->s_fs_info; 933 - const char *host_root = fc->source; 934 932 struct inode *root_inode; 935 933 int err; 936 934 ··· 942 942 err = super_setup_bdi(sb); 943 943 if (err) 944 944 return err; 945 - 946 - /* NULL is printed as '(null)' by printf(): avoid that. */ 947 - if (fc->source == NULL) 948 - host_root = ""; 949 - 950 - fsi->host_root_path = 951 - kasprintf(GFP_KERNEL, "%s/%s", root_ino, host_root); 952 - if (fsi->host_root_path == NULL) 953 - return -ENOMEM; 954 945 955 946 root_inode = hostfs_iget(sb, fsi->host_root_path); 956 947 if (IS_ERR(root_inode)) ··· 968 977 return 0; 969 978 } 970 979 980 + enum hostfs_parma { 981 + Opt_hostfs, 982 + }; 983 + 984 + static const struct fs_parameter_spec hostfs_param_specs[] = { 985 + fsparam_string_empty("hostfs", Opt_hostfs), 986 + {} 987 + }; 988 + 989 + static int hostfs_parse_param(struct fs_context *fc, struct fs_parameter *param) 990 + { 991 + struct hostfs_fs_info *fsi = fc->s_fs_info; 992 + struct fs_parse_result result; 993 + char *host_root; 994 + int opt; 995 + 996 + opt = fs_parse(fc, hostfs_param_specs, param, &result); 997 + if (opt < 0) 998 + return opt; 999 + 1000 + switch (opt) { 1001 + case Opt_hostfs: 1002 + host_root = param->string; 1003 + if (!*host_root) 1004 + host_root = ""; 1005 + fsi->host_root_path = 1006 + kasprintf(GFP_KERNEL, "%s/%s", root_ino, host_root); 1007 + if (fsi->host_root_path == NULL) 1008 + return -ENOMEM; 1009 + break; 1010 + } 1011 + 1012 + return 0; 1013 + } 1014 + 1015 + static int hostfs_parse_monolithic(struct fs_context *fc, void *data) 1016 + { 1017 + struct hostfs_fs_info *fsi = fc->s_fs_info; 1018 + char *host_root = (char *)data; 1019 + 1020 + /* NULL is printed as '(null)' by printf(): avoid that. */ 1021 + if (host_root == NULL) 1022 + host_root = ""; 1023 + 1024 + fsi->host_root_path = 1025 + kasprintf(GFP_KERNEL, "%s/%s", root_ino, host_root); 1026 + if (fsi->host_root_path == NULL) 1027 + return -ENOMEM; 1028 + 1029 + return 0; 1030 + } 1031 + 971 1032 static int hostfs_fc_get_tree(struct fs_context *fc) 972 1033 { 973 1034 return get_tree_nodev(fc, hostfs_fill_super); ··· 1037 994 } 1038 995 1039 996 static const struct fs_context_operations hostfs_context_ops = { 997 + .parse_monolithic = hostfs_parse_monolithic, 998 + .parse_param = hostfs_parse_param, 1040 999 .get_tree = hostfs_fc_get_tree, 1041 1000 .free = hostfs_fc_free, 1042 1001 };
+11
fs/super.c
··· 736 736 struct user_namespace *user_ns = fc->global ? &init_user_ns : fc->user_ns; 737 737 int err; 738 738 739 + /* 740 + * Never allow s_user_ns != &init_user_ns when FS_USERNS_MOUNT is 741 + * not set, as the filesystem is likely unprepared to handle it. 742 + * This can happen when fsconfig() is called from init_user_ns with 743 + * an fs_fd opened in another user namespace. 744 + */ 745 + if (user_ns != &init_user_ns && !(fc->fs_type->fs_flags & FS_USERNS_MOUNT)) { 746 + errorfc(fc, "VFS: Mounting from non-initial user namespace is not allowed"); 747 + return ERR_PTR(-EPERM); 748 + } 749 + 739 750 retry: 740 751 spin_lock(&sb_lock); 741 752 if (test) {