Bound the subprocess lifetime using prctl(PR_SET_PDEATHSIG, ...).

The pipes wouldn't do this job anymore because they were unused and thus
never performed writes that would generate SIGPIPEs, so the pipes are
removed, too.
This commit is contained in:
Nicholas J. Kain 2014-04-15 18:01:01 -04:00
parent b3ce601f20
commit b00444ab8b
4 changed files with 25 additions and 46 deletions

View File

@ -184,7 +184,7 @@ static int ifchd_cmd(char *b, size_t bl, uint8_t *od, ssize_t ol, uint8_t code)
return -1; return -1;
} }
static void pipewrite(struct client_state_t *cs, const char *buf, size_t count) static void ifchwrite(struct client_state_t *cs, const char *buf, size_t count)
{ {
cs->ifchWorking = 1; cs->ifchWorking = 1;
ssize_t r = safe_write(ifchSock[0], buf, count); ssize_t r = safe_write(ifchSock[0], buf, count);
@ -205,7 +205,7 @@ void ifchange_deconfig(struct client_state_t *cs)
snprintf(buf, sizeof buf, "ip4:0.0.0.0,255.255.255.255;"); snprintf(buf, sizeof buf, "ip4:0.0.0.0,255.255.255.255;");
log_line("%s: Resetting IP configuration.", client_config.interface); log_line("%s: Resetting IP configuration.", client_config.interface);
pipewrite(cs, buf, strlen(buf)); ifchwrite(cs, buf, strlen(buf));
memset(&cfg_packet, 0, sizeof cfg_packet); memset(&cfg_packet, 0, sizeof cfg_packet);
} }
@ -307,7 +307,7 @@ void ifchange_bind(struct client_state_t *cs, struct dhcpmsg *packet)
bo += send_cmd(buf + bo, sizeof buf - bo, packet, DCODE_MTU); bo += send_cmd(buf + bo, sizeof buf - bo, packet, DCODE_MTU);
bo += send_cmd(buf + bo, sizeof buf - bo, packet, DCODE_WINS); bo += send_cmd(buf + bo, sizeof buf - bo, packet, DCODE_WINS);
if (bo) if (bo)
pipewrite(cs, buf, bo); ifchwrite(cs, buf, bo);
cs->ifDeconfig = 0; cs->ifDeconfig = 0;
memcpy(&cfg_packet, packet, sizeof cfg_packet); memcpy(&cfg_packet, packet, sizeof cfg_packet);

View File

