Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F141994918
D46440.id142442.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D46440.id142442.diff
View Options
diff --git a/sbin/init/init.8 b/sbin/init/init.8
--- a/sbin/init/init.8
+++ b/sbin/init/init.8
@@ -28,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 22, 2021
+.Dd August 10, 2024
.Dt INIT 8
.Os
.Sh NAME
@@ -112,19 +112,6 @@
.Va kern.securelevel
variable to the required security level.
.Pp
-If
-.Nm
-is run in a jail, the security level of the
-.Dq host system
-will not be affected.
-Part of the information set up in the kernel to support a jail
-is a per-jail security level.
-This allows running a higher security level inside of a jail
-than that of the host system.
-See
-.Xr jail 8
-for more information about jails.
-.Pp
In multi-user operation,
.Nm
maintains
@@ -396,6 +383,66 @@
.Pa /etc/rc
script is executed with the standard shell
.Pa /bin/sh .
+.El
+.Sh JAIL SUPPORT
+.Nm
+can run in a
+.Xr jail 8
+environment to emulate a bootstrap of another userland environment
+with
+.Xr rc 8
+scripts and the same directory structure as the root filesystem.
+.Pp
+While the behavior of
+.Nm
+is basically the same as the host environment,
+there are several differences.
+.Nm
+will have a process id other than
+.Li 1
+and never enter the single-user mode even if it terminates abnormally
+in a jail.
+.Va STDOUT
+and
+.Va STDERR
+will be used instead of opening the system console device for logging.
+All of the
+.Xr kenv 1
+variables described in the previous section will be ignored in a jail.
+.Pp
+Upon invoked,
+.Nm
+will fork and wait until the
+.Xr rc 8
+script runs.
+After the script ends successfully,
+the parent process of
+.Nm
+terminates and the child process continues
+to handle
+.Xr ttys 5
+as a background process.
+The
+.Xr jail 8
+command blocks until the jailed environment runs the
+.Xr rc 8
+script and enters the
+.Dq emulated
+multi-user mode.
+.Pp
+If
+.Nm
+runs in a jail,
+the security level of the
+.Dq host system
+will not be affected.
+Part of the information set up in the kernel to support a jail
+is a per-jail security level.
+This allows running a higher security level inside of a jail
+than that of the host system.
+See
+.Xr jail 8
+for more information about jails.
.Sh FILES
.Bl -tag -width /var/log/init.log -compact
.It Pa /dev/console
@@ -451,6 +498,9 @@
.Nm
utility appeared in
.At v1 .
+.Xr jail 8
+support was first appeared in
+.Fx 15.0 .
.Sh CAVEATS
Systems without
.Xr sysctl 8
diff --git a/sbin/init/init.c b/sbin/init/init.c
--- a/sbin/init/init.c
+++ b/sbin/init/init.c
@@ -38,6 +38,7 @@
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/reboot.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/uio.h>
@@ -56,6 +57,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sysexits.h>
#include <syslog.h>
#include <time.h>
#include <ttyent.h>
@@ -183,6 +185,11 @@
static session_t *find_session(pid_t);
static DB *session_db;
+static int jailed;
+static int sv[2] = {-1, -1};
+#define SV_RECV 0
+#define SV_SEND 1
+
/*
* The mother of all processes.
*/
@@ -201,8 +208,12 @@
BOOTTRACE("init(8) starting...");
+ /* Check if init(8) is invoked in a jail. */
+ (void) sysctlbyname("security.jail.jailed", &jailed,
+ &(size_t){ sizeof(jailed) }, NULL, 0);
+
/* System V users like to reexec init. */
- if (getpid() != 1) {
+ if (jailed == 0 && getpid() != 1) {
#ifdef COMPAT_SYSV_INIT
/* So give them what they want */
if (argc > 1) {
@@ -250,7 +261,7 @@
* Note that this does NOT open a file...
* Does 'init' deserve its own facility number?
*/
- openlog("init", LOG_CONS, LOG_AUTH);
+ openlog("init", (jailed) ? LOG_PERROR : LOG_CONS, LOG_AUTH);
/*
* Create an initial session.
@@ -315,22 +326,31 @@
* Paranoia.
*/
close(0);
- close(1);
- close(2);
+ if (jailed == 0) {
+ /*
+ * Keep stdout and stderr open in jail
+ * in order to deliver console messages.
+ */
+ close(1);
+ close(2);
+ }
- if (kenv(KENV_GET, "init_exec", kenv_value, sizeof(kenv_value)) > 0) {
+ if (jailed == 0 &&
+ kenv(KENV_GET, "init_exec", kenv_value, sizeof(kenv_value)) > 0) {
replace_init(kenv_value);
_exit(0); /* reboot */
}
- if (kenv(KENV_GET, "init_script", kenv_value, sizeof(kenv_value)) > 0) {
+ if (jailed == 0 &&
+ kenv(KENV_GET, "init_script", kenv_value, sizeof(kenv_value)) > 0) {
state_func_t next_transition;
if ((next_transition = run_script(kenv_value)) != NULL)
initial_transition = (state_t) next_transition;
}
- if (kenv(KENV_GET, "init_chroot", kenv_value, sizeof(kenv_value)) > 0) {
+ if (jailed == 0 &&
+ kenv(KENV_GET, "init_chroot", kenv_value, sizeof(kenv_value)) > 0) {
if (chdir(kenv_value) != 0 || chroot(".") != 0)
warning("Can't chroot to %s: %m", kenv_value);
}
@@ -388,7 +408,8 @@
free(s);
}
- if (initial_transition != reroot_phase_two) {
+ if (jailed == 0 &&
+ initial_transition != reroot_phase_two) {
/*
* Unmount reroot leftovers. This runs after init(8)
* gets reexecuted after reroot_phase_two() is done.
@@ -398,6 +419,77 @@
warning("Cannot unmount %s: %m", _PATH_REROOT);
}
+ if (jailed) {
+ pid_t pid;
+ /*
+ * The init(8) process will never terminate on the host
+ * environment. Inside a jail, it needs to run as a
+ * background process because the jail(8) utility needs to
+ * finish. To do this, it calls fork() and the child
+ * process will handle the original functions of init(8).
+ *
+ * The child process runs the rc(8) script, reads
+ * /etc/ttys to watch the terminal ports, and stays in the
+ * background. However, the parent process does not terminate
+ * immediately to emulate the blocking behavior until
+ * entering the multi-user mode (starting the state machine)
+ * in the host environment. The below socketpair is used
+ * to send a notification from the child after running
+ * the rc(8) script successfully to block the jail(8)
+ * utility that invoked /sbin/init.
+ * Data in sizeof(int) are used as the frame for this
+ * socketpair and the payload is a constant defined
+ * in sysexits.h.
+ *
+ */
+ error = socketpair(AF_LOCAL, SOCK_SEQPACKET | SOCK_CLOEXEC,
+ 0, sv);
+ if (error)
+ err(1, "socketpair");
+
+ pid = fork();
+ if (pid == -1)
+ err(1, "fork()");
+ else if (pid > 0) {
+ fd_set readfds;
+ ssize_t len;
+ int nfds, buf;
+
+ close(sv[SV_SEND]);
+ sv[SV_SEND] = -1;
+
+ /*
+ * The parent process waits until init(8) enters
+ * multi-user mode successfully.
+ */
+ FD_ZERO(&readfds);
+ nfds = sv[SV_RECV];
+ for (;;) {
+ FD_SET(sv[SV_RECV], &readfds);
+ error = select(nfds, &readfds, NULL, NULL,
+ &(struct timeval){0});
+ if (error && errno == EINTR)
+ continue;
+ if (error)
+ err(1, "select");
+ do {
+ len = read(sv[SV_RECV], &buf,
+ sizeof(buf));
+ } while (len < 0 && errno == EINTR);
+ if (len != sizeof(buf))
+ err(1, "invalid length: %zd", len);
+ switch (buf) {
+ case EX_OK:
+ case EX_SOFTWARE:
+ return (buf);
+ default:
+ warn("invalid notification: %d", buf);
+ }
+ }
+ }
+ close(sv[SV_RECV]);
+ sv[SV_RECV] = -1;
+ }
/*
* Start the state machine.
*/
@@ -609,6 +701,23 @@
}
dup2(STDOUT_FILENO, STDERR_FILENO);
}
+/*
+ * Close STDIN and use STDOUT and STDERR for console output for jail.
+ */
+static void
+open_console_jail(void)
+{
+ int fd;
+
+ if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
+ stall("cannot open null device.");
+ _exit(1);
+ }
+ if (fd != STDIN_FILENO) {
+ dup2(fd, STDIN_FILENO);
+ close(fd);
+ }
+}
static const char *
get_shell(void)
@@ -862,6 +971,16 @@
char altshell[128];
#endif
+ /* Notify abnormal termination. */
+ if (jailed && sv[SV_SEND] > 0) {
+ (void) send(sv[SV_SEND], &(int){EX_SOFTWARE}, sizeof(int), 0);
+ close(sv[SV_SEND]);
+ sv[SV_SEND] = -1;
+ }
+ /* In jail, init(8) terminates instead of entering single-user mode. */
+ if (jailed)
+ exit(1);
+
if (Reboot) {
/* Instead of going single user, let's reboot the machine */
BOOTTRACE("shutting down the system");
@@ -1041,7 +1160,11 @@
sigaction(SIGTSTP, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
- open_console();
+ /* Use stdout and stderr in jail. */
+ if (jailed == 0)
+ open_console();
+ else
+ open_console_jail();
sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL);
#ifdef LOGIN_CAP
@@ -1708,6 +1831,13 @@
requested_transition = 0;
+ /* Notify entering multi-user mode successfully. */
+ if (jailed && sv[SV_SEND] > 0) {
+ (void) send(sv[SV_SEND], &(int){EX_OK}, sizeof(int), 0);
+ close(sv[SV_SEND]);
+ sv[SV_SEND] = -1;
+ }
+
/*
* If the administrator has not set the security level to -1
* to indicate that the kernel should not run multiuser in secure
@@ -1901,6 +2031,10 @@
pid_t pid;
static const int death_sigs[2] = { SIGTERM, SIGKILL };
+ /* init(8) in jail terminates when receiving SIGTERM or SIGKILL. */
+ if (jailed)
+ exit(EXIT_SUCCESS);
+
revoke(_PATH_CONSOLE);
BOOTTRACE("start killing user processes");
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jan 15, 3:49 PM (11 h, 30 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27652839
Default Alt Text
D46440.id142442.diff (8 KB)
Attached To
Mode
D46440: init: Add jail(8) support
Attached
Detach File
Event Timeline
Log In to Comment