Revert "Revert "exec: Ensure mm->user_ns contains the execed files"" 70/209270/2 accepted/tizen/unified/20190705.110605 submit/tizen/20190705.061120
authorSeung-Woo Kim <sw0312.kim@samsung.com>
Thu, 4 Jul 2019 07:43:42 +0000 (16:43 +0900)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Thu, 4 Jul 2019 07:43:42 +0000 (16:43 +0900)
This reverts commit bbfdec4e6db8c7d95cb5a370f393ad872bbd608a.

The last backport calls improperly would_dump() after calling
exec_binprm() and it causes NULL pointer deference. Fix the issue
by moving would_dump() to proper position.

Change-Id: Ia957cda5d4126675ea18fc095e273f43d2f5dcd5
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
fs/exec.c
include/linux/capability.h
kernel/capability.c

index 6caf829..b69705a 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -56,6 +56,7 @@
 #include <linux/pipe_fs_i.h>
 #include <linux/oom.h>
 #include <linux/compat.h>
+#include <linux/user_namespace.h>
 #include <swap/swap_us_hooks.h>
 
 #include <asm/uaccess.h>
@@ -1092,8 +1093,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);
 
@@ -1123,7 +1138,6 @@ void setup_new_exec(struct linux_binprm * bprm)
            !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);
        }
@@ -1533,6 +1547,8 @@ static int do_execve_common(struct filename *filename,
        if (retval < 0)
                goto out;
 
+       would_dump(bprm, bprm->file);
+
        retval = exec_binprm(bprm);
        if (retval < 0)
                goto out;
index aa93e5e..135d0a4 100644 (file)
@@ -213,6 +213,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t,
                                      struct user_namespace *ns, int cap);
 extern bool capable(int cap);
 extern bool ns_capable(struct user_namespace *ns, int cap);
+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);
 
index 989f5bf..c8b7489 100644 (file)
@@ -428,6 +428,19 @@ bool capable(int cap)
 EXPORT_SYMBOL(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
@@ -440,7 +453,6 @@ bool capable_wrt_inode_uidgid(const struct inode *inode, int cap)
 {
        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);