@ -57,7 +57,7 @@
struct ifchd_client cl; struct ifchd_client cl;
static int epollfd, signalFd; static int epollfd, signalFd;
/* Slots are for signalFd and the ndhc -> ifchd pipe. */ /* Slots are for signalFd and the ndhc -> ifchd socket. */
static struct epoll_event events[2]; static struct epoll_event events[2];
static int resolv_conf_fd = -1; static int resolv_conf_fd = -1;
@ -260,7 +260,6 @@ static void setup_signals_ifch(void)
{ {
sigset_t mask; sigset_t mask;
sigemptyset(&mask); sigemptyset(&mask);
sigaddset(&mask, SIGPIPE);
sigaddset(&mask, SIGUSR1); sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGUSR2); sigaddset(&mask, SIGUSR2);
sigaddset(&mask, SIGTSTP); sigaddset(&mask, SIGTSTP);
@ -294,10 +293,7 @@ static void signal_dispatch(void)
switch (si.ssi_signo) { switch (si.ssi_signo) {
case SIGINT: case SIGINT:
case SIGTERM: case SIGTERM:
exit(EXIT_SUCCESS); case SIGHUP:
break;
case SIGPIPE:
log_line("ndhc-ifch: IPC pipe closed. Exiting.");
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
break; break;
default: default:
@ -312,11 +308,11 @@ static void inform_execute(char c)
// Remote end hung up. // Remote end hung up.
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} else if (r < 0) } else if (r < 0)
suicide("%s: (%s) error writing to ifch -> ndhc pipe: %s", suicide("%s: (%s) error writing to ifch -> ndhc socket: %s",
client_config.interface, __func__, strerror(errno)); client_config.interface, __func__, strerror(errno));
} }
static void process_client_pipe(void) static void process_client_socket(void)
{ {
char buf[MAX_BUF]; char buf[MAX_BUF];
@ -328,7 +324,7 @@ static void process_client_pipe(void)
} else if (r < 0) { } else if (r < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) if (errno == EAGAIN || errno == EWOULDBLOCK)
return; return;
suicide("%s: (%s) error reading from ndhc -> ifch pipe: %s", suicide("%s: (%s) error reading from ndhc -> ifch socket: %s",
client_config.interface, __func__, strerror(errno)); client_config.interface, __func__, strerror(errno));
} }
@ -368,7 +364,7 @@ static void do_ifch_work(void)
for (int i = 0; i < r; ++i) { for (int i = 0; i < r; ++i) {
int fd = events[i].data.fd; int fd = events[i].data.fd;
if (fd == ifchSock[1]) if (fd == ifchSock[1])
process_client_pipe(); process_client_socket();
else if (fd == signalFd) else if (fd == signalFd)
signal_dispatch(); signal_dispatch();
else else
@ -380,7 +376,7 @@ static void do_ifch_work(void)
void ifch_main(void) void ifch_main(void)
{ {
prctl(PR_SET_NAME, "ndhc: ifch"); prctl(PR_SET_NAME, "ndhc: ifch");
prctl(PR_SET_PDEATHSIG, SIGHUP);
umask(077); umask(077);
setup_signals_ifch(); setup_signals_ifch();
@ -401,7 +397,6 @@ void ifch_main(void)
memset(chroot_dir, '\0', sizeof chroot_dir); memset(chroot_dir, '\0', sizeof chroot_dir);
unsigned char keepcaps[] = { CAP_NET_ADMIN }; unsigned char keepcaps[] = { CAP_NET_ADMIN };
nk_set_uidgid(ifch_uid, ifch_gid, keepcaps, sizeof keepcaps); nk_set_uidgid(ifch_uid, ifch_gid, keepcaps, sizeof keepcaps);
do_ifch_work(); do_ifch_work();
} }

View File

@ -169,7 +169,6 @@ static void setup_signals_ndhc(void)
sigaddset(&mask, SIGUSR1); sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGUSR2); sigaddset(&mask, SIGUSR2);
sigaddset(&mask, SIGCHLD); sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGPIPE);
sigaddset(&mask, SIGTERM); sigaddset(&mask, SIGTERM);
if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
suicide("sigprocmask failed"); suicide("sigprocmask failed");
@ -205,10 +204,6 @@ static void signal_dispatch(void)
case SIGUSR2: case SIGUSR2:
force_release_action(&cs); force_release_action(&cs);
break; break;
case SIGPIPE:
log_line("ndhc-master: IPC pipe closed. Exiting.");
exit(EXIT_SUCCESS);
break;
case SIGCHLD: case SIGCHLD:
suicide("ndhc-master: Subprocess terminated unexpectedly. Exiting."); suicide("ndhc-master: Subprocess terminated unexpectedly. Exiting.");
break; break;
@ -278,7 +273,7 @@ static void handle_ifch_message(void)
} else if (r < 0) { } else if (r < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) if (errno == EAGAIN || errno == EWOULDBLOCK)
return; return;
suicide("%s: (%s) error reading from ifch -> ndhc pipe: %s", suicide("%s: (%s) error reading from ifch -> ndhc socket: %s",
client_config.interface, __func__, strerror(errno)); client_config.interface, __func__, strerror(errno));
} }
@ -367,54 +362,44 @@ char pidfile[PATH_MAX] = PID_FILE_DEFAULT;
uid_t ndhc_uid = 0; uid_t ndhc_uid = 0;
gid_t ndhc_gid = 0; gid_t ndhc_gid = 0;
int ifchSock[2]; int ifchSock[2];
int ifchPipe[2];
int sockdSock[2]; int sockdSock[2];
int sockdPipe[2];
static void create_ifch_ipc_pipes(void) { static void create_ifch_ipc_sockets(void) {
if (pipe(ifchPipe))
suicide("FATAL - can't create ndhc/ifch pipe: %s", strerror(errno));
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, ifchSock) < 0) if (socketpair(AF_UNIX, SOCK_DGRAM, 0, ifchSock) < 0)
suicide("FATAL - can't create ndhc/ifch socket: %s", strerror(errno)); suicide("FATAL - can't create ndhc/ifch socket: %s", strerror(errno));
} }
static void create_sockd_ipc_pipes(void) { static void create_sockd_ipc_sockets(void) {
if (pipe(sockdPipe))
suicide("FATAL - can't create ndhc/sockd pipe: %s", strerror(errno));
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockdSock) < 0) if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockdSock) < 0)
suicide("FATAL - can't create ndhc/sockd socket: %s", strerror(errno)); suicide("FATAL - can't create ndhc/sockd socket: %s", strerror(errno));
} }
static void spawn_ifch(void) static void spawn_ifch(void)
{ {
create_ifch_ipc_pipes(); create_ifch_ipc_sockets();
pid_t ifch_pid = fork(); pid_t ifch_pid = fork();
if (ifch_pid == 0) { if (ifch_pid == 0) {
close(ifchSock[0]); close(ifchSock[0]);
close(ifchPipe[0]);
// Don't share the RNG state with the master process. // Don't share the RNG state with the master process.
nk_random_u32_init(&cs.rnd32_state); nk_random_u32_init(&cs.rnd32_state);
ifch_main(); ifch_main();
} else if (ifch_pid > 0) { } else if (ifch_pid > 0) {
close(ifchSock[1]); close(ifchSock[1]);
close(ifchPipe[1]);
} else } else
suicide("failed to fork ndhc-ifch: %s", strerror(errno)); suicide("failed to fork ndhc-ifch: %s", strerror(errno));
} }
static void spawn_sockd(void) static void spawn_sockd(void)
{ {
create_sockd_ipc_pipes(); create_sockd_ipc_sockets();
pid_t sockd_pid = fork(); pid_t sockd_pid = fork();
if (sockd_pid == 0) { if (sockd_pid == 0) {
close(sockdSock[0]); close(sockdSock[0]);
close(sockdPipe[0]);
// Don't share the RNG state with the master process. // Don't share the RNG state with the master process.
nk_random_u32_init(&cs.rnd32_state); nk_random_u32_init(&cs.rnd32_state);
sockd_main(); sockd_main();
} else if (sockd_pid > 0) { } else if (sockd_pid > 0) {
close(sockdSock[1]); close(sockdSock[1]);
close(sockdPipe[1]);
} else } else
suicide("failed to fork ndhc-sockd: %s", strerror(errno)); suicide("failed to fork ndhc-sockd: %s", strerror(errno));
} }

