aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@amacapital.net>2016-06-23 17:41:05 -0400
committerEric W. Biederman <ebiederm@xmission.com>2016-06-24 11:40:41 -0400
commit380cf5ba6b0a0b307f4afb62b186ca801defb203 (patch)
treee5c5c1d0f2f87cc6eafb17d1d35c14c664e47d98
parentd07b846f6200454c50d791796edb82660192513d (diff)
fs: Treat foreign mounts as nosuid
If a process gets access to a mount from a different user namespace, that process should not be able to take advantage of setuid files or selinux entrypoints from that filesystem. Prevent this by treating mounts from other mount namespaces and those not owned by current_user_ns() or an ancestor as nosuid. This will make it safer to allow more complex filesystems to be mounted in non-root user namespaces. This does not remove the need for MNT_LOCK_NOSUID. The setuid, setgid, and file capability bits can no longer be abused if code in a user namespace were to clear nosuid on an untrusted filesystem, but this patch, by itself, is insufficient to protect the system from abuse of files that, when execed, would increase MAC privilege. As a more concrete explanation, any task that can manipulate a vfsmount associated with a given user namespace already has capabilities in that namespace and all of its descendents. If they can cause a malicious setuid, setgid, or file-caps executable to appear in that mount, then that executable will only allow them to elevate privileges in exactly the set of namespaces in which they are already privileges. On the other hand, if they can cause a malicious executable to appear with a dangerous MAC label, running it could change the caller's security context in a way that should not have been possible, even inside the namespace in which the task is confined. As a hardening measure, this would have made CVE-2014-5207 much more difficult to exploit. Signed-off-by: Andy Lutomirski <luto@amacapital.net> Signed-off-by: Seth Forshee <seth.forshee@canonical.com> Acked-by: James Morris <james.l.morris@oracle.com> Acked-by: Serge Hallyn <serge.hallyn@canonical.com> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
-rw-r--r--fs/exec.c2
-rw-r--r--fs/namespace.c13
-rw-r--r--include/linux/mount.h1
-rw-r--r--security/commoncap.c8
-rw-r--r--security/selinux/hooks.c2
5 files changed, 23 insertions, 3 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 887c1c955df8..ca239fc86d8d 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1411,7 +1411,7 @@ static void bprm_fill_uid(struct linux_binprm *bprm)
1411 bprm->cred->euid = current_euid(); 1411 bprm->cred->euid = current_euid();
1412 bprm->cred->egid = current_egid(); 1412 bprm->cred->egid = current_egid();
1413 1413
1414 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) 1414 if (!mnt_may_suid(bprm->file->f_path.mnt))
1415 return; 1415 return;
1416 1416
1417 if (task_no_new_privs(current)) 1417 if (task_no_new_privs(current))
diff --git a/fs/namespace.c b/fs/namespace.c
index 9786a38d1681..aabe8e397fc3 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -3280,6 +3280,19 @@ static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags)
3280 return !mnt_already_visible(ns, mnt, new_mnt_flags); 3280 return !mnt_already_visible(ns, mnt, new_mnt_flags);
3281} 3281}
3282 3282
3283bool mnt_may_suid(struct vfsmount *mnt)
3284{
3285 /*
3286 * Foreign mounts (accessed via fchdir or through /proc
3287 * symlinks) are always treated as if they are nosuid. This
3288 * prevents namespaces from trusting potentially unsafe
3289 * suid/sgid bits, file caps, or security labels that originate
3290 * in other namespaces.
3291 */
3292 return !(mnt->mnt_flags & MNT_NOSUID) && check_mnt(real_mount(mnt)) &&
3293 current_in_userns(mnt->mnt_sb->s_user_ns);
3294}
3295
3283static struct ns_common *mntns_get(struct task_struct *task) 3296static struct ns_common *mntns_get(struct task_struct *task)
3284{ 3297{
3285 struct ns_common *ns = NULL; 3298 struct ns_common *ns = NULL;
diff --git a/include/linux/mount.h b/include/linux/mount.h
index f822c3c11377..54a594d49733 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -81,6 +81,7 @@ extern void mntput(struct vfsmount *mnt);
81extern struct vfsmount *mntget(struct vfsmount *mnt); 81extern struct vfsmount *mntget(struct vfsmount *mnt);
82extern struct vfsmount *mnt_clone_internal(struct path *path); 82extern struct vfsmount *mnt_clone_internal(struct path *path);
83extern int __mnt_is_readonly(struct vfsmount *mnt); 83extern int __mnt_is_readonly(struct vfsmount *mnt);
84extern bool mnt_may_suid(struct vfsmount *mnt);
84 85
85struct path; 86struct path;
86extern struct vfsmount *clone_private_mount(struct path *path); 87extern struct vfsmount *clone_private_mount(struct path *path);
diff --git a/security/commoncap.c b/security/commoncap.c
index e109e6dac858..14540bd78561 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -453,8 +453,14 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c
453 if (!file_caps_enabled) 453 if (!file_caps_enabled)
454 return 0; 454 return 0;
455 455
456 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) 456 if (!mnt_may_suid(bprm->file->f_path.mnt))
457 return 0; 457 return 0;
458
459 /*
460 * This check is redundant with mnt_may_suid() but is kept to make
461 * explicit that capability bits are limited to s_user_ns and its
462 * descendants.
463 */
458 if (!current_in_userns(bprm->file->f_path.mnt->mnt_sb->s_user_ns)) 464 if (!current_in_userns(bprm->file->f_path.mnt->mnt_sb->s_user_ns))
459 return 0; 465 return 0;
460 466
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index a86d537eb79b..15541756eb07 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2259,7 +2259,7 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
2259 const struct task_security_struct *new_tsec) 2259 const struct task_security_struct *new_tsec)
2260{ 2260{
2261 int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS); 2261 int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS);
2262 int nosuid = (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID); 2262 int nosuid = !mnt_may_suid(bprm->file->f_path.mnt);
2263 int rc; 2263 int rc;
2264 2264
2265 if (!nnp && !nosuid) 2265 if (!nnp && !nosuid)