165 lines
5.5 KiB
Diff
165 lines
5.5 KiB
Diff
From e5652fc65a54ab2d3f161c264254579f00699b00 Mon Sep 17 00:00:00 2001
|
|
From: "Todd C. Miller" <Todd.Miller@sudo.ws>
|
|
Date: Thu, 14 Jul 2022 09:29:40 -0600
|
|
Subject: [PATCH] Linux execve(2) allows argv or envp to be NULL. Add checks to
|
|
make sure we don't deference a NULL pointer.
|
|
|
|
---
|
|
lib/util/sudo_debug.c | 10 +++++-----
|
|
src/exec_intercept.c | 2 +-
|
|
src/exec_preload.c | 5 +++++
|
|
src/exec_ptrace.c | 36 +++++++++++++++++++++++++++++-------
|
|
src/sudo_intercept.c | 10 ++++++++++
|
|
src/sudo_intercept_common.c | 25 ++++++++++++++-----------
|
|
6 files changed, 64 insertions(+), 24 deletions(-)
|
|
|
|
diff --git a/lib/util/sudo_debug.c b/lib/util/sudo_debug.c
|
|
index d78536a0c..a2ead5228 100644
|
|
--- a/lib/util/sudo_debug.c
|
|
+++ b/lib/util/sudo_debug.c
|
|
@@ -831,7 +831,7 @@ sudo_debug_execve2_v1(int level, const char *path, char *const argv[], char *con
|
|
size_t plen;
|
|
debug_decl_func(sudo_debug_execve2);
|
|
|
|
- if (sudo_debug_active_instance == -1)
|
|
+ if (sudo_debug_active_instance == -1 || path == NULL)
|
|
goto out;
|
|
|
|
/* Extract priority and subsystem from level. */
|
|
@@ -867,13 +867,13 @@ sudo_debug_execve2_v1(int level, const char *path, char *const argv[], char *con
|
|
/* Alloc and build up buffer. */
|
|
plen = strlen(path);
|
|
buflen = sizeof(EXEC_PREFIX) -1 + plen;
|
|
- if (argv[0] != NULL) {
|
|
+ if (argv != NULL && argv[0] != NULL) {
|
|
buflen += sizeof(" []") - 1;
|
|
for (av = argv; *av; av++)
|
|
buflen += strlen(*av) + 1;
|
|
buflen--;
|
|
}
|
|
- if (log_envp) {
|
|
+ if (envp != NULL && log_envp) {
|
|
buflen += sizeof(" []") - 1;
|
|
for (av = envp; *av; av++)
|
|
buflen += strlen(*av) + 1;
|
|
@@ -892,7 +892,7 @@ sudo_debug_execve2_v1(int level, const char *path, char *const argv[], char *con
|
|
cp += plen;
|
|
|
|
/* Copy argv. */
|
|
- if (argv[0] != NULL) {
|
|
+ if (argv != NULL && argv[0] != NULL) {
|
|
*cp++ = ' ';
|
|
*cp++ = '[';
|
|
for (av = argv; *av; av++) {
|
|
@@ -904,7 +904,7 @@ sudo_debug_execve2_v1(int level, const char *path, char *const argv[], char *con
|
|
cp[-1] = ']';
|
|
}
|
|
|
|
- if (log_envp) {
|
|
+ if (envp != NULL && log_envp) {
|
|
*cp++ = ' ';
|
|
*cp++ = '[';
|
|
for (av = envp; *av; av++) {
|
|
diff --git a/src/exec_preload.c b/src/exec_preload.c
|
|
index 4f04a0113..81e865333 100644
|
|
--- a/src/exec_preload.c
|
|
+++ b/src/exec_preload.c
|
|
@@ -44,6 +44,7 @@ sudo_preload_dso(char *const envp[], const char *dso_file, int intercept_fd)
|
|
int env_len, len;
|
|
int preload_idx = -1;
|
|
int intercept_idx = -1;
|
|
+ char *const empty[1] = { NULL };
|
|
bool fd_present = false;
|
|
bool dso_present = false;
|
|
# ifdef RTLD_PRELOAD_ENABLE_VAR
|
|
@@ -73,4 +73,8 @@ sudo_preload_dso(char *const envp[], const char *dso_file, int intercept_fd)
|
|
* XXX - need to support 32-bit and 64-bit variants
|
|
*/
|
|
|
|
+ /* Treat a NULL envp as empty, thanks Linux. */
|
|
+ if (envp == NULL)
|
|
+ envp = empty;
|
|
+
|
|
/* Count entries in envp, looking for LD_PRELOAD as we go. */
|
|
diff --git a/src/sudo_intercept.c b/src/sudo_intercept.c
|
|
index 97c612892..48ecc9bc9 100644
|
|
--- a/src/sudo_intercept.c
|
|
+++ b/src/sudo_intercept.c
|
|
@@ -135,6 +135,11 @@ exec_wrapper(const char *cmnd, char * const argv[], char * const envp[],
|
|
void *fn = NULL;
|
|
debug_decl(exec_wrapper, SUDO_DEBUG_EXEC);
|
|
|
|
+ if (cmnd == NULL) {
|
|
+ errno = EINVAL;
|
|
+ debug_return_int(-1);
|
|
+ }
|
|
+
|
|
/* Only check PATH for the command for execlp/execvp/execvpe. */
|
|
if (strchr(cmnd, '/') == NULL) {
|
|
if (!is_execvp) {
|
|
@@ -201,6 +206,11 @@ execl_wrapper(int type, const char *name, const char *arg, va_list ap)
|
|
va_list ap2;
|
|
debug_decl(execl_wrapper, SUDO_DEBUG_EXEC);
|
|
|
|
+ if (name == NULL || arg == NULL) {
|
|
+ errno = EINVAL;
|
|
+ debug_return_int(-1);
|
|
+ }
|
|
+
|
|
va_copy(ap2, ap);
|
|
while (va_arg(ap2, char *) != NULL)
|
|
argc++;
|
|
diff --git a/src/sudo_intercept_common.c b/src/sudo_intercept_common.c
|
|
index 102393952..a81a3c880 100644
|
|
--- a/src/sudo_intercept_common.c
|
|
+++ b/src/sudo_intercept_common.c
|
|
@@ -297,6 +297,7 @@ send_policy_check_req(int sock, const char *cmnd, char * const argv[],
|
|
InterceptRequest msg = INTERCEPT_REQUEST__INIT;
|
|
PolicyCheckRequest req = POLICY_CHECK_REQUEST__INIT;
|
|
char cwdbuf[PATH_MAX];
|
|
+ char *empty[1] = { NULL };
|
|
uint8_t *buf = NULL;
|
|
bool ret = false;
|
|
uint32_t msg_len;
|
|
@@ -313,14 +314,14 @@ send_policy_check_req(int sock, const char *cmnd, char * const argv[],
|
|
/* Setup policy check request. */
|
|
req.intercept_fd = sock;
|
|
req.command = (char *)cmnd;
|
|
- req.argv = (char **)argv;
|
|
- for (len = 0; argv[len] != NULL; len++)
|
|
- continue;
|
|
- req.n_argv = len;
|
|
- req.envp = (char **)envp;
|
|
- for (len = 0; envp[len] != NULL; len++)
|
|
- continue;
|
|
- req.n_envp = len;
|
|
+ req.argv = argv ? (char **)argv : empty;
|
|
+ req.n_argv = 0;
|
|
+ while (req.argv[req.n_argv] != NULL)
|
|
+ req.n_argv++;
|
|
+ req.envp = envp ? (char **)envp : empty;
|
|
+ req.n_envp = 0;
|
|
+ while (req.envp[req.n_envp] != NULL)
|
|
+ req.n_envp++;
|
|
if (getcwd(cwdbuf, sizeof(cwdbuf)) != NULL) {
|
|
req.cwd = cwdbuf;
|
|
}
|
|
@@ -409,9 +410,11 @@ command_allowed(const char *cmnd, char * const argv[],
|
|
if (sudo_debug_needed(SUDO_DEBUG_INFO)) {
|
|
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
|
"req_command: %s", cmnd);
|
|
- for (idx = 0; argv[idx] != NULL; idx++) {
|
|
- sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
|
- "req_argv[%zu]: %s", idx, argv[idx]);
|
|
+ if (argv != NULL) {
|
|
+ for (idx = 0; argv[idx] != NULL; idx++) {
|
|
+ sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
|
+ "req_argv[%zu]: %s", idx, argv[idx]);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
--
|
|
2.33.0
|
|
|