+++ /dev/null
-From f84df2a6f268de584a201e8911384a2d244876e3 Mon Sep 17 00:00:00 2001
-From: "Eric W. Biederman" <ebiederm@xmission.com>
-Date: Wed, 16 Nov 2016 22:06:51 -0600
-Subject: exec: Ensure mm->user_ns contains the execed files
-
-From: Eric W. Biederman <ebiederm@xmission.com>
-
-commit f84df2a6f268de584a201e8911384a2d244876e3 upstream.
-
-When the user namespace support was merged the need to prevent
-ptrace from revealing the contents of an unreadable executable
-was overlooked.
-
-Correct this oversight by ensuring that the executed file
-or files are in mm->user_ns, by adjusting mm->user_ns.
-
-Use the new function privileged_wrt_inode_uidgid to see if
-the executable is a member of the user namespace, and as such
-if having CAP_SYS_PTRACE in the user namespace should allow
-tracing the executable. If not update mm->user_ns to
-the parent user namespace until an appropriate parent is found.
-
-Reported-by: Jann Horn <jann@thejh.net>
-Fixes: 9e4a36ece652 ("userns: Fail exec for suid and sgid binaries with ids outside our user namespace.")
-Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- fs/exec.c | 19 +++++++++++++++++--
- include/linux/capability.h | 1 +
- kernel/capability.c | 16 ++++++++++++++--
- 3 files changed, 32 insertions(+), 4 deletions(-)
-
---- a/fs/exec.c
-+++ b/fs/exec.c
-@@ -1123,8 +1123,22 @@ EXPORT_SYMBOL(flush_old_exec);
-
- void would_dump(struct linux_binprm *bprm, struct file *file)
- {
-- if (inode_permission(file_inode(file), MAY_READ) < 0)
-+ struct inode *inode = file_inode(file);
-+ if (inode_permission(inode, MAY_READ) < 0) {
-+ struct user_namespace *old, *user_ns;
- bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
-+
-+ /* Ensure mm->user_ns contains the executable */
-+ user_ns = old = bprm->mm->user_ns;
-+ while ((user_ns != &init_user_ns) &&
-+ !privileged_wrt_inode_uidgid(user_ns, inode))
-+ user_ns = user_ns->parent;
-+
-+ if (old != user_ns) {
-+ bprm->mm->user_ns = get_user_ns(user_ns);
-+ put_user_ns(old);
-+ }
-+ }
- }
- EXPORT_SYMBOL(would_dump);
-
-@@ -1154,7 +1168,6 @@ void setup_new_exec(struct linux_binprm
- !gid_eq(bprm->cred->gid, current_egid())) {
- current->pdeath_signal = 0;
- } else {
-- would_dump(bprm, bprm->file);
- if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)
- set_dumpable(current->mm, suid_dumpable);
- }
-@@ -1587,6 +1600,8 @@ static int do_execveat_common(int fd, st
- if (retval < 0)
- goto out;
-
-+ would_dump(bprm, bprm->file);
-+
- retval = exec_binprm(bprm);
- if (retval < 0)
- goto out;
---- a/include/linux/capability.h
-+++ b/include/linux/capability.h
-@@ -247,6 +247,7 @@ static inline bool ns_capable_noaudit(st
- return true;
- }
- #endif /* CONFIG_MULTIUSER */
-+extern bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct inode *inode);
- extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap);
- extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap);
-
---- a/kernel/capability.c
-+++ b/kernel/capability.c
-@@ -457,6 +457,19 @@ bool file_ns_capable(const struct file *
- EXPORT_SYMBOL(file_ns_capable);
-
- /**
-+ * privileged_wrt_inode_uidgid - Do capabilities in the namespace work over the inode?
-+ * @ns: The user namespace in question
-+ * @inode: The inode in question
-+ *
-+ * Return true if the inode uid and gid are within the namespace.
-+ */
-+bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct inode *inode)
-+{
-+ return kuid_has_mapping(ns, inode->i_uid) &&
-+ kgid_has_mapping(ns, inode->i_gid);
-+}
-+
-+/**
- * capable_wrt_inode_uidgid - Check nsown_capable and uid and gid mapped
- * @inode: The inode in question
- * @cap: The capability in question
-@@ -469,7 +482,6 @@ bool capable_wrt_inode_uidgid(const stru
- {
- struct user_namespace *ns = current_user_ns();
-
-- return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid) &&
-- kgid_has_mapping(ns, inode->i_gid);
-+ return ns_capable(ns, cap) && privileged_wrt_inode_uidgid(ns, inode);
- }
- EXPORT_SYMBOL(capable_wrt_inode_uidgid);
--- a/fs/exec.c
+++ b/fs/exec.c
-@@ -1273,7 +1273,7 @@ static void check_unsafe_exec(struct lin
+@@ -1254,7 +1254,7 @@ static void check_unsafe_exec(struct lin
unsigned n_fs;
if (p->ptrace) {
bprm->unsafe |= LSM_UNSAFE_PTRACE;
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
-@@ -250,6 +250,7 @@ static inline bool ns_capable_noaudit(st
- extern bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct inode *inode);
+@@ -249,6 +249,7 @@ static inline bool ns_capable_noaudit(st
+ #endif /* CONFIG_MULTIUSER */
extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap);
extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap);
+extern bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns);
const struct cred __rcu *cred; /* effective (overridable) subjective task
--- a/kernel/capability.c
+++ b/kernel/capability.c
-@@ -485,3 +485,23 @@ bool capable_wrt_inode_uidgid(const stru
- return ns_capable(ns, cap) && privileged_wrt_inode_uidgid(ns, inode);
+@@ -473,3 +473,23 @@ bool capable_wrt_inode_uidgid(const stru
+ kgid_has_mapping(ns, inode->i_gid);
}
EXPORT_SYMBOL(capable_wrt_inode_uidgid);
+