]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/exec.c
drm/nouveau/clock: fix support for more than 2 monitors on nve0
[karo-tx-linux.git] / fs / exec.c
index 0039055b1fc6533c636ca98dd2b9ad73b52d5de6..18c45cac368fe3ec830c7f0c8433e5cd2db0fc2d 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1175,9 +1175,24 @@ void free_bprm(struct linux_binprm *bprm)
                mutex_unlock(&current->signal->cred_guard_mutex);
                abort_creds(bprm->cred);
        }
+       /* If a binfmt changed the interp, free it. */
+       if (bprm->interp != bprm->filename)
+               kfree(bprm->interp);
        kfree(bprm);
 }
 
+int bprm_change_interp(char *interp, struct linux_binprm *bprm)
+{
+       /* If a binfmt changed the interp, free it first. */
+       if (bprm->interp != bprm->filename)
+               kfree(bprm->interp);
+       bprm->interp = kstrdup(interp, GFP_KERNEL);
+       if (!bprm->interp)
+               return -ENOMEM;
+       return 0;
+}
+EXPORT_SYMBOL(bprm_change_interp);
+
 /*
  * install the new credentials for this executable
  */
@@ -1266,14 +1281,13 @@ int prepare_binprm(struct linux_binprm *bprm)
        bprm->cred->egid = current_egid();
 
        if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) &&
-           !current->no_new_privs) {
+           !current->no_new_privs &&
+           kuid_has_mapping(bprm->cred->user_ns, inode->i_uid) &&
+           kgid_has_mapping(bprm->cred->user_ns, inode->i_gid)) {
                /* Set-uid? */
                if (mode & S_ISUID) {
-                       if (!kuid_has_mapping(bprm->cred->user_ns, inode->i_uid))
-                               return -EPERM;
                        bprm->per_clear |= PER_CLEAR_ON_SETID;
                        bprm->cred->euid = inode->i_uid;
-
                }
 
                /* Set-gid? */
@@ -1283,8 +1297,6 @@ int prepare_binprm(struct linux_binprm *bprm)
                 * executable.
                 */
                if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
-                       if (!kgid_has_mapping(bprm->cred->user_ns, inode->i_gid))
-                               return -EPERM;
                        bprm->per_clear |= PER_CLEAR_ON_SETID;
                        bprm->cred->egid = inode->i_gid;
                }
@@ -1349,13 +1361,17 @@ EXPORT_SYMBOL(remove_arg_zero);
 /*
  * cycle the list of binary formats handler, until one recognizes the image
  */
-int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
+int search_binary_handler(struct linux_binprm *bprm)
 {
        unsigned int depth = bprm->recursion_depth;
        int try,retval;
        struct linux_binfmt *fmt;
        pid_t old_pid, old_vpid;
 
+       /* This allows 4 levels of binfmt rewrites before failing hard. */
+       if (depth > 5)
+               return -ELOOP;
+
        retval = security_bprm_check(bprm);
        if (retval)
                return retval;
@@ -1374,18 +1390,14 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
        for (try=0; try<2; try++) {
                read_lock(&binfmt_lock);
                list_for_each_entry(fmt, &formats, lh) {
-                       int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary;
+                       int (*fn)(struct linux_binprm *) = fmt->load_binary;
                        if (!fn)
                                continue;
                        if (!try_module_get(fmt->module))
                                continue;
                        read_unlock(&binfmt_lock);
-                       retval = fn(bprm, regs);
-                       /*
-                        * Restore the depth counter to its starting value
-                        * in this call, so we don't have to rely on every
-                        * load_binary function to restore it on return.
-                        */
+                       bprm->recursion_depth = depth + 1;
+                       retval = fn(bprm);
                        bprm->recursion_depth = depth;
                        if (retval >= 0) {
                                if (depth == 0) {
@@ -1439,8 +1451,7 @@ EXPORT_SYMBOL(search_binary_handler);
  */
 static int do_execve_common(const char *filename,
                                struct user_arg_ptr argv,
-                               struct user_arg_ptr envp,
-                               struct pt_regs *regs)
+                               struct user_arg_ptr envp)
 {
        struct linux_binprm *bprm;
        struct file *file;
@@ -1524,7 +1535,7 @@ static int do_execve_common(const char *filename,
        if (retval < 0)
                goto out;
 
-       retval = search_binary_handler(bprm,regs);
+       retval = search_binary_handler(bprm);
        if (retval < 0)
                goto out;
 
@@ -1566,19 +1577,17 @@ out_ret:
 
 int do_execve(const char *filename,
        const char __user *const __user *__argv,
-       const char __user *const __user *__envp,
-       struct pt_regs *regs)
+       const char __user *const __user *__envp)
 {
        struct user_arg_ptr argv = { .ptr.native = __argv };
        struct user_arg_ptr envp = { .ptr.native = __envp };
-       return do_execve_common(filename, argv, envp, regs);
+       return do_execve_common(filename, argv, envp);
 }
 
 #ifdef CONFIG_COMPAT
-int compat_do_execve(const char *filename,
+static int compat_do_execve(const char *filename,
        const compat_uptr_t __user *__argv,
-       const compat_uptr_t __user *__envp,
-       struct pt_regs *regs)
+       const compat_uptr_t __user *__envp)
 {
        struct user_arg_ptr argv = {
                .is_compat = true,
@@ -1588,7 +1597,7 @@ int compat_do_execve(const char *filename,
                .is_compat = true,
                .ptr.compat = __envp,
        };
-       return do_execve_common(filename, argv, envp, regs);
+       return do_execve_common(filename, argv, envp);
 }
 #endif
 
@@ -1660,7 +1669,6 @@ int get_dumpable(struct mm_struct *mm)
        return __get_dumpable(mm->flags);
 }
 
-#ifdef __ARCH_WANT_SYS_EXECVE
 SYSCALL_DEFINE3(execve,
                const char __user *, filename,
                const char __user *const __user *, argv,
@@ -1669,7 +1677,7 @@ SYSCALL_DEFINE3(execve,
        struct filename *path = getname(filename);
        int error = PTR_ERR(path);
        if (!IS_ERR(path)) {
-               error = do_execve(path->name, argv, envp, current_pt_regs());
+               error = do_execve(path->name, argv, envp);
                putname(path);
        }
        return error;
@@ -1682,33 +1690,9 @@ asmlinkage long compat_sys_execve(const char __user * filename,
        struct filename *path = getname(filename);
        int error = PTR_ERR(path);
        if (!IS_ERR(path)) {
-               error = compat_do_execve(path->name, argv, envp,
-                                                       current_pt_regs());
+               error = compat_do_execve(path->name, argv, envp);
                putname(path);
        }
        return error;
 }
 #endif
-#endif
-
-#ifdef __ARCH_WANT_KERNEL_EXECVE
-int kernel_execve(const char *filename,
-                 const char *const argv[],
-                 const char *const envp[])
-{
-       struct pt_regs *p = current_pt_regs();
-       int ret;
-
-       ret = do_execve(filename,
-                       (const char __user *const __user *)argv,
-                       (const char __user *const __user *)envp, p);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * We were successful.  We won't be returning to our caller, but
-        * instead to user space by manipulating the kernel stack.
-        */
-       ret_from_kernel_execve(p);
-}
-#endif