Skip to content

Commit 0c9cdff

Browse files
committed
exec: Factor bprm_execve out of do_execve_common
Currently it is necessary for the usermode helper code and the code that launches init to use set_fs so that pages coming from the kernel look like they are coming from userspace. To allow that usage of set_fs to be removed cleanly the argument copying from userspace needs to happen earlier. Factor bprm_execve out of do_execve_common to separate out the copying of arguments to the newe stack, and the rest of exec. In separating bprm_execve from do_execve_common the copying of the arguments onto the new stack happens earlier. As the copying of the arguments does not depend any security hooks, files, the file table, current->in_execve, current->fs->in_exec, bprm->unsafe, or creds this is safe. Likewise the security hook security_creds_for_exec does not depend upon preventing the argument copying from happening. In addition to making it possible to implement kernel_execve that performs the copying differently, this separation of bprm_execve from do_execve_common makes for a nice separation of responsibilities making the exec code easier to navigate. Reviewed-by: Kees Cook <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: "Eric W. Biederman" <[email protected]>
1 parent f18ac55 commit 0c9cdff

File tree

1 file changed

+58
-50
lines changed

1 file changed

+58
-50
lines changed

fs/exec.c

Lines changed: 58 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,44 +1856,16 @@ static int exec_binprm(struct linux_binprm *bprm)
18561856
/*
18571857
* sys_execve() executes a new program.
18581858
*/
1859-
static int do_execveat_common(int fd, struct filename *filename,
1860-
struct user_arg_ptr argv,
1861-
struct user_arg_ptr envp,
1862-
int flags)
1859+
static int bprm_execve(struct linux_binprm *bprm,
1860+
int fd, struct filename *filename, int flags)
18631861
{
1864-
struct linux_binprm *bprm;
18651862
struct file *file;
18661863
struct files_struct *displaced;
18671864
int retval;
18681865

1869-
if (IS_ERR(filename))
1870-
return PTR_ERR(filename);
1871-
1872-
/*
1873-
* We move the actual failure in case of RLIMIT_NPROC excess from
1874-
* set*uid() to execve() because too many poorly written programs
1875-
* don't check setuid() return code. Here we additionally recheck
1876-
* whether NPROC limit is still exceeded.
1877-
*/
1878-
if ((current->flags & PF_NPROC_EXCEEDED) &&
1879-
atomic_read(&current_user()->processes) > rlimit(RLIMIT_NPROC)) {
1880-
retval = -EAGAIN;
1881-
goto out_ret;
1882-
}
1883-
1884-
/* We're below the limit (still or again), so we don't want to make
1885-
* further execve() calls fail. */
1886-
current->flags &= ~PF_NPROC_EXCEEDED;
1887-
1888-
bprm = alloc_bprm(fd, filename);
1889-
if (IS_ERR(bprm)) {
1890-
retval = PTR_ERR(bprm);
1891-
goto out_ret;
1892-
}
1893-
18941866
retval = unshare_files(&displaced);
18951867
if (retval)
1896-
goto out_free;
1868+
return retval;
18971869

18981870
retval = prepare_bprm_creds(bprm);
18991871
if (retval)
@@ -1919,28 +1891,11 @@ static int do_execveat_common(int fd, struct filename *filename,
19191891
close_on_exec(fd, rcu_dereference_raw(current->files->fdt)))
19201892
bprm->interp_flags |= BINPRM_FLAGS_PATH_INACCESSIBLE;
19211893

1922-
retval = prepare_arg_pages(bprm, argv, envp);
1923-
if (retval < 0)
1924-
goto out;
1925-
19261894
/* Set the unchanging part of bprm->cred */
19271895
retval = security_bprm_creds_for_exec(bprm);
19281896
if (retval)
19291897
goto out;
19301898

1931-
retval = copy_string_kernel(bprm->filename, bprm);
1932-
if (retval < 0)
1933-
goto out;
1934-
1935-
bprm->exec = bprm->p;
1936-
retval = copy_strings(bprm->envc, envp, bprm);
1937-
if (retval < 0)
1938-
goto out;
1939-
1940-
retval = copy_strings(bprm->argc, argv, bprm);
1941-
if (retval < 0)
1942-
goto out;
1943-
19441899
retval = exec_binprm(bprm);
19451900
if (retval < 0)
19461901
goto out;
@@ -1951,8 +1906,6 @@ static int do_execveat_common(int fd, struct filename *filename,
19511906
rseq_execve(current);
19521907
acct_update_integrals(current);
19531908
task_numa_free(current, false);
1954-
free_bprm(bprm);
1955-
putname(filename);
19561909
if (displaced)
19571910
put_files_struct(displaced);
19581911
return retval;
@@ -1974,6 +1927,61 @@ static int do_execveat_common(int fd, struct filename *filename,
19741927
out_files:
19751928
if (displaced)
19761929
reset_files_struct(displaced);
1930+
1931+
return retval;
1932+
}
1933+
1934+
static int do_execveat_common(int fd, struct filename *filename,
1935+
struct user_arg_ptr argv,
1936+
struct user_arg_ptr envp,
1937+
int flags)
1938+
{
1939+
struct linux_binprm *bprm;
1940+
int retval;
1941+
1942+
if (IS_ERR(filename))
1943+
return PTR_ERR(filename);
1944+
1945+
/*
1946+
* We move the actual failure in case of RLIMIT_NPROC excess from
1947+
* set*uid() to execve() because too many poorly written programs
1948+
* don't check setuid() return code. Here we additionally recheck
1949+
* whether NPROC limit is still exceeded.
1950+
*/
1951+
if ((current->flags & PF_NPROC_EXCEEDED) &&
1952+
atomic_read(&current_user()->processes) > rlimit(RLIMIT_NPROC)) {
1953+
retval = -EAGAIN;
1954+
goto out_ret;
1955+
}
1956+
1957+
/* We're below the limit (still or again), so we don't want to make
1958+
* further execve() calls fail. */
1959+
current->flags &= ~PF_NPROC_EXCEEDED;
1960+
1961+
bprm = alloc_bprm(fd, filename);
1962+
if (IS_ERR(bprm)) {
1963+
retval = PTR_ERR(bprm);
1964+
goto out_ret;
1965+
}
1966+
1967+
retval = prepare_arg_pages(bprm, argv, envp);
1968+
if (retval < 0)
1969+
goto out_free;
1970+
1971+
retval = copy_string_kernel(bprm->filename, bprm);
1972+
if (retval < 0)
1973+
goto out_free;
1974+
bprm->exec = bprm->p;
1975+
1976+
retval = copy_strings(bprm->envc, envp, bprm);
1977+
if (retval < 0)
1978+
goto out_free;
1979+
1980+
retval = copy_strings(bprm->argc, argv, bprm);
1981+
if (retval < 0)
1982+
goto out_free;
1983+
1984+
retval = bprm_execve(bprm, fd, filename, flags);
19771985
out_free:
19781986
free_bprm(bprm);
19791987

0 commit comments

Comments
 (0)