View File

@ -61,7 +61,7 @@
#include "seccomp.h" #include "seccomp.h"
static int epollfd, signalFd; static int epollfd, signalFd;
/* Slots are for signalFd and the ndhc -> ifchd pipe. */ /* Slots are for signalFd and the ndhc -> ifchd socket. */
static struct epoll_event events[2]; static struct epoll_event events[2];
uid_t sockd_uid = 0; uid_t sockd_uid = 0;
@ -439,7 +439,6 @@ static void setup_signals_sockd(void)
{ {
sigset_t mask; sigset_t mask;
sigemptyset(&mask); sigemptyset(&mask);
sigaddset(&mask, SIGPIPE);
sigaddset(&mask, SIGUSR1); sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGUSR2); sigaddset(&mask, SIGUSR2);
sigaddset(&mask, SIGTSTP); sigaddset(&mask, SIGTSTP);
@ -474,10 +473,7 @@ static void signal_dispatch(void)
switch (si.ssi_signo) { switch (si.ssi_signo) {
case SIGINT: case SIGINT:
case SIGTERM: case SIGTERM:
exit(EXIT_SUCCESS); case SIGHUP:
break;
case SIGPIPE:
log_line("ndhc-sockd: IPC pipe closed. Exiting.");
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
break; break;
default: default:
@ -538,7 +534,8 @@ static size_t execute_sockd(char *buf, size_t buflen)
uint8_t client_mac[6]; uint8_t client_mac[6];
bool using_bpf; bool using_bpf;
if (buflen < 1 + sizeof client_addr + 6) if (buflen < 1 + sizeof client_addr + 6)
return 0; suicide("%s: (%s) 'd' does not have necessary arguments: %zu",
client_config.interface, __func__, buflen);
memcpy(&client_addr, buf + 1, sizeof client_addr); memcpy(&client_addr, buf + 1, sizeof client_addr);
memcpy(client_mac, buf + 1 + sizeof client_addr, 6); memcpy(client_mac, buf + 1 + sizeof client_addr, 6);
int fd = create_arp_defense_socket(client_addr, client_mac, int fd = create_arp_defense_socket(client_addr, client_mac,
@ -550,7 +547,8 @@ static size_t execute_sockd(char *buf, size_t buflen)
case 'u': { case 'u': {
uint32_t client_addr; uint32_t client_addr;
if (buflen < 1 + sizeof client_addr) if (buflen < 1 + sizeof client_addr)
return 0; suicide("%s: (%s) 'u' does not have necessary arguments: %zu",
client_config.interface, __func__, buflen);
memcpy(&client_addr, buf + 1, sizeof client_addr); memcpy(&client_addr, buf + 1, sizeof client_addr);
xfer_fd(create_udp_send_socket(client_addr), 'u'); xfer_fd(create_udp_send_socket(client_addr), 'u');
return 5; return 5;
@ -560,7 +558,7 @@ static size_t execute_sockd(char *buf, size_t buflen)
} }
} }
static void process_client_pipe(void) static void process_client_socket(void)
{ {
static char buf[MAX_BUF]; static char buf[MAX_BUF];
static size_t buflen; static size_t buflen;
@ -577,7 +575,7 @@ static void process_client_pipe(void)
} else if (r < 0) { } else if (r < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) if (errno == EAGAIN || errno == EWOULDBLOCK)
return; return;
suicide("%s: (%s) error reading from ndhc -> sockd pipe: %s", suicide("%s: (%s) error reading from ndhc -> sockd socket: %s",
client_config.interface, __func__, strerror(errno)); client_config.interface, __func__, strerror(errno));
} }
buflen += (size_t)r; buflen += (size_t)r;
@ -607,7 +605,7 @@ static void do_sockd_work(void)
for (int i = 0; i < r; ++i) { for (int i = 0; i < r; ++i) {
int fd = events[i].data.fd; int fd = events[i].data.fd;
if (fd == sockdSock[1]) if (fd == sockdSock[1])
process_client_pipe(); process_client_socket();
else if (fd == signalFd) else if (fd == signalFd)
signal_dispatch(); signal_dispatch();
else else
@ -619,6 +617,7 @@ static void do_sockd_work(void)
void sockd_main(void) void sockd_main(void)
{ {
prctl(PR_SET_NAME, "ndhc: sockd"); prctl(PR_SET_NAME, "ndhc: sockd");
prctl(PR_SET_PDEATHSIG, SIGHUP);
umask(077); umask(077);
setup_signals_sockd(); setup_signals_sockd();
nk_set_chroot(chroot_dir); nk_set_chroot(chroot_dir);