From e5652fc65a54ab2d3f161c264254579f00699b00 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" 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