diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2016-07-23 12:20:44 -0400 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2016-07-23 15:51:26 -0400 |
commit | aeaa4a79ff6a5ed912b7362f206cf8576fca538b (patch) | |
tree | cfdd5207fef5e23cf7dc84691cd3301faa9688ec | |
parent | 81754357770ebd900801231e7bc8d151ddc00498 (diff) |
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: 6e4eab577a0c ("fs: Add user namespace member to struct super_block")
Tested-by: Seth Forshee <seth.forshee@canonical.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
-rw-r--r-- | fs/namei.c | 7 |
1 files changed, 7 insertions, 0 deletions
diff --git a/fs/namei.c b/fs/namei.c index 629823f19a6a..ef573df3297f 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/posix_acl.h> | 36 | #include <linux/posix_acl.h> |
37 | #include <linux/hash.h> | 37 | #include <linux/hash.h> |
38 | #include <linux/bitops.h> | 38 | #include <linux/bitops.h> |
39 | #include <linux/init_task.h> | ||
39 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
40 | 41 | ||
41 | #include "internal.h" | 42 | #include "internal.h" |
@@ -1099,6 +1100,7 @@ static int follow_automount(struct path *path, struct nameidata *nd, | |||
1099 | bool *need_mntput) | 1100 | bool *need_mntput) |
1100 | { | 1101 | { |
1101 | struct vfsmount *mnt; | 1102 | struct vfsmount *mnt; |
1103 | const struct cred *old_cred; | ||
1102 | int err; | 1104 | int err; |
1103 | 1105 | ||
1104 | if (!path->dentry->d_op || !path->dentry->d_op->d_automount) | 1106 | 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 | path->dentry->d_inode) | 1122 | path->dentry->d_inode) |
1121 | return -EISDIR; | 1123 | return -EISDIR; |
1122 | 1124 | ||
1125 | if (path->dentry->d_sb->s_user_ns != &init_user_ns) | ||
1126 | return -EACCES; | ||
1127 | |||
1123 | nd->total_link_count++; | 1128 | nd->total_link_count++; |
1124 | if (nd->total_link_count >= 40) | 1129 | if (nd->total_link_count >= 40) |
1125 | return -ELOOP; | 1130 | return -ELOOP; |
1126 | 1131 | ||
1132 | old_cred = override_creds(&init_cred); | ||
1127 | mnt = path->dentry->d_op->d_automount(path); | 1133 | mnt = path->dentry->d_op->d_automount(path); |
1134 | revert_creds(old_cred); | ||
1128 | if (IS_ERR(mnt)) { | 1135 | if (IS_ERR(mnt)) { |
1129 | /* | 1136 | /* |
1130 | * The filesystem is allowed to return -EISDIR here to indicate | 1137 | * The filesystem is allowed to return -EISDIR here to indicate |