Make the signal handling code use safe_read() and unify ifchd and sockd
signals code.
This commit is contained in:
		
							
								
								
									
										55
									
								
								src/ifchd.c
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								src/ifchd.c
									
									
									
									
									
								
							| @@ -35,13 +35,11 @@ | |||||||
| #include <sys/time.h> | #include <sys/time.h> | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| #include <sys/epoll.h> | #include <sys/epoll.h> | ||||||
| #include <sys/signalfd.h> |  | ||||||
| #include <sys/prctl.h> | #include <sys/prctl.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
| #include <signal.h> | #include <signal.h> | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
| #include <getopt.h> |  | ||||||
| #include "nk/log.h" | #include "nk/log.h" | ||||||
| #include "nk/privilege.h" | #include "nk/privilege.h" | ||||||
| #include "nk/signals.h" | #include "nk/signals.h" | ||||||
| @@ -256,51 +254,6 @@ void perform_wins(const char *str, size_t len) | |||||||
|     (void)len; |     (void)len; | ||||||
| } | } | ||||||
|  |  | ||||||
| static void setup_signals_ifch(void) |  | ||||||
| { |  | ||||||
|     sigset_t mask; |  | ||||||
|     sigemptyset(&mask); |  | ||||||
|     sigaddset(&mask, SIGUSR1); |  | ||||||
|     sigaddset(&mask, SIGUSR2); |  | ||||||
|     sigaddset(&mask, SIGTSTP); |  | ||||||
|     sigaddset(&mask, SIGTTIN); |  | ||||||
|     sigaddset(&mask, SIGCHLD); |  | ||||||
|     sigaddset(&mask, SIGHUP); |  | ||||||
|     sigaddset(&mask, SIGINT); |  | ||||||
|     sigaddset(&mask, SIGTERM); |  | ||||||
|     if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) |  | ||||||
|         suicide("sigprocmask failed"); |  | ||||||
|     signalFd = signalfd(-1, &mask, SFD_NONBLOCK); |  | ||||||
|     if (signalFd < 0) |  | ||||||
|         suicide("signalfd failed"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void signal_dispatch(void) |  | ||||||
| { |  | ||||||
|     int t; |  | ||||||
|     size_t off = 0; |  | ||||||
|     struct signalfd_siginfo si = {0}; |  | ||||||
|   again: |  | ||||||
|     t = read(signalFd, (char *)&si + off, sizeof si - off); |  | ||||||
|     if (t < 0) { |  | ||||||
|         if (t == EAGAIN || t == EWOULDBLOCK || t == EINTR) |  | ||||||
|             goto again; |  | ||||||
|         else |  | ||||||
|             suicide("signalfd read error"); |  | ||||||
|     } |  | ||||||
|     if (off + (unsigned)t < sizeof si) |  | ||||||
|         off += t; |  | ||||||
|     switch (si.ssi_signo) { |  | ||||||
|         case SIGINT: |  | ||||||
|         case SIGTERM: |  | ||||||
|         case SIGHUP: |  | ||||||
|             exit(EXIT_SUCCESS); |  | ||||||
|             break; |  | ||||||
|         default: |  | ||||||
|             break; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void inform_execute(char c) | static void inform_execute(char c) | ||||||
| { | { | ||||||
|     ssize_t r = safe_write(ifchSock[1], &c, sizeof c); |     ssize_t r = safe_write(ifchSock[1], &c, sizeof c); | ||||||
| @@ -366,7 +319,7 @@ static void do_ifch_work(void) | |||||||
|             if (fd == ifchSock[1]) |             if (fd == ifchSock[1]) | ||||||
|                 process_client_socket(); |                 process_client_socket(); | ||||||
|             else if (fd == signalFd) |             else if (fd == signalFd) | ||||||
|                 signal_dispatch(); |                 signal_dispatch_subprocess(signalFd, "ifch"); | ||||||
|             else |             else | ||||||
|                 suicide("ifch: unexpected fd while performing epoll"); |                 suicide("ifch: unexpected fd while performing epoll"); | ||||||
|         } |         } | ||||||
| @@ -376,9 +329,11 @@ 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); |     if (prctl(PR_SET_PDEATHSIG, SIGHUP) < 0) | ||||||
|  |         suicide("%s: (%s) prctl(PR_SET_PDEATHSIG) failed: %s", | ||||||
|  |                 client_config.interface, __func__, strerror(errno)); | ||||||
|     umask(077); |     umask(077); | ||||||
|     setup_signals_ifch(); |     signalFd = setup_signals_subprocess(); | ||||||
|  |  | ||||||
|     // If we are requested to update resolv.conf, preopen the fd before |     // If we are requested to update resolv.conf, preopen the fd before | ||||||
|     // we drop root privileges, making sure that if we create |     // we drop root privileges, making sure that if we create | ||||||
|   | |||||||
							
								
								
									
										32
									
								
								src/ndhc.c
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								src/ndhc.c
									
									
									
									
									
								
							| @@ -184,26 +184,21 @@ static void setup_signals_ndhc(void) | |||||||
|  |  | ||||||
| static void signal_dispatch(void) | static void signal_dispatch(void) | ||||||
| { | { | ||||||
|     int t; |  | ||||||
|     size_t off = 0; |  | ||||||
|     struct signalfd_siginfo si = {0}; |     struct signalfd_siginfo si = {0}; | ||||||
|   again: |     ssize_t r = safe_read(cs.signalFd, (char *)&si, sizeof si); | ||||||
|     t = read(cs.signalFd, (char *)&si + off, sizeof si - off); |     if (r < 0) { | ||||||
|     if (t < 0) { |         log_error("%s: ndhc: error reading from signalfd: %s", | ||||||
|         if (t == EAGAIN || t == EWOULDBLOCK || t == EINTR) |                   client_config.interface, strerror(errno)); | ||||||
|             goto again; |         return; | ||||||
|         else |     } | ||||||
|             suicide("signalfd read error"); |     if ((size_t)r < sizeof si) { | ||||||
|  |         log_error("%s: ndhc: short read from signalfd: %zd < %zu", | ||||||
|  |                   client_config.interface, r, sizeof si); | ||||||
|  |         return; | ||||||
|     } |     } | ||||||
|     if (off + (unsigned)t < sizeof si) |  | ||||||
|         off += t; |  | ||||||
|     switch (si.ssi_signo) { |     switch (si.ssi_signo) { | ||||||
|         case SIGUSR1: |         case SIGUSR1: force_renew_action(&cs); break; | ||||||
|             force_renew_action(&cs); |         case SIGUSR2: force_release_action(&cs); break; | ||||||
|             break; |  | ||||||
|         case SIGUSR2: |  | ||||||
|             force_release_action(&cs); |  | ||||||
|             break; |  | ||||||
|         case SIGCHLD: |         case SIGCHLD: | ||||||
|             suicide("ndhc-master: Subprocess terminated unexpectedly.  Exiting."); |             suicide("ndhc-master: Subprocess terminated unexpectedly.  Exiting."); | ||||||
|             break; |             break; | ||||||
| @@ -211,8 +206,7 @@ static void signal_dispatch(void) | |||||||
|             log_line("Received SIGTERM.  Exiting gracefully."); |             log_line("Received SIGTERM.  Exiting gracefully."); | ||||||
|             exit(EXIT_SUCCESS); |             exit(EXIT_SUCCESS); | ||||||
|             break; |             break; | ||||||
|         default: |         default: break; | ||||||
|             break; |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										56
									
								
								src/sockd.c
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								src/sockd.c
									
									
									
									
									
								
							| @@ -36,7 +36,6 @@ | |||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
| #include <assert.h> | #include <assert.h> | ||||||
| #include <sys/socket.h> | #include <sys/socket.h> | ||||||
| #include <sys/signalfd.h> |  | ||||||
| #include <sys/epoll.h> | #include <sys/epoll.h> | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| @@ -434,53 +433,6 @@ static int create_arp_basic_socket(bool *using_bpf) | |||||||
|     return fd; |     return fd; | ||||||
| } | } | ||||||
|  |  | ||||||
| // XXX: Can share with ifch |  | ||||||
| static void setup_signals_sockd(void) |  | ||||||
| { |  | ||||||
|     sigset_t mask; |  | ||||||
|     sigemptyset(&mask); |  | ||||||
|     sigaddset(&mask, SIGUSR1); |  | ||||||
|     sigaddset(&mask, SIGUSR2); |  | ||||||
|     sigaddset(&mask, SIGTSTP); |  | ||||||
|     sigaddset(&mask, SIGTTIN); |  | ||||||
|     sigaddset(&mask, SIGCHLD); |  | ||||||
|     sigaddset(&mask, SIGHUP); |  | ||||||
|     sigaddset(&mask, SIGINT); |  | ||||||
|     sigaddset(&mask, SIGTERM); |  | ||||||
|     if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) |  | ||||||
|         suicide("sigprocmask failed"); |  | ||||||
|     signalFd = signalfd(-1, &mask, SFD_NONBLOCK); |  | ||||||
|     if (signalFd < 0) |  | ||||||
|         suicide("signalfd failed"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // XXX: Can share with ifch |  | ||||||
| static void signal_dispatch(void) |  | ||||||
| { |  | ||||||
|     int t; |  | ||||||
|     size_t off = 0; |  | ||||||
|     struct signalfd_siginfo si = {0}; |  | ||||||
|   again: |  | ||||||
|     t = read(signalFd, (char *)&si + off, sizeof si - off); |  | ||||||
|     if (t < 0) { |  | ||||||
|         if (t == EAGAIN || t == EWOULDBLOCK || t == EINTR) |  | ||||||
|             goto again; |  | ||||||
|         else |  | ||||||
|             suicide("signalfd read error"); |  | ||||||
|     } |  | ||||||
|     if (off + (unsigned)t < sizeof si) |  | ||||||
|         off += t; |  | ||||||
|     switch (si.ssi_signo) { |  | ||||||
|         case SIGINT: |  | ||||||
|         case SIGTERM: |  | ||||||
|         case SIGHUP: |  | ||||||
|             exit(EXIT_SUCCESS); |  | ||||||
|             break; |  | ||||||
|         default: |  | ||||||
|             break; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void xfer_fd(int fd, char cmd) | static void xfer_fd(int fd, char cmd) | ||||||
| { | { | ||||||
|     char control[sizeof(struct cmsghdr) + 10]; |     char control[sizeof(struct cmsghdr) + 10]; | ||||||
| @@ -607,7 +559,7 @@ static void do_sockd_work(void) | |||||||
|             if (fd == sockdSock[1]) |             if (fd == sockdSock[1]) | ||||||
|                 process_client_socket(); |                 process_client_socket(); | ||||||
|             else if (fd == signalFd) |             else if (fd == signalFd) | ||||||
|                 signal_dispatch(); |                 signal_dispatch_subprocess(signalFd, "sockd"); | ||||||
|             else |             else | ||||||
|                 suicide("sockd: unexpected fd while performing epoll"); |                 suicide("sockd: unexpected fd while performing epoll"); | ||||||
|         } |         } | ||||||
| @@ -617,9 +569,11 @@ 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); |     if (prctl(PR_SET_PDEATHSIG, SIGHUP) < 0) | ||||||
|  |         suicide("%s: (%s) prctl(PR_SET_PDEATHSIG) failed: %s", | ||||||
|  |                 client_config.interface, __func__, strerror(errno)); | ||||||
|     umask(077); |     umask(077); | ||||||
|     setup_signals_sockd(); |     signalFd = setup_signals_subprocess(); | ||||||
|     nk_set_chroot(chroot_dir); |     nk_set_chroot(chroot_dir); | ||||||
|     memset(chroot_dir, 0, sizeof chroot_dir); |     memset(chroot_dir, 0, sizeof chroot_dir); | ||||||
|     unsigned char keepcaps[] = { CAP_NET_BIND_SERVICE, CAP_NET_BROADCAST, |     unsigned char keepcaps[] = { CAP_NET_BIND_SERVICE, CAP_NET_BROADCAST, | ||||||
|   | |||||||
							
								
								
									
										44
									
								
								src/sys.c
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								src/sys.c
									
									
									
									
									
								
							| @@ -26,12 +26,16 @@ | |||||||
|  * POSSIBILITY OF SUCH DAMAGE. |  * POSSIBILITY OF SUCH DAMAGE. | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
|  | #include <signal.h> | ||||||
| #include <sys/epoll.h> | #include <sys/epoll.h> | ||||||
| #include <sys/signalfd.h> | #include <sys/signalfd.h> | ||||||
| #include "nk/log.h" | #include "nk/log.h" | ||||||
|  | #include "nk/io.h" | ||||||
|  | #include "ndhc.h" | ||||||
| #include "sys.h" | #include "sys.h" | ||||||
|  |  | ||||||
| void epoll_add(int epfd, int fd) | void epoll_add(int epfd, int fd) | ||||||
| @@ -55,3 +59,41 @@ void epoll_del(int epfd, int fd) | |||||||
|     if (r < 0) |     if (r < 0) | ||||||
|         suicide("epoll_del failed %s", strerror(errno)); |         suicide("epoll_del failed %s", strerror(errno)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int setup_signals_subprocess(void) | ||||||
|  | { | ||||||
|  |     sigset_t mask; | ||||||
|  |     sigemptyset(&mask); | ||||||
|  |     sigaddset(&mask, SIGHUP); | ||||||
|  |     sigaddset(&mask, SIGINT); | ||||||
|  |     sigaddset(&mask, SIGTERM); | ||||||
|  |     if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) | ||||||
|  |         suicide("sigprocmask failed"); | ||||||
|  |     int sfd = signalfd(-1, &mask, SFD_NONBLOCK); | ||||||
|  |     if (sfd < 0) | ||||||
|  |         suicide("signalfd failed"); | ||||||
|  |     return sfd; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void signal_dispatch_subprocess(int sfd, const char *pname) | ||||||
|  | { | ||||||
|  |     struct signalfd_siginfo si = {0}; | ||||||
|  |     ssize_t r = safe_read(sfd, (char *)&si, sizeof si); | ||||||
|  |     if (r < 0) { | ||||||
|  |         log_error("%s: %s: error reading from signalfd: %s", | ||||||
|  |                   client_config.interface, pname, strerror(errno)); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     if ((size_t)r < sizeof si) { | ||||||
|  |         log_error("%s: %s: short read from signalfd: %zd < %zu", | ||||||
|  |                   client_config.interface, pname, r, sizeof si); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     switch (si.ssi_signo) { | ||||||
|  |         case SIGINT: | ||||||
|  |         case SIGTERM: | ||||||
|  |         case SIGHUP: exit(EXIT_SUCCESS); break; | ||||||
|  |         default: break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -46,4 +46,8 @@ static inline size_t min_size_t(size_t a, size_t b) | |||||||
| void epoll_add(int epfd, int fd); | void epoll_add(int epfd, int fd); | ||||||
| void epoll_del(int epfd, int fd); | void epoll_del(int epfd, int fd); | ||||||
|  |  | ||||||
|  | int setup_signals_subprocess(void); | ||||||
|  | void signal_dispatch_subprocess(int sfd, const char *pname); | ||||||
|  |  | ||||||
| #endif /* SYS_H_ */ | #endif /* SYS_H_ */ | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user