ptrace_intercept_execve: read back the updated syscall args in test mode.
This makes it easier to detect problems with the syscall rewrite code when testing with test_ptrace.
This commit is contained in:
@@ -661,7 +661,7 @@ get_execve_info(pid_t pid, struct sudo_ptrace_regs *regs, char **pathname_out,
|
||||
strtab += len;
|
||||
bufsize -= len;
|
||||
|
||||
sudo_debug_execve(SUDO_DEBUG_INFO, pathname, argv, envp);
|
||||
sudo_debug_execve(SUDO_DEBUG_DIAG, pathname, argv, envp);
|
||||
|
||||
*pathname_out = pathname;
|
||||
*argc_out = argc;
|
||||
@@ -803,7 +803,7 @@ set_exec_filter(void)
|
||||
nitems(exec_filter),
|
||||
exec_filter
|
||||
};
|
||||
debug_decl(set_exec_filter, SUDO_DEBUG_UTIL);
|
||||
debug_decl(set_exec_filter, SUDO_DEBUG_EXEC);
|
||||
|
||||
/* We must set SECCOMP_MODE_FILTER before dropping privileges. */
|
||||
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &exec_fprog) == -1) {
|
||||
@@ -825,7 +825,7 @@ exec_ptrace_seize(pid_t child)
|
||||
PTRACE_O_TRACEFORK|PTRACE_O_TRACEVFORK;
|
||||
int ret = -1;
|
||||
int status;
|
||||
debug_decl(exec_ptrace_seize, SUDO_DEBUG_UTIL);
|
||||
debug_decl(exec_ptrace_seize, SUDO_DEBUG_EXEC);
|
||||
|
||||
/* Seize control of the child process. */
|
||||
if (ptrace(PTRACE_SEIZE, child, NULL, ptrace_opts) == -1) {
|
||||
@@ -878,6 +878,75 @@ done:
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that the execve(2) argument we wrote match the contents of closure.
|
||||
* Returns true if they match, else false.
|
||||
*/
|
||||
static bool
|
||||
verify_execve_info(pid_t pid, struct sudo_ptrace_regs *regs,
|
||||
struct intercept_closure *closure)
|
||||
{
|
||||
char *pathname, **argv, **envp, *buf;
|
||||
int argc, envc, i;
|
||||
bool ret = true;
|
||||
debug_decl(verify_execve_info, SUDO_DEBUG_EXEC);
|
||||
|
||||
buf = get_execve_info(pid, regs, &pathname, &argc, &argv,
|
||||
&envc, &envp);
|
||||
if (buf == NULL)
|
||||
debug_return_bool(false);
|
||||
|
||||
if (pathname == NULL || strcmp(pathname, closure->command) != 0) {
|
||||
sudo_warn(
|
||||
U_("pathname mismatch, expected \"%s\", got \"%s\""),
|
||||
closure->command, pathname ? pathname : "(NULL)");
|
||||
ret = false;
|
||||
}
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (closure->run_argv[i] == NULL) {
|
||||
ret = false;
|
||||
sudo_warn(
|
||||
U_("%s[%d] mismatch, expected \"%s\", got \"%s\""),
|
||||
"argv", i, "(NULL)", argv[i] ? argv[i] : "(NULL)");
|
||||
break;
|
||||
} else if (argv[i] == NULL) {
|
||||
ret = false;
|
||||
sudo_warn(
|
||||
U_("%s[%d] mismatch, expected \"%s\", got \"%s\""),
|
||||
"argv", i, closure->run_argv[i], "(NULL)");
|
||||
break;
|
||||
} else if (strcmp(argv[i], closure->run_argv[i]) != 0) {
|
||||
ret = false;
|
||||
sudo_warn(
|
||||
U_("%s[%d] mismatch, expected \"%s\", got \"%s\""),
|
||||
"argv", i, closure->run_argv[i], argv[i]);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < envc; i++) {
|
||||
if (closure->run_envp[i] == NULL) {
|
||||
ret = false;
|
||||
sudo_warn(
|
||||
U_("%s[%d] mismatch, expected \"%s\", got \"%s\""),
|
||||
"envp", i, "(NULL)", envp[i] ? envp[i] : "(NULL)");
|
||||
break;
|
||||
} else if (envp[i] == NULL) {
|
||||
ret = false;
|
||||
sudo_warn(
|
||||
U_("%s[%d] mismatch, expected \"%s\", got \"%s\""),
|
||||
"envp", i, closure->run_envp[i], "(NULL)");
|
||||
break;
|
||||
} else if (strcmp(envp[i], closure->run_envp[i]) != 0) {
|
||||
ret = false;
|
||||
sudo_warn(
|
||||
U_("%s[%d] mismatch, expected \"%s\", got \"%s\""),
|
||||
"envp", i, closure->run_envp[i], envp[i]);
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
|
||||
debug_return_bool(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Intercept execve(2) and perform a policy check.
|
||||
* Reads current registers and execve(2) arguments.
|
||||
@@ -898,7 +967,7 @@ ptrace_intercept_execve(pid_t pid, struct intercept_closure *closure)
|
||||
bool ret = false;
|
||||
struct stat sb;
|
||||
int i;
|
||||
debug_decl(ptrace_intercept_execve, SUDO_DEBUG_UTIL);
|
||||
debug_decl(ptrace_intercept_execve, SUDO_DEBUG_EXEC);
|
||||
|
||||
/* Do not check the policy if we are executing the initial command. */
|
||||
if (closure->initial_command != 0) {
|
||||
@@ -1000,6 +1069,8 @@ ptrace_intercept_execve(pid_t pid, struct intercept_closure *closure)
|
||||
closure->command = pathname;
|
||||
if (closure->run_argv == NULL)
|
||||
closure->run_argv = argv;
|
||||
if (closure->run_envp == NULL)
|
||||
closure->run_envp = envp;
|
||||
FALLTHROUGH;
|
||||
case POLICY_ACCEPT:
|
||||
/*
|
||||
@@ -1026,6 +1097,9 @@ ptrace_intercept_execve(pid_t pid, struct intercept_closure *closure)
|
||||
unsigned long strtab;
|
||||
size_t len, space = 0;
|
||||
|
||||
sudo_debug_execve(SUDO_DEBUG_DIAG, closure->command,
|
||||
closure->run_argv, envp);
|
||||
|
||||
/*
|
||||
* Calculate the amount of space required for pointers + strings.
|
||||
* Since ptrace(2) always writes in sizeof(long) increments we
|
||||
@@ -1088,6 +1162,14 @@ ptrace_intercept_execve(pid_t pid, struct intercept_closure *closure)
|
||||
(int)pid);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (closure->state == POLICY_TEST) {
|
||||
/* Verify the contents of what we just wrote. */
|
||||
if (!verify_execve_info(pid, ®s, closure)) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR,
|
||||
"%s: new execve args don't match closure", __func__);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
Reference in New Issue
Block a user