Commit aeaa4a79 authored by Eric W. Biederman's avatar Eric W. Biederman

fs: Call d_automount with the filesystems creds

Seth Forshee reported a mount regression in nfs autmounts
with "fs: Add user namespace member to struct super_block".

It turns out that the assumption that current->cred is something
reasonable during mount while necessary to improve support of
unprivileged mounts is wrong in the automount path.

To fix the existing filesystems override current->cred with the
init_cred before calling d_automount and restore current->cred after
d_automount completes.

To support unprivileged mounts would require a more nuanced cred
selection, so fail on unprivileged mounts for the time being.  As none
of the filesystems that currently set FS_USERNS_MOUNT implement
d_automount this check is only good for preventing future problems.

Fixes: 6e4eab57 ("fs: Add user namespace member to struct super_block")
Tested-by: default avatarSeth Forshee <seth.forshee@canonical.com>
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parent 81754357
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/posix_acl.h> #include <linux/posix_acl.h>
#include <linux/hash.h> #include <linux/hash.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/init_task.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "internal.h" #include "internal.h"
...@@ -1099,6 +1100,7 @@ static int follow_automount(struct path *path, struct nameidata *nd, ...@@ -1099,6 +1100,7 @@ static int follow_automount(struct path *path, struct nameidata *nd,
bool *need_mntput) bool *need_mntput)
{ {
struct vfsmount *mnt; struct vfsmount *mnt;
const struct cred *old_cred;
int err; int err;
if (!path->dentry->d_op || !path->dentry->d_op->d_automount) if (!path->dentry->d_op || !path->dentry->d_op->d_automount)
...@@ -1120,11 +1122,16 @@ static int follow_automount(struct path *path, struct nameidata *nd, ...@@ -1120,11 +1122,16 @@ static int follow_automount(struct path *path, struct nameidata *nd,
path->dentry->d_inode) path->dentry->d_inode)
return -EISDIR; return -EISDIR;
if (path->dentry->d_sb->s_user_ns != &init_user_ns)
return -EACCES;
nd->total_link_count++; nd->total_link_count++;
if (nd->total_link_count >= 40) if (nd->total_link_count >= 40)
return -ELOOP; return -ELOOP;
old_cred = override_creds(&init_cred);
mnt = path->dentry->d_op->d_automount(path); mnt = path->dentry->d_op->d_automount(path);
revert_creds(old_cred);
if (IS_ERR(mnt)) { if (IS_ERR(mnt)) {
/* /*
* The filesystem is allowed to return -EISDIR here to indicate * The filesystem is allowed to return -EISDIR here to indicate
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment