Skip to content

Commit 1a94eba

Browse files
committed
ce_intercept_execve: Don't swap original argv[0] into run_argv
The sudoers policy verifies the command based on the path in the requested argv[0] so we copy the execve path to argv[0] before the policy check. We were swapping the original argv[0] into run_argv[] after the policy check if the command path was unchanged to avoid having to rewrite argv in the process's address space and to avoid issues with login shells where argv[0] starts with a '-'. However, this is unsafe for multi-function binaries like busybox where argv[0] determines the command that is actually run. Reported by Christos Papakonstantinou from Cantina (cantina.xyz)
1 parent f24f72f commit 1a94eba

1 file changed

Lines changed: 21 additions & 10 deletions

File tree

src/exec_ptrace.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1923,6 +1923,10 @@ ptrace_intercept_execve(pid_t pid, struct intercept_closure *closure)
19231923
sudo_warnx("%s", U_(closure->errstr));
19241924
}
19251925

1926+
/* Restore original argv[0] after policy check (if set). */
1927+
if (*orig_argv0 != '\0')
1928+
argv[0] = orig_argv0;
1929+
19261930
switch (closure->state) {
19271931
case POLICY_TEST:
19281932
path_mismatch = true;
@@ -1941,17 +1945,24 @@ ptrace_intercept_execve(pid_t pid, struct intercept_closure *closure)
19411945
*/
19421946
if (strcmp(pathname, closure->command) != 0)
19431947
path_mismatch = true;
1944-
if (!path_mismatch) {
1945-
/* Path unchanged, restore original argv[0]. */
1946-
if (strcmp(argv[0], orig_argv0) != 0) {
1947-
argv[0] = orig_argv0;
1948-
free(closure->run_argv[0]);
1949-
closure->run_argv[0] = strdup(orig_argv0);
1950-
if (closure->run_argv[0] == NULL) {
1951-
sudo_warnx(U_("%s: %s"), __func__,
1952-
U_("unable to allocate memory"));
1953-
}
1948+
if (argv[0][0] != '/' && closure->run_argv[0][0] == '/') {
1949+
/* Original argv was not a path, store basename. */
1950+
const char *base = sudo_basename(closure->run_argv[0]);
1951+
char *run_argv0;
1952+
if (argv[0][0] == '-') {
1953+
/* Special case for login shell, starts with a '-'. */
1954+
if (asprintf(&run_argv0, "-%s", base) == -1)
1955+
run_argv0 = NULL;
1956+
} else {
1957+
run_argv0 = strdup(base);
1958+
}
1959+
if (run_argv0 == NULL) {
1960+
sudo_warnx(U_("%s: %s"), __func__,
1961+
U_("unable to allocate memory"));
1962+
goto done;
19541963
}
1964+
free(closure->run_argv[0]);
1965+
closure->run_argv[0] = run_argv0;
19551966
}
19561967
for (i = 0; closure->run_argv[i] != NULL && argv[i] != NULL; i++) {
19571968
if (strcmp(closure->run_argv[i], argv[i]) != 0) {

0 commit comments

Comments
 (0)