fs: Better permission checking for submounts
am: d3381fab77
Change-Id: I5f0019d2c86afd0a055f823f6751db9f6378e38f
This commit is contained in:
+1
-1
@@ -202,7 +202,7 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
|
||||
|
||||
/* try and do the mount */
|
||||
_debug("--- attempting mount %s -o %s ---", devname, options);
|
||||
mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options);
|
||||
mnt = vfs_submount(mntpt, &afs_fs_type, devname, options);
|
||||
_debug("--- mount result %p ---", mnt);
|
||||
|
||||
free_page((unsigned long) devname);
|
||||
|
||||
+2
-2
@@ -431,8 +431,8 @@ int autofs4_wait(struct autofs_sb_info *sbi,
|
||||
memcpy(&wq->name, &qstr, sizeof(struct qstr));
|
||||
wq->dev = autofs4_get_dev(sbi);
|
||||
wq->ino = autofs4_get_ino(sbi);
|
||||
wq->uid = current_real_cred()->uid;
|
||||
wq->gid = current_real_cred()->gid;
|
||||
wq->uid = current_cred()->uid;
|
||||
wq->gid = current_cred()->gid;
|
||||
wq->pid = pid;
|
||||
wq->tgid = tgid;
|
||||
wq->status = -EINTR; /* Status return if interrupted */
|
||||
|
||||
@@ -245,7 +245,8 @@ compose_mount_options_err:
|
||||
* @fullpath: full path in UNC format
|
||||
* @ref: server's referral
|
||||
*/
|
||||
static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb,
|
||||
static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *fullpath, const struct dfs_info3_param *ref)
|
||||
{
|
||||
struct vfsmount *mnt;
|
||||
@@ -259,7 +260,7 @@ static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb,
|
||||
if (IS_ERR(mountdata))
|
||||
return (struct vfsmount *)mountdata;
|
||||
|
||||
mnt = vfs_kern_mount(&cifs_fs_type, 0, devname, mountdata);
|
||||
mnt = vfs_submount(mntpt, &cifs_fs_type, devname, mountdata);
|
||||
kfree(mountdata);
|
||||
kfree(devname);
|
||||
return mnt;
|
||||
@@ -334,7 +335,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
|
||||
mnt = ERR_PTR(-EINVAL);
|
||||
break;
|
||||
}
|
||||
mnt = cifs_dfs_do_refmount(cifs_sb,
|
||||
mnt = cifs_dfs_do_refmount(mntpt, cifs_sb,
|
||||
full_path, referrals + i);
|
||||
cifs_dbg(FYI, "%s: cifs_dfs_do_refmount:%s , mnt:%p\n",
|
||||
__func__, referrals[i].node_name, mnt);
|
||||
|
||||
+4
-4
@@ -187,9 +187,9 @@ static const struct super_operations debugfs_super_operations = {
|
||||
|
||||
static struct vfsmount *debugfs_automount(struct path *path)
|
||||
{
|
||||
struct vfsmount *(*f)(void *);
|
||||
f = (struct vfsmount *(*)(void *))path->dentry->d_fsdata;
|
||||
return f(d_inode(path->dentry)->i_private);
|
||||
debugfs_automount_t f;
|
||||
f = (debugfs_automount_t)path->dentry->d_fsdata;
|
||||
return f(path->dentry, d_inode(path->dentry)->i_private);
|
||||
}
|
||||
|
||||
static const struct dentry_operations debugfs_dops = {
|
||||
@@ -504,7 +504,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_dir);
|
||||
*/
|
||||
struct dentry *debugfs_create_automount(const char *name,
|
||||
struct dentry *parent,
|
||||
struct vfsmount *(*f)(void *),
|
||||
debugfs_automount_t f,
|
||||
void *data)
|
||||
{
|
||||
struct dentry *dentry = start_creating(name, parent);
|
||||
|
||||
@@ -1115,7 +1115,6 @@ static int follow_automount(struct path *path, struct nameidata *nd,
|
||||
bool *need_mntput)
|
||||
{
|
||||
struct vfsmount *mnt;
|
||||
const struct cred *old_cred;
|
||||
int err;
|
||||
|
||||
if (!path->dentry->d_op || !path->dentry->d_op->d_automount)
|
||||
@@ -1144,9 +1143,7 @@ static int follow_automount(struct path *path, struct nameidata *nd,
|
||||
if (nd->total_link_count >= 40)
|
||||
return -ELOOP;
|
||||
|
||||
old_cred = override_creds(&init_cred);
|
||||
mnt = path->dentry->d_op->d_automount(path);
|
||||
revert_creds(old_cred);
|
||||
if (IS_ERR(mnt)) {
|
||||
/*
|
||||
* The filesystem is allowed to return -EISDIR here to indicate
|
||||
|
||||
+16
-1
@@ -1006,6 +1006,21 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vfs_kern_mount);
|
||||
|
||||
struct vfsmount *
|
||||
vfs_submount(const struct dentry *mountpoint, struct file_system_type *type,
|
||||
const char *name, void *data)
|
||||
{
|
||||
/* Until it is worked out how to pass the user namespace
|
||||
* through from the parent mount to the submount don't support
|
||||
* unprivileged mounts with submounts.
|
||||
*/
|
||||
if (mountpoint->d_sb->s_user_ns != &init_user_ns)
|
||||
return ERR_PTR(-EPERM);
|
||||
|
||||
return vfs_kern_mount(type, MS_SUBMOUNT, name, data);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vfs_submount);
|
||||
|
||||
static struct mount *clone_mnt(struct mount *old, struct dentry *root,
|
||||
int flag)
|
||||
{
|
||||
@@ -2805,7 +2820,7 @@ long do_mount(const char *dev_name, const char __user *dir_name,
|
||||
|
||||
flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN |
|
||||
MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
|
||||
MS_STRICTATIME | MS_NOREMOTELOCK);
|
||||
MS_STRICTATIME | MS_NOREMOTELOCK | MS_SUBMOUNT);
|
||||
|
||||
if (flags & MS_REMOUNT)
|
||||
retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
|
||||
|
||||
+1
-1
@@ -226,7 +226,7 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,
|
||||
const char *devname,
|
||||
struct nfs_clone_mount *mountdata)
|
||||
{
|
||||
return vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata);
|
||||
return vfs_submount(mountdata->dentry, &nfs_xdev_fs_type, devname, mountdata);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -279,7 +279,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
|
||||
mountdata->hostname,
|
||||
mountdata->mnt_path);
|
||||
|
||||
mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, page, mountdata);
|
||||
mnt = vfs_submount(mountdata->dentry, &nfs4_referral_fs_type, page, mountdata);
|
||||
if (!IS_ERR(mnt))
|
||||
break;
|
||||
}
|
||||
|
||||
+10
-3
@@ -470,7 +470,7 @@ struct super_block *sget_userns(struct file_system_type *type,
|
||||
struct super_block *old;
|
||||
int err;
|
||||
|
||||
if (!(flags & MS_KERNMOUNT) &&
|
||||
if (!(flags & (MS_KERNMOUNT|MS_SUBMOUNT)) &&
|
||||
!(type->fs_flags & FS_USERNS_MOUNT) &&
|
||||
!capable(CAP_SYS_ADMIN))
|
||||
return ERR_PTR(-EPERM);
|
||||
@@ -500,7 +500,7 @@ retry:
|
||||
}
|
||||
if (!s) {
|
||||
spin_unlock(&sb_lock);
|
||||
s = alloc_super(type, flags, user_ns);
|
||||
s = alloc_super(type, (flags & ~MS_SUBMOUNT), user_ns);
|
||||
if (!s)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
goto retry;
|
||||
@@ -541,8 +541,15 @@ struct super_block *sget(struct file_system_type *type,
|
||||
{
|
||||
struct user_namespace *user_ns = current_user_ns();
|
||||
|
||||
/* We don't yet pass the user namespace of the parent
|
||||
* mount through to here so always use &init_user_ns
|
||||
* until that changes.
|
||||
*/
|
||||
if (flags & MS_SUBMOUNT)
|
||||
user_ns = &init_user_ns;
|
||||
|
||||
/* Ensure the requestor has permissions over the target filesystem */
|
||||
if (!(flags & MS_KERNMOUNT) && !ns_capable(user_ns, CAP_SYS_ADMIN))
|
||||
if (!(flags & (MS_KERNMOUNT|MS_SUBMOUNT)) && !ns_capable(user_ns, CAP_SYS_ADMIN))
|
||||
return ERR_PTR(-EPERM);
|
||||
|
||||
return sget_userns(type, test, set, flags, user_ns, data);
|
||||
|
||||
@@ -96,9 +96,10 @@ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
|
||||
struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
|
||||
const char *dest);
|
||||
|
||||
typedef struct vfsmount *(*debugfs_automount_t)(struct dentry *, void *);
|
||||
struct dentry *debugfs_create_automount(const char *name,
|
||||
struct dentry *parent,
|
||||
struct vfsmount *(*f)(void *),
|
||||
debugfs_automount_t f,
|
||||
void *data);
|
||||
|
||||
void debugfs_remove(struct dentry *dentry);
|
||||
|
||||
@@ -91,6 +91,9 @@ struct file_system_type;
|
||||
extern struct vfsmount *vfs_kern_mount(struct file_system_type *type,
|
||||
int flags, const char *name,
|
||||
void *data);
|
||||
extern struct vfsmount *vfs_submount(const struct dentry *mountpoint,
|
||||
struct file_system_type *type,
|
||||
const char *name, void *data);
|
||||
|
||||
extern void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list);
|
||||
extern void mark_mounts_for_expiry(struct list_head *mounts);
|
||||
|
||||
@@ -132,6 +132,7 @@ struct inodes_stat_t {
|
||||
#define MS_LAZYTIME (1<<25) /* Update the on-disk [acm]times lazily */
|
||||
|
||||
/* These sb flags are internal to the kernel */
|
||||
#define MS_SUBMOUNT (1<<26)
|
||||
#define MS_NOREMOTELOCK (1<<27)
|
||||
#define MS_NOSEC (1<<28)
|
||||
#define MS_BORN (1<<29)
|
||||
|
||||
@@ -7334,7 +7334,7 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
|
||||
ftrace_init_tracefs(tr, d_tracer);
|
||||
}
|
||||
|
||||
static struct vfsmount *trace_automount(void *ingore)
|
||||
static struct vfsmount *trace_automount(struct dentry *mntpt, void *ingore)
|
||||
{
|
||||
struct vfsmount *mnt;
|
||||
struct file_system_type *type;
|
||||
@@ -7347,7 +7347,7 @@ static struct vfsmount *trace_automount(void *ingore)
|
||||
type = get_fs_type("tracefs");
|
||||
if (!type)
|
||||
return NULL;
|
||||
mnt = vfs_kern_mount(type, 0, "tracefs", NULL);
|
||||
mnt = vfs_submount(mntpt, type, "tracefs", NULL);
|
||||
put_filesystem(type);
|
||||
if (IS_ERR(mnt))
|
||||
return NULL;
|
||||
|
||||
Reference in New Issue
Block a user