Skip to content

Commit bc4eee8

Browse files
committed
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
2 parents 910bfc2 + ef9ca17 commit bc4eee8

File tree

2 files changed

+66
-10
lines changed

2 files changed

+66
-10
lines changed

fs/hostfs/hostfs_kern.c

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/writeback.h>
1818
#include <linux/mount.h>
1919
#include <linux/fs_context.h>
20+
#include <linux/fs_parser.h>
2021
#include <linux/namei.h>
2122
#include "hostfs.h"
2223
#include <init.h>
@@ -929,7 +930,6 @@ static const struct inode_operations hostfs_link_iops = {
929930
static int hostfs_fill_super(struct super_block *sb, struct fs_context *fc)
930931
{
931932
struct hostfs_fs_info *fsi = sb->s_fs_info;
932-
const char *host_root = fc->source;
933933
struct inode *root_inode;
934934
int err;
935935

@@ -943,15 +943,6 @@ static int hostfs_fill_super(struct super_block *sb, struct fs_context *fc)
943943
if (err)
944944
return err;
945945

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-
955946
root_inode = hostfs_iget(sb, fsi->host_root_path);
956947
if (IS_ERR(root_inode))
957948
return PTR_ERR(root_inode);
@@ -977,6 +968,58 @@ static int hostfs_fill_super(struct super_block *sb, struct fs_context *fc)
977968
return 0;
978969
}
979970

971+
enum hostfs_parma {
972+
Opt_hostfs,
973+
};
974+
975+
static const struct fs_parameter_spec hostfs_param_specs[] = {
976+
fsparam_string_empty("hostfs", Opt_hostfs),
977+
{}
978+
};
979+
980+
static int hostfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
981+
{
982+
struct hostfs_fs_info *fsi = fc->s_fs_info;
983+
struct fs_parse_result result;
984+
char *host_root;
985+
int opt;
986+
987+
opt = fs_parse(fc, hostfs_param_specs, param, &result);
988+
if (opt < 0)
989+
return opt;
990+
991+
switch (opt) {
992+
case Opt_hostfs:
993+
host_root = param->string;
994+
if (!*host_root)
995+
host_root = "";
996+
fsi->host_root_path =
997+
kasprintf(GFP_KERNEL, "%s/%s", root_ino, host_root);
998+
if (fsi->host_root_path == NULL)
999+
return -ENOMEM;
1000+
break;
1001+
}
1002+
1003+
return 0;
1004+
}
1005+
1006+
static int hostfs_parse_monolithic(struct fs_context *fc, void *data)
1007+
{
1008+
struct hostfs_fs_info *fsi = fc->s_fs_info;
1009+
char *host_root = (char *)data;
1010+
1011+
/* NULL is printed as '(null)' by printf(): avoid that. */
1012+
if (host_root == NULL)
1013+
host_root = "";
1014+
1015+
fsi->host_root_path =
1016+
kasprintf(GFP_KERNEL, "%s/%s", root_ino, host_root);
1017+
if (fsi->host_root_path == NULL)
1018+
return -ENOMEM;
1019+
1020+
return 0;
1021+
}
1022+
9801023
static int hostfs_fc_get_tree(struct fs_context *fc)
9811024
{
9821025
return get_tree_nodev(fc, hostfs_fill_super);
@@ -994,6 +1037,8 @@ static void hostfs_fc_free(struct fs_context *fc)
9941037
}
9951038

9961039
static const struct fs_context_operations hostfs_context_ops = {
1040+
.parse_monolithic = hostfs_parse_monolithic,
1041+
.parse_param = hostfs_parse_param,
9971042
.get_tree = hostfs_fc_get_tree,
9981043
.free = hostfs_fc_free,
9991044
};

fs/super.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,17 @@ struct super_block *sget_fc(struct fs_context *fc,
736736
struct user_namespace *user_ns = fc->global ? &init_user_ns : fc->user_ns;
737737
int err;
738738

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+
739750
retry:
740751
spin_lock(&sb_lock);
741752
if (test) {

0 commit comments

Comments
 (0)