Add debug support to sudo_intercept.so

This commit is contained in:
Todd C. Miller
2021-08-09 15:50:25 -06:00
parent 9c3df47da9
commit 258fa9d4f9
2 changed files with 118 additions and 58 deletions

View File

@@ -40,6 +40,7 @@ char **
sudo_preload_dso(char *envp[], const char *dso_file, int intercept_fd) sudo_preload_dso(char *envp[], const char *dso_file, int intercept_fd)
{ {
char *preload = NULL; char *preload = NULL;
char **nenvp = NULL;
int env_len; int env_len;
int preload_idx = -1; int preload_idx = -1;
int intercept_idx = -1; int intercept_idx = -1;
@@ -59,7 +60,6 @@ sudo_preload_dso(char *envp[], const char *dso_file, int intercept_fd)
*/ */
/* Count entries in envp, looking for LD_PRELOAD as we go. */ /* Count entries in envp, looking for LD_PRELOAD as we go. */
/* XXX - If multiple LD_PRELOAD should remove extras */
for (env_len = 0; envp[env_len] != NULL; env_len++) { for (env_len = 0; envp[env_len] != NULL; env_len++) {
if (strncmp(envp[env_len], RTLD_PRELOAD_VAR "=", sizeof(RTLD_PRELOAD_VAR)) == 0) { if (strncmp(envp[env_len], RTLD_PRELOAD_VAR "=", sizeof(RTLD_PRELOAD_VAR)) == 0) {
if (preload_idx == -1) { if (preload_idx == -1) {
@@ -130,7 +130,7 @@ sudo_preload_dso(char *envp[], const char *dso_file, int intercept_fd)
if (preload_idx == -1 || !dso_enabled || intercept_idx == -1) { if (preload_idx == -1 || !dso_enabled || intercept_idx == -1) {
const int env_size = env_len + 1 + (preload_idx == -1) + dso_enabled + (intercept_idx == -1); // -V547 const int env_size = env_len + 1 + (preload_idx == -1) + dso_enabled + (intercept_idx == -1); // -V547
char **nenvp = reallocarray(NULL, env_size, sizeof(*envp)); nenvp = reallocarray(NULL, env_size, sizeof(*nenvp));
if (nenvp == NULL) { if (nenvp == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
debug_return_ptr(NULL); debug_return_ptr(NULL);
@@ -150,10 +150,7 @@ sudo_preload_dso(char *envp[], const char *dso_file, int intercept_fd)
preload = sudo_new_key_val(RTLD_PRELOAD_VAR, dso_file); preload = sudo_new_key_val(RTLD_PRELOAD_VAR, dso_file);
# endif # endif
if (preload == NULL) { if (preload == NULL) {
sudo_warnx(U_("%s: %s"), __func__, goto oom;
U_("unable to allocate memory"));
/* XXX - leak */
debug_return_ptr(NULL);
} }
envp[env_len++] = preload; envp[env_len++] = preload;
envp[env_len] = NULL; envp[env_len] = NULL;
@@ -161,10 +158,7 @@ sudo_preload_dso(char *envp[], const char *dso_file, int intercept_fd)
int len = asprintf(&preload, "%s=%s%s%s", RTLD_PRELOAD_VAR, int len = asprintf(&preload, "%s=%s%s%s", RTLD_PRELOAD_VAR,
dso_file, RTLD_PRELOAD_DELIM, envp[preload_idx]); dso_file, RTLD_PRELOAD_DELIM, envp[preload_idx]);
if (len == -1) { if (len == -1) {
sudo_warnx(U_("%s: %s"), __func__, goto oom;
U_("unable to allocate memory"));
/* XXX - leak */
debug_return_ptr(NULL);
} }
envp[preload_idx] = preload; envp[preload_idx] = preload;
} }
@@ -181,10 +175,7 @@ sudo_preload_dso(char *envp[], const char *dso_file, int intercept_fd)
len = asprintf(&fdstr, "SUDO_INTERCEPT_FD=%d", intercept_fd); len = asprintf(&fdstr, "SUDO_INTERCEPT_FD=%d", intercept_fd);
if (len == -1) { if (len == -1) {
sudo_warnx(U_("%s: %s"), __func__, goto oom;
U_("unable to allocate memory"));
/* XXX - leak */
debug_return_ptr(NULL);
} }
if (intercept_idx != -1) { if (intercept_idx != -1) {
envp[preload_idx] = fdstr; envp[preload_idx] = fdstr;
@@ -195,5 +186,10 @@ sudo_preload_dso(char *envp[], const char *dso_file, int intercept_fd)
} }
debug_return_ptr(envp); debug_return_ptr(envp);
oom:
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
free(preload);
free(nenvp);
debug_return_ptr(NULL);
} }
#endif /* RTLD_PRELOAD_VAR */ #endif /* RTLD_PRELOAD_VAR */

View File

@@ -41,13 +41,13 @@
# include "compat/stdbool.h" # include "compat/stdbool.h"
#endif /* HAVE_STDBOOL_H */ #endif /* HAVE_STDBOOL_H */
#define SUDO_ERROR_WRAP 0
#include "sudo_compat.h" #include "sudo_compat.h"
#include "sudo_conf.h" #include "sudo_conf.h"
#include "sudo_debug.h"
#include "sudo_fatal.h" #include "sudo_fatal.h"
#include "sudo_exec.h" #include "sudo_exec.h"
#include "sudo_gettext.h" #include "sudo_gettext.h"
#include "sudo_util.h"
#include "intercept.pb-c.h" #include "intercept.pb-c.h"
extern char **environ; extern char **environ;
@@ -63,10 +63,17 @@ sudo_interposer_init(void)
{ {
static bool initialized; static bool initialized;
char **p; char **p;
debug_decl(sudo_interposer_init, SUDO_DEBUG_EXEC);
if (!initialized) { if (!initialized) {
initialized = true; initialized = true;
/* Read debug section of sudo.conf and init debugging. */
if (sudo_conf_read(NULL, SUDO_CONF_DEBUG) != -1) {
sudo_debug_register("sudo_intercept.so", NULL, NULL,
sudo_conf_debug_files("sudo_intercept.so"));
}
/* /*
* Missing SUDO_INTERCEPT_FD will result in execve() failure. * Missing SUDO_INTERCEPT_FD will result in execve() failure.
* Note that we cannot use getenv(3) here on Linux at least. * Note that we cannot use getenv(3) here on Linux at least.
@@ -74,20 +81,25 @@ sudo_interposer_init(void)
for (p = environ; *p != NULL; p++) { for (p = environ; *p != NULL; p++) {
if (strncmp(*p, "SUDO_INTERCEPT_FD=", sizeof("SUDO_INTERCEPT_FD=") -1) == 0) { if (strncmp(*p, "SUDO_INTERCEPT_FD=", sizeof("SUDO_INTERCEPT_FD=") -1) == 0) {
const char *fdstr = *p + sizeof("SUDO_INTERCEPT_FD=") - 1; const char *fdstr = *p + sizeof("SUDO_INTERCEPT_FD=") - 1;
char *ep; const char *errstr;
long ulval; int fd;
/* XXX - debugging */ fd = sudo_strtonum(fdstr, 0, INT_MAX, &errstr);
ulval = strtoul(fdstr, &ep, 10); if (errstr != NULL) {
if (*fdstr == '\0' || *ep != '\0' || ulval > INT_MAX) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
sudo_warnx(U_("invalid SUDO_INTERCEPT_FD: %s"), fdstr); "invalid SUDO_INTERCEPT_FD: %s: %s", fdstr, errstr);
break; break;
} }
intercept_sock = ulval; intercept_sock = fd;
break; break;
} }
} }
if (intercept_sock == -1) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"SUDO_INTERCEPT_FD not found in environment");
}
} }
debug_return;
} }
static uint8_t * static uint8_t *
@@ -99,6 +111,7 @@ fmt_policy_check_req(const char *cmnd, char * const argv[], char * const envp[],
uint8_t *buf = NULL; uint8_t *buf = NULL;
uint32_t msg_len; uint32_t msg_len;
size_t len; size_t len;
debug_decl(sudo_interposer_init, SUDO_DEBUG_EXEC);
/* Setup policy check request. */ /* Setup policy check request. */
req.command = (char *)cmnd; req.command = (char *)cmnd;
@@ -115,7 +128,8 @@ fmt_policy_check_req(const char *cmnd, char * const argv[], char * const envp[],
len = intercept_message__get_packed_size(&msg); len = intercept_message__get_packed_size(&msg);
if (len > MESSAGE_SIZE_MAX) { if (len > MESSAGE_SIZE_MAX) {
sudo_warnx(U_("client message too large: %zu"), len); sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"InterceptMessage too large: %zu", len);
goto done; goto done;
} }
/* Wire message size is used for length encoding, precedes message. */ /* Wire message size is used for length encoding, precedes message. */
@@ -131,7 +145,7 @@ fmt_policy_check_req(const char *cmnd, char * const argv[], char * const envp[],
*buflen = len; *buflen = len;
done: done:
return buf; debug_return_ptr(buf);
} }
/* Send fd over a unix domain socket. */ /* Send fd over a unix domain socket. */
@@ -147,6 +161,7 @@ intercept_send_fd(int sock, int fd)
struct iovec iov[1]; struct iovec iov[1];
char ch = '\0'; char ch = '\0';
ssize_t nsent; ssize_t nsent;
debug_decl(intercept_send_fd, SUDO_DEBUG_EXEC);
/* /*
* We send a single byte of data along with the fd; some systems * We send a single byte of data along with the fd; some systems
@@ -171,33 +186,46 @@ intercept_send_fd(int sock, int fd)
for (;;) { for (;;) {
nsent = sendmsg(sock, &msg, 0); nsent = sendmsg(sock, &msg, 0);
if (nsent != -1) if (nsent != -1)
return true; debug_return_bool(true);
if (errno != EAGAIN && errno != EINTR) if (errno != EAGAIN && errno != EINTR)
break; break;
} }
sudo_warn("sendmsg"); sudo_warn("sendmsg");
return false; debug_return_bool(false);
} }
bool bool
command_allowed(const char *cmnd, char * const argv[], char * const envp[], command_allowed(const char *cmnd, char * const argv[], char * const envp[],
char **ncmnd, char ***nargv, char ***nenvp) char **ncmndp, char ***nargvp, char ***nenvpp)
{ {
char *ncmnd = NULL, **nargv = NULL, **nenvp = NULL;
PolicyCheckResult *res = NULL; PolicyCheckResult *res = NULL;
int sv[2] = { -1, -1 }; int sv[2] = { -1, -1 };
ssize_t nread, nwritten; ssize_t nread, nwritten;
uint8_t *cp, *buf = NULL; uint8_t *cp, *buf = NULL;
bool ret = false; bool ret = false;
uint32_t res_len; uint32_t res_len;
size_t len; size_t idx, len;
debug_decl(intercept_send_fd, SUDO_DEBUG_EXEC);
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 (intercept_sock < INTERCEPT_FD_MIN) { if (intercept_sock < INTERCEPT_FD_MIN) {
sudo_warnx("invalid intercept fd: %d", intercept_sock); // XXX debugging sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"invalid intercept fd: %d", intercept_sock);
errno = EINVAL; errno = EINVAL;
goto done; goto done;
} }
if (fcntl(intercept_sock, F_GETFD, 0) == -1) { if (fcntl(intercept_sock, F_GETFD, 0) == -1) {
sudo_warnx("intercept fd %d not open", intercept_sock); // XXX debugging sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"intercept fd %d not open", intercept_sock);
errno = EINVAL; errno = EINVAL;
goto done; goto done;
} }
@@ -238,60 +266,96 @@ command_allowed(const char *cmnd, char * const argv[], char * const envp[],
/* Read message size (uint32_t in host byte order). */ /* Read message size (uint32_t in host byte order). */
nread = read(sv[0], &res_len, sizeof(res_len)); nread = read(sv[0], &res_len, sizeof(res_len));
if ((size_t)nread != sizeof(res_len)) { if ((size_t)nread != sizeof(res_len)) {
if (nread == 0) if (nread == 0) {
sudo_warnx("unexpected EOF reading message size"); // XXX sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
else "unexpected EOF reading result size");
sudo_warn("read"); } else {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"error reading result size");
}
goto done; goto done;
} }
if (res_len > MESSAGE_SIZE_MAX) { if (res_len > MESSAGE_SIZE_MAX) {
sudo_warnx(U_("server message too large: %zu"), (size_t)res_len); sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"PolicyCheckResult too large: %zu", len);
goto done; goto done;
} }
/* Read response from sudo (blocking). */ /* Read result from sudo (blocking). */
if ((buf = malloc(res_len)) == NULL) { if ((buf = malloc(res_len)) == NULL) {
goto done; goto done;
} }
nread = read(sv[0], buf, res_len); nread = read(sv[0], buf, res_len);
if ((size_t)nread != res_len) { if ((size_t)nread != res_len) {
if (nread == 0) if (nread == 0) {
sudo_warnx("unexpected EOF reading response"); // XXX sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
else "unexpected EOF reading result");
sudo_warn("read"); } else {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"error reading result");
}
goto done; goto done;
} }
res = policy_check_result__unpack(NULL, res_len, buf); res = policy_check_result__unpack(NULL, res_len, buf);
if (res == NULL) { if (res == NULL) {
sudo_warnx("unable to unpack %s size %zu", "PolicyCheckResult", sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
(size_t)res_len); "unable to unpack %s size %u", "PolicyCheckResult", res_len);
goto done; goto done;
} }
switch (res->type_case) { switch (res->type_case) {
case POLICY_CHECK_RESULT__TYPE_ACCEPT_MSG: case POLICY_CHECK_RESULT__TYPE_ACCEPT_MSG:
// XXX - return value if (sudo_debug_needed(SUDO_DEBUG_INFO)) {
*ncmnd = strdup(res->u.accept_msg->run_command); sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
*nargv = reallocarray(NULL, res->u.accept_msg->n_run_argv + 1, sizeof(char *)); "run_command: %s", res->u.accept_msg->run_command);
for (len = 0; len < res->u.accept_msg->n_run_argv; len++) { for (idx = 0; idx < res->u.accept_msg->n_run_argv; idx++) {
(*nargv)[len] = strdup(res->u.accept_msg->run_argv[len]); sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
"run_argv[%zu]: %s", idx, res->u.accept_msg->run_argv[idx]);
}
} }
(*nargv)[len] = NULL; ncmnd = strdup(res->u.accept_msg->run_command);
if (ncmnd == NULL)
goto oom;
nargv = reallocarray(NULL, res->u.accept_msg->n_run_argv + 1,
sizeof(char *));
if (nargv == NULL)
goto oom;
for (len = 0; len < res->u.accept_msg->n_run_argv; len++) {
nargv[len] = strdup(res->u.accept_msg->run_argv[len]);
if (nargv[len] == NULL)
goto oom;
}
nargv[len] = NULL;
// XXX - bogus cast // XXX - bogus cast
*nenvp = sudo_preload_dso((char **)envp, sudo_conf_intercept_path(), intercept_sock); nenvp = sudo_preload_dso((char **)envp, sudo_conf_intercept_path(),
intercept_sock);
if (nenvp == NULL)
goto oom;
*ncmndp = ncmnd;
*nargvp = nargv;
*nenvpp = nenvp;
ret = true; ret = true;
break; goto done;
case POLICY_CHECK_RESULT__TYPE_REJECT_MSG: case POLICY_CHECK_RESULT__TYPE_REJECT_MSG:
/* XXX - display reject message */ /* Policy module displayed reject message but we are in raw mode. */
break; fputc('\r', stderr);
goto done;
case POLICY_CHECK_RESULT__TYPE_ERROR_MSG: case POLICY_CHECK_RESULT__TYPE_ERROR_MSG:
/* XXX - display error message */ /* Policy module may display error message but we are in raw mode. */
break; fputc('\r', stderr);
sudo_warnx("%s", res->u.error_msg->error_message);
goto done;
default: default:
sudo_warnx(U_("unexpected type_case value %d in %s from %s"), sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unexpected type_case value %d in %s from %s",
res->type_case, "PolicyCheckResult", "sudo"); res->type_case, "PolicyCheckResult", "sudo");
break; goto done;
} }
oom:
free(ncmnd);
while (len > 0)
free(nargv[--len]);
done: done:
policy_check_result__free_unpacked(res, NULL); policy_check_result__free_unpacked(res, NULL);
if (sv[0] != -1) if (sv[0] != -1)
@@ -300,5 +364,5 @@ done:
close(sv[1]); close(sv[1]);
free(buf); free(buf);
return ret; debug_return_bool(ret);
} }