@@ -495,8 +495,14 @@ static int bprm_stack_limits(struct linux_binprm *bprm)
495495 * the stack. They aren't stored until much later when we can't
496496 * signal to the parent that the child has run out of stack space.
497497 * Instead, calculate it here so it's possible to fail gracefully.
498+ *
499+ * In the case of argc = 0, make sure there is space for adding a
500+ * empty string (which will bump argc to 1), to ensure confused
501+ * userspace programs don't start processing from argv[1], thinking
502+ * argc can never be 0, to keep them from walking envp by accident.
503+ * See do_execveat_common().
498504 */
499- ptr_size = (bprm -> argc + bprm -> envc ) * sizeof (void * );
505+ ptr_size = (max ( bprm -> argc , 1 ) + bprm -> envc ) * sizeof (void * );
500506 if (limit <= ptr_size )
501507 return - E2BIG ;
502508 limit -= ptr_size ;
@@ -1897,6 +1903,9 @@ static int do_execveat_common(int fd, struct filename *filename,
18971903 }
18981904
18991905 retval = count (argv , MAX_ARG_STRINGS );
1906+ if (retval == 0 )
1907+ pr_warn_once ("process '%s' launched '%s' with NULL argv: empty string added\n" ,
1908+ current -> comm , bprm -> filename );
19001909 if (retval < 0 )
19011910 goto out_free ;
19021911 bprm -> argc = retval ;
@@ -1923,6 +1932,19 @@ static int do_execveat_common(int fd, struct filename *filename,
19231932 if (retval < 0 )
19241933 goto out_free ;
19251934
1935+ /*
1936+ * When argv is empty, add an empty string ("") as argv[0] to
1937+ * ensure confused userspace programs that start processing
1938+ * from argv[1] won't end up walking envp. See also
1939+ * bprm_stack_limits().
1940+ */
1941+ if (bprm -> argc == 0 ) {
1942+ retval = copy_string_kernel ("" , bprm );
1943+ if (retval < 0 )
1944+ goto out_free ;
1945+ bprm -> argc = 1 ;
1946+ }
1947+
19261948 retval = bprm_execve (bprm , fd , filename , flags );
19271949out_free :
19281950 free_bprm (bprm );
@@ -1951,6 +1973,8 @@ int kernel_execve(const char *kernel_filename,
19511973 }
19521974
19531975 retval = count_strings_kernel (argv );
1976+ if (WARN_ON_ONCE (retval == 0 ))
1977+ retval = - EINVAL ;
19541978 if (retval < 0 )
19551979 goto out_free ;
19561980 bprm -> argc = retval ;
0 commit comments