Merge tag 'ptrace-cleanups-for-v5.18' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / fs / exec.c
index e23e2d4..e3e55d5 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -117,7 +117,7 @@ bool path_noexec(const struct path *path)
  * Note that a shared library must be both readable and executable due to
  * security reasons.
  *
- * Also note that we take the address to load from from the file itself.
+ * Also note that we take the address to load from the file itself.
  */
 SYSCALL_DEFINE1(uselib, const char __user *, library)
 {
@@ -494,8 +494,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;
@@ -535,7 +541,7 @@ static int copy_strings(int argc, struct user_arg_ptr argv,
                if (!valid_arg_len(bprm, len))
                        goto out;
 
-               /* We're going to work our way backwords. */
+               /* We're going to work our way backwards. */
                pos = bprm->p;
                str += len;
                bprm->p -= len;
@@ -1268,7 +1274,7 @@ int begin_new_exec(struct linux_binprm * bprm)
 
        /*
         * Must be called _before_ exec_mmap() as bprm->mm is
-        * not visibile until then. This also enables the update
+        * not visible until then. This also enables the update
         * to be lockless.
         */
        retval = set_mm_exe_file(bprm->mm, bprm->file);
@@ -1302,12 +1308,6 @@ int begin_new_exec(struct linux_binprm * bprm)
        if (retval)
                goto out_unlock;
 
-       /*
-        * Ensure that the uaccess routines can actually operate on userspace
-        * pointers:
-        */
-       force_uaccess_begin();
-
        if (me->flags & PF_KTHREAD)
                free_kthread_struct(me);
        me->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD |
@@ -1896,6 +1896,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;
@@ -1922,6 +1925,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);
@@ -1950,6 +1966,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;