Change intercept IPC to use a localhost socket instead of inherited fd.

This allows intercept mode to work with shells that close all open
fds upon startup.  The ctor in sudo_intercept.so requests the port
number and secret over the socket inherited from the parent then
closes it.  For each policy request, a TCP connection is made to
the sudo parent process to perform the policy check.  Child processes
re-use the TCP socket to request the port number and secret just like
the initial process started by sudo does.
This commit is contained in:
Todd C. Miller
2021-08-25 14:24:36 -06:00
parent 448536e0f7
commit c465d8971d
11 changed files with 1067 additions and 632 deletions

View File

@@ -43,15 +43,11 @@
#include "sudo_exec.h"
#include "sudo_plugin.h"
#include "sudo_plugin_int.h"
#include "sudo_rand.h"
/* Note that details and evbase must come first. */
struct exec_closure_nopty {
uint64_t secret;
struct command_details *details;
struct sudo_event_base *evbase;
struct sudo_event *errpipe_event;
struct sudo_event *intercept_event;
struct sudo_event *sigint_event;
struct sudo_event *sigquit_event;
struct sudo_event *sigtstp_event;
@@ -203,13 +199,11 @@ signal_cb_nopty(int signo, int what, void *v)
*/
static void
fill_exec_closure_nopty(struct exec_closure_nopty *ec,
struct command_status *cstat, struct command_details *details,
int intercept_fd, int errfd)
struct command_status *cstat, struct command_details *details, int errfd)
{
debug_decl(fill_exec_closure_nopty, SUDO_DEBUG_EXEC);
/* Fill in the non-event part of the closure. */
ec->secret = arc4random() | ((uint64_t)arc4random() << 32);
ec->ppgrp = getpgrp();
ec->cstat = cstat;
ec->details = details;
@@ -227,17 +221,6 @@ fill_exec_closure_nopty(struct exec_closure_nopty *ec,
sudo_fatal("%s", U_("unable to add event to queue"));
sudo_debug_printf(SUDO_DEBUG_INFO, "error pipe fd %d\n", errfd);
/* Event for sudo_intercept.so (optional). */
if (intercept_fd != -1) {
ec->intercept_event = sudo_ev_alloc(intercept_fd,
SUDO_EV_READ|SUDO_EV_PERSIST, intercept_fd_cb, ec);
if (ec->intercept_event == NULL)
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
if (sudo_ev_add(ec->evbase, ec->intercept_event, NULL, false) == -1)
sudo_fatal("%s", U_("unable to add event to queue"));
sudo_debug_printf(SUDO_DEBUG_INFO, "intercept fd %d\n", intercept_fd);
}
/* Events for local signals. */
ec->sigint_event = sudo_ev_alloc(SIGINT,
SUDO_EV_SIGINFO, signal_cb_nopty, ec);
@@ -387,7 +370,7 @@ exec_nopty(struct command_details *details, struct command_status *cstat)
* This must be inherited across exec, hence no FD_CLOEXEC.
*/
if (ISSET(details->flags, CD_INTERCEPT|CD_LOG_CHILDREN)) {
if (socketpair(PF_UNIX, SOCK_DGRAM, 0, intercept_sv) == -1)
if (socketpair(PF_UNIX, SOCK_STREAM, 0, intercept_sv) == -1)
sudo_fatal("%s", U_("unable to create sockets"));
}
@@ -454,7 +437,13 @@ exec_nopty(struct command_details *details, struct command_status *cstat)
* Fill in exec closure, allocate event base, signal events and
* the error pipe event.
*/
fill_exec_closure_nopty(&ec, cstat, details, intercept_sv[0], errpipe[0]);
fill_exec_closure_nopty(&ec, cstat, details, errpipe[0]);
/* Create event and closure for intercept mode. */
if (intercept_sv[0] != -1) {
if (!intercept_setup(intercept_sv[0], ec.evbase, details))
exit(EXIT_FAILURE);
}
/* Restore signal mask now that signal handlers are setup. */
sigprocmask(SIG_SETMASK, &oset, NULL);