blob: d256f1ac9ff1bf1158b483b7c7efc85abc55a367 [file] [log] [blame]
David Howells24dcb3d2018-11-01 23:33:31 +00001/* Filesystem access-by-fd.
2 *
3 * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12#include <linux/fs_context.h>
13#include <linux/slab.h>
14#include <linux/uaccess.h>
15#include <linux/syscalls.h>
16#include <linux/security.h>
17#include <linux/anon_inodes.h>
18#include <linux/namei.h>
19#include <linux/file.h>
20#include <uapi/linux/mount.h>
21#include "mount.h"
22
23static int fscontext_release(struct inode *inode, struct file *file)
24{
25 struct fs_context *fc = file->private_data;
26
27 if (fc) {
28 file->private_data = NULL;
29 put_fs_context(fc);
30 }
31 return 0;
32}
33
34const struct file_operations fscontext_fops = {
35 .release = fscontext_release,
36 .llseek = no_llseek,
37};
38
39/*
40 * Attach a filesystem context to a file and an fd.
41 */
42static int fscontext_create_fd(struct fs_context *fc, unsigned int o_flags)
43{
44 int fd;
45
46 fd = anon_inode_getfd("fscontext", &fscontext_fops, fc,
47 O_RDWR | o_flags);
48 if (fd < 0)
49 put_fs_context(fc);
50 return fd;
51}
52
53/*
54 * Open a filesystem by name so that it can be configured for mounting.
55 *
56 * We are allowed to specify a container in which the filesystem will be
57 * opened, thereby indicating which namespaces will be used (notably, which
58 * network namespace will be used for network filesystems).
59 */
60SYSCALL_DEFINE2(fsopen, const char __user *, _fs_name, unsigned int, flags)
61{
62 struct file_system_type *fs_type;
63 struct fs_context *fc;
64 const char *fs_name;
65
66 if (!ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN))
67 return -EPERM;
68
69 if (flags & ~FSOPEN_CLOEXEC)
70 return -EINVAL;
71
72 fs_name = strndup_user(_fs_name, PAGE_SIZE);
73 if (IS_ERR(fs_name))
74 return PTR_ERR(fs_name);
75
76 fs_type = get_fs_type(fs_name);
77 kfree(fs_name);
78 if (!fs_type)
79 return -ENODEV;
80
81 fc = fs_context_for_mount(fs_type, 0);
82 put_filesystem(fs_type);
83 if (IS_ERR(fc))
84 return PTR_ERR(fc);
85
86 fc->phase = FS_CONTEXT_CREATE_PARAMS;
87 return fscontext_create_fd(fc, flags & FSOPEN_CLOEXEC ? O_CLOEXEC : 0);
88}