From 272f112c98deacf1cb88e3cb8f64cc5b64aca6fb Mon Sep 17 00:00:00 2001 From: Jesse Smith Date: Tue, 17 Apr 2018 19:44:50 -0300 Subject: [PATCH] Added new signal handler for SIGUSR2. When init receives SIGUSR2 it closes (and leaves closed) the named pipe /run/initctl. This can be used to make sure init does not have any files open. However, it also means we cannot switch run levels or bring down the system. The pipe can be re-opened by sending init the SIGUSR1 signal. Updated the man pages for initctl and init to include this information. --- doc/Changelog | 5 +++++ man/init.8 | 7 +++++++ man/initctl.5 | 12 ++++++++++++ src/init.c | 23 +++++++++++++++++++---- 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/doc/Changelog b/doc/Changelog index 8d8c811..f39fcfb 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -18,6 +18,11 @@ sysvinit (2.90) UNRELEASED; urgency=low * Added check that named pipe is open before trying to close it when something goes wrong or we receive SIGUSER1. Avoids potential crash if we receive SIGUSR1 while pipe is not open. + * Added new signal handler for SIGUSR2. When init receives SIGUSR2 + it closes (and leaves closed) the named pipe /run/initctl. This + can be used to make sure init does not have any files open. However, + it also means we cannot switch run levels or bring down the system. + The pipe can be re-opened by sending init the SIGUSR1 signal. sysvinit (2.89) world; urgency=low diff --git a/man/init.8 b/man/init.8 index 2adc1a2..2741595 100644 --- a/man/init.8 +++ b/man/init.8 @@ -264,6 +264,13 @@ Has the same effect as \fBtelinit q\fP. On receipt of this signals, init closes and re-opens its control fifo, \fB/run/initctl\fP. Useful for bootscripts when /dev is remounted. .TP 0.5i +.B SIGUSR2 +When init receives SIGUSR2, init closes and leaves the control fifo, +\fB/run/initctl\f\P, closed. This may be used to make sure init is not +holding open any files. However, it also prevents init from switching +runlevels. Which means commands like shutdown no longer work. +The fifo can be re-opened by sending init the SIGUSR1 signal. +.TP 0.5i .B SIGINT Normally the kernel sends this signal to init when CTRL-ALT-DEL is pressed. It activates the \fIctrlaltdel\fP action. diff --git a/man/initctl.5 b/man/initctl.5 index d8a435c..f736c23 100644 --- a/man/initctl.5 +++ b/man/initctl.5 @@ -128,6 +128,18 @@ The commands passed through the /run/initctl pipe must be sent in a specific binary format and be of a specific length. Larger data structures or ones not using the proper format will be ignored. Typically, only root has the ability to write to the initctl pipe for security reasons. +.PP +The /run/initctl pipe can be closed by sending init (PID 1) the SIGUSR2 +signal. This closes the pipe and leaves it closed. This may be useful +for making sure init is not keeping any files open. However, when the +pipe is closed, init no longer receives signals, such as those sent by +shutdown or telinit. In other words if we close the pipe, init cannot +change its runlevel directly. The pipe may be re-opened by sending init (PID 1) +the SIGUSR1 signal. +.PP +If the /run/initctl pipe is closed then it may still be possible to bring +down the system using the shutdown command's -n flag, but this is not +always clean and not recommended. .RE .SH FILES /run/initctl diff --git a/src/init.c b/src/init.c index feb384d..a3e0276 100644 --- a/src/init.c +++ b/src/init.c @@ -1116,7 +1116,11 @@ pid_t spawn(CHILD *ch, int *res) close(0); close(1); close(2); - if (pipe_fd >= 0) close(pipe_fd); + if (pipe_fd >= 0) + { + close(pipe_fd); + pipe_fd = -1; + } sigprocmask(SIG_SETMASK, &omask, NULL); @@ -2172,6 +2176,7 @@ void re_exec(void) DELSET(got_signals, SIGCHLD); DELSET(got_signals, SIGHUP); DELSET(got_signals, SIGUSR1); + DELSET(got_signals, SIGUSR2); /* * That should be cleaned. @@ -2368,9 +2373,10 @@ void check_init_fifo(void) } /* - * Now finally try to open /run/initctl + * Now finally try to open /run/initctl if pipe_fd is -1 + * if it is -2, then we leave it closed */ - if (pipe_fd < 0) { + if (pipe_fd == -1) { if ((pipe_fd = open(INIT_FIFO, O_RDWR|O_NONBLOCK)) >= 0) { fstat(pipe_fd, &st); if (!S_ISFIFO(st.st_mode)) { @@ -2471,7 +2477,7 @@ void check_init_fifo(void) /* * We come here if the pipe couldn't be opened. */ - if (pipe_fd < 0) pause(); + if (pipe_fd == -1) pause(); } @@ -2682,6 +2688,14 @@ void process_signals() pipe_fd = -1; DELSET(got_signals, SIGUSR1); } + else if (ISMEMBER(got_signals, SIGUSR2)) { + /* SIGUSR1 mean close the pipe and leave it closed */ + INITDBG(L_VB, "got SIGUSR2"); + if (pipe_fd) + close(pipe_fd); + pipe_fd = -2; + DELSET(got_signals, SIGUSR2); + } } /* @@ -2740,6 +2754,7 @@ void init_main(void) SETSIG(sa, SIGPWR, signal_handler, 0); SETSIG(sa, SIGWINCH, signal_handler, 0); SETSIG(sa, SIGUSR1, signal_handler, 0); + SETSIG(sa, SIGUSR2, signal_handler, 0); SETSIG(sa, SIGSTOP, stop_handler, SA_RESTART); SETSIG(sa, SIGTSTP, stop_handler, SA_RESTART); SETSIG(sa, SIGCONT, cont_handler, SA_RESTART);