ptrace_intercept_execve: fail syscall rather than killing process on error.

If the execve(2) args are bogus pointers, we should just return an
error instead of killing the process.  For consistency with the
kernel, convert EIO from ptrace(2) to EFAULT.
Also convert some ptrace(2) warnings to debug printfs so sudo is less chatty.
This commit is contained in:
Todd C. Miller
2022-08-19 11:05:10 -06:00
parent 9f552471bc
commit b2d8909c19

View File

@@ -348,8 +348,9 @@ ptrace_read_string(pid_t pid, unsigned long addr, char *buf, size_t bufsize)
for (;;) { for (;;) {
word = ptrace(PTRACE_PEEKDATA, pid, addr, NULL); word = ptrace(PTRACE_PEEKDATA, pid, addr, NULL);
if (word == (unsigned long)-1) { if (word == (unsigned long)-1) {
sudo_warn("%s: ptrace(PTRACE_PEEKDATA, %d, 0x%lx, NULL)", sudo_debug_printf(
__func__, (int)pid, addr); SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"ptrace(PTRACE_PEEKDATA, %d, 0x%lx, NULL)", (int)pid, addr);
debug_return_ssize_t(-1); debug_return_ssize_t(-1);
} }
@@ -653,6 +654,9 @@ get_execve_info(pid_t pid, struct sudo_ptrace_regs *regs, char **pathname_out,
path_addr = get_sc_arg1(regs); path_addr = get_sc_arg1(regs);
argv_addr = get_sc_arg2(regs); argv_addr = get_sc_arg2(regs);
envp_addr = get_sc_arg3(regs); envp_addr = get_sc_arg3(regs);
sudo_debug_printf(SUDO_DEBUG_INFO,
"%s: %d: path 0x%lx, argv 0x%lx, envp 0x%lx", __func__,
(int)pid, path_addr, argv_addr, envp_addr);
/* Count argv and envp. */ /* Count argv and envp. */
argc = ptrace_get_vec_len(pid, regs, argv_addr); argc = ptrace_get_vec_len(pid, regs, argv_addr);
@@ -678,8 +682,9 @@ get_execve_info(pid_t pid, struct sudo_ptrace_regs *regs, char **pathname_out,
/* Read argv */ /* Read argv */
len = ptrace_read_vec(pid, regs, argv_addr, argv, strtab, bufsize); len = ptrace_read_vec(pid, regs, argv_addr, argv, strtab, bufsize);
if (len == (size_t)-1) { if (len == (size_t)-1) {
sudo_warn(U_("unable to read execve %s for process %d"), sudo_debug_printf(
"argv", (int)pid); SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"unable to read execve argv for process %d", (int)pid);
goto bad; goto bad;
} }
strtab += len; strtab += len;
@@ -688,8 +693,9 @@ get_execve_info(pid_t pid, struct sudo_ptrace_regs *regs, char **pathname_out,
/* Read envp */ /* Read envp */
len = ptrace_read_vec(pid, regs, envp_addr, envp, strtab, bufsize); len = ptrace_read_vec(pid, regs, envp_addr, envp, strtab, bufsize);
if (len == (size_t)-1) { if (len == (size_t)-1) {
sudo_warn(U_("unable to read execve %s for process %d"), sudo_debug_printf(
"envp", (int)pid); SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"unable to read execve envp for process %d", (int)pid);
goto bad; goto bad;
} }
strtab += len; strtab += len;
@@ -702,8 +708,9 @@ get_execve_info(pid_t pid, struct sudo_ptrace_regs *regs, char **pathname_out,
} else { } else {
len = ptrace_read_string(pid, path_addr, strtab, bufsize); len = ptrace_read_string(pid, path_addr, strtab, bufsize);
if (len == (size_t)-1) { if (len == (size_t)-1) {
sudo_warn(U_("unable to read execve %s for process %d"), sudo_debug_printf(
"pathname", (int)pid); SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"unable to read execve pathname for process %d", (int)pid);
goto bad; goto bad;
} }
pathname = strtab; pathname = strtab;
@@ -1286,8 +1293,9 @@ ptrace_verify_post_exec(pid_t pid, struct sudo_ptrace_regs *regs,
/* Read argv */ /* Read argv */
len = ptrace_read_vec(pid, regs, argv_addr, argv, strtab, bufsize); len = ptrace_read_vec(pid, regs, argv_addr, argv, strtab, bufsize);
if (len == (size_t)-1) { if (len == (size_t)-1) {
sudo_warn(U_("unable to read execve %s for process %d"), sudo_debug_printf(
"argv", (int)pid); SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"unable to read execve argv for process %d", (int)pid);
goto done; goto done;
} }
strtab += len; strtab += len;
@@ -1296,8 +1304,9 @@ ptrace_verify_post_exec(pid_t pid, struct sudo_ptrace_regs *regs,
/* Read envp */ /* Read envp */
len = ptrace_read_vec(pid, regs, envp_addr, envp, strtab, bufsize); len = ptrace_read_vec(pid, regs, envp_addr, envp, strtab, bufsize);
if (len == (size_t)-1) { if (len == (size_t)-1) {
sudo_warn(U_("unable to read execve %s for process %d"), sudo_debug_printf(
"envp", (int)pid); SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"unable to read execve envp for process %d", (int)pid);
goto done; goto done;
} }
strtab += len; strtab += len;
@@ -1404,11 +1413,11 @@ ptrace_intercept_execve(pid_t pid, struct intercept_closure *closure)
if (buf == NULL) { if (buf == NULL) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
"%s: %d: unable to get execve info", __func__, (int)pid); "%s: %d: unable to get execve info", __func__, (int)pid);
/* EIO from ptrace is like EFAULT from the kernel. */
/* Unrecoverable error, kill the process if it still exists. */ if (errno == EIO)
if (errno != ESRCH) errno = EFAULT;
kill(pid, SIGKILL); ptrace_fail_syscall(pid, &regs, errno);
debug_return_bool(false); goto done;
} }
/* Must have a pathname. */ /* Must have a pathname. */