]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - fs/exec.c
fuse: add file_modified() to fallocate
[mirror_ubuntu-jammy-kernel.git] / fs / exec.c
index a098c133d8d74039e46256ac365883148911b9ae..4b54b0f59dc70601df0fbc79a32e4a54042cc3ae 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -111,6 +111,7 @@ bool path_noexec(const struct path *path)
        return (path->mnt->mnt_flags & MNT_NOEXEC) ||
               (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC);
 }
+EXPORT_SYMBOL_GPL(path_noexec);
 
 #ifdef CONFIG_USELIB
 /*
@@ -494,8 +495,14 @@ static int bprm_stack_limits(struct linux_binprm *bprm)
         * the stack. They aren't stored until much later when we can't
         * signal to the parent that the child has run out of stack space.
         * Instead, calculate it here so it's possible to fail gracefully.
+        *
+        * In the case of argc = 0, make sure there is space for adding a
+        * empty string (which will bump argc to 1), to ensure confused
+        * userspace programs don't start processing from argv[1], thinking
+        * argc can never be 0, to keep them from walking envp by accident.
+        * See do_execveat_common().
         */
-       ptr_size = (bprm->argc + bprm->envc) * sizeof(void *);
+       ptr_size = (max(bprm->argc, 1) + bprm->envc) * sizeof(void *);
        if (limit <= ptr_size)
                return -E2BIG;
        limit -= ptr_size;
@@ -1192,11 +1199,11 @@ static int unshare_sighand(struct task_struct *me)
                        return -ENOMEM;
 
                refcount_set(&newsighand->count, 1);
-               memcpy(newsighand->action, oldsighand->action,
-                      sizeof(newsighand->action));
 
                write_lock_irq(&tasklist_lock);
                spin_lock(&oldsighand->siglock);
+               memcpy(newsighand->action, oldsighand->action,
+                      sizeof(newsighand->action));
                rcu_assign_pointer(me->sighand, newsighand);
                spin_unlock(&oldsighand->siglock);
                write_unlock_irq(&tasklist_lock);
@@ -1292,7 +1299,10 @@ int begin_new_exec(struct linux_binprm * bprm)
        bprm->mm = NULL;
 
 #ifdef CONFIG_POSIX_TIMERS
-       exit_itimers(me->signal);
+       spin_lock_irq(&me->sighand->siglock);
+       posix_cpu_timers_exit(me);
+       spin_unlock_irq(&me->sighand->siglock);
+       exit_itimers(me);
        flush_itimer_signals();
 #endif
 
@@ -1852,7 +1862,7 @@ out:
         * SIGSEGV.
         */
        if (bprm->point_of_no_return && !fatal_signal_pending(current))
-               force_sigsegv(SIGSEGV);
+               force_fatal_sig(SIGSEGV);
 
 out_unmark:
        current->fs->in_exec = 0;
@@ -1895,6 +1905,9 @@ static int do_execveat_common(int fd, struct filename *filename,
        }
 
        retval = count(argv, MAX_ARG_STRINGS);
+       if (retval == 0)
+               pr_warn_once("process '%s' launched '%s' with NULL argv: empty string added\n",
+                            current->comm, bprm->filename);
        if (retval < 0)
                goto out_free;
        bprm->argc = retval;
@@ -1921,6 +1934,19 @@ static int do_execveat_common(int fd, struct filename *filename,
        if (retval < 0)
                goto out_free;
 
+       /*
+        * When argv is empty, add an empty string ("") as argv[0] to
+        * ensure confused userspace programs that start processing
+        * from argv[1] won't end up walking envp. See also
+        * bprm_stack_limits().
+        */
+       if (bprm->argc == 0) {
+               retval = copy_string_kernel("", bprm);
+               if (retval < 0)
+                       goto out_free;
+               bprm->argc = 1;
+       }
+
        retval = bprm_execve(bprm, fd, filename, flags);
 out_free:
        free_bprm(bprm);
@@ -1949,6 +1975,8 @@ int kernel_execve(const char *kernel_filename,
        }
 
        retval = count_strings_kernel(argv);
+       if (WARN_ON_ONCE(retval == 0))
+               retval = -EINVAL;
        if (retval < 0)
                goto out_free;
        bprm->argc = retval;