diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2022-01-16 02:12:02 +0000 |
---|---|---|
committer | Laurent Bercot <ska@appnovation.com> | 2022-01-16 02:12:02 +0000 |
commit | 2588893b126bb596733b508114a5380839a3df72 (patch) | |
tree | 4c4f7b23e78573d4485e6c7407506f463ccc9425 /src/init | |
parent | f61cc5fc0f2e7f6dd042aeea20e3107b689c703d (diff) | |
download | s6-linux-init-2588893b126bb596733b508114a5380839a3df72.tar.xz |
ctty-passing doesn't look satanic anymore, thx Leah
Signed-off-by: Laurent Bercot <ska@appnovation.com>
Diffstat (limited to 'src/init')
-rw-r--r-- | src/init/s6-linux-init.c | 99 |
1 files changed, 22 insertions, 77 deletions
diff --git a/src/init/s6-linux-init.c b/src/init/s6-linux-init.c index 2cf3c09..c7873be 100644 --- a/src/init/s6-linux-init.c +++ b/src/init/s6-linux-init.c @@ -87,12 +87,24 @@ static void kbspecials (void) strerr_warnwu1sys("trap ctrl-alt-del") ; } -static inline void run_stage2 (char const *basedir, char const **argv, unsigned int argc, char const *const *envp, size_t envlen, char const *modifs, size_t modiflen, char const *initdefault) +static inline void run_stage2 (char const *basedir, char const **argv, unsigned int argc, char const *const *envp, size_t envlen, char const *modifs, size_t modiflen, char const *initdefault, char const *tty) { size_t dirlen = strlen(basedir) ; char const *childargv[argc + 3] ; char fn[dirlen + sizeof("/scripts/" STAGE2)] ; PROG = "s6-linux-init (child)" ; + + if (setsid() == -1) strerr_diefu1sys(111, "setsid") ; + if (tty) + { + int fd = openb_read(tty) ; + if (fd == -1) strerr_warnwu2sys("open ", tty) ; + else if (fd_move(0, fd) == -1) + { + strerr_warnwu3sys("make ", tty, " into new stdin") ; + close(fd) ; + } + } memcpy(fn, basedir, dirlen) ; memcpy(fn + dirlen, "/scripts/" STAGE2, sizeof("/scripts/" STAGE2)) ; childargv[0] = fn ; @@ -117,79 +129,6 @@ static inline void run_stage2 (char const *basedir, char const **argv, unsigned xmexec_fm(childargv, envp, envlen, modifs, modiflen) ; } -/* - This is ugly voodoo, keep away from innocent eyes. - If ttyfd exists, it means we're in a "docker run -it" container or -equivalent, and tty (name of the original stdin) is a ctty. We don't -want the supervision tree to have this ctty (else ^C kills everything) -but we want stage 2 to keep it if possible, so that if we have a CMD run -by stage 2 (as is the case with s6-overlay), it remains interactive, i.e. -control sequences can be sent to it. - We cannot have the child (future stage 2) steal the ctty from the parent -(future s6-svscan) via TIOCSCTTY because we may not have the permissions for -it: Docker containers don't give CAP_SYS_ADMIN to pid 1, and user containers -are a thing. - So instead, we have the parent relinquish the ctty, then the child reopen -it - which makes it a ctty for the child. This requires /dev/pts to be -pre-mounted, but that's usually the case. Even if it's not, the child doesn't -get its ctty, but at least the parent doesn't have it anymore. - Pipes are used for synchronization. -*/ - -static inline pid_t fork_and_setup_session (char const *tty) -{ - pid_t pid ; - if (!tty) - { - pid = fork() ; - if (pid == -1) strerr_diefu1sys(111, "fork") ; - setsid() ; - } - else - { - int p[2][2] ; - int r ; - char c ; - if (pipe(p[0]) == -1 || pipe(p[1])) strerr_diefu1sys(111, "pipe") ; - pid = fork() ; - if (pid == -1) strerr_diefu1sys(111, "fork") ; - if (pid) - { - close(p[0][1]) ; - close(p[1][0]) ; - r = read(p[0][0], &c, 1) ; - if (r == -1) strerr_diefu2sys(111, "read from ", "child") ; - if (!r) strerr_dief2x(111, "child", " died") ; - close(p[0][0]) ; - if (ioctl(1, TIOCNOTTY) == -1) strerr_warnwu1sys("relinquish controlling terminal") ; - if (write(p[1][1], "", 1) < 1) strerr_diefu2sys(111, "write to ", "child") ; - close(p[1][1]) ; - } - else - { - int fd ; - PROG = "s6-linux-init (child)" ; - close(p[1][1]) ; - close(p[0][0]) ; - if (setsid() == -1) strerr_diefu1sys(111, "setsid") ; - if (write(p[0][1], "", 1) < 1) strerr_diefu2sys(111, "write to ", "parent") ; - close(p[0][1]) ; - r = read(p[1][0], &c, 1) ; - if (r == -1) strerr_diefu2sys(111, "read from ", "parent") ; - if (!r) strerr_dief2x(111, "parent", " died") ; - close(p[1][0]) ; - fd = openb_read(tty) ; - if (fd == -1) strerr_warnwu2sys("open ", tty) ; - else if (fd_move(0, fd) == -1) - { - strerr_warnwu3sys("make ", tty, " into new stdin") ; - close(fd) ; - } - } - } - return pid ; -} - int main (int argc, char const **argv, char const *const *envp) { mode_t mask = 0022 ; @@ -238,7 +177,7 @@ int main (int argc, char const **argv, char const *const *envp) if (inns) { char c ; - ssize_t r = read(3, &c, 1) ; + ssize_t r = read(3, &c, 1) ; /* Docker synchronization protocol */ if (r < 0) { if (errno != EBADF) strerr_diefu1sys(111, "read from fd 3") ; @@ -333,6 +272,7 @@ int main (int argc, char const **argv, char const *const *envp) } { + pid_t pid ; char const *newenvp[2] = { 0, 0 } ; size_t pathlen = path ? strlen(path) : 0 ; char fmtfd[2 + UINT_FMT] = "-" ; @@ -347,8 +287,13 @@ int main (int argc, char const **argv, char const *const *envp) newenvp[0] = pathvar ; } if (nologger && pipe(notifpipe) < 0) strerr_diefu1sys(111, "pipe") ; - if (!fork_and_setup_session(tty)) - run_stage2(basedir, argv, argc, newenvp, !!path, envmodifs.s, envmodifs.len, initdefault) ; + if (tty && ioctl(1, TIOCNOTTY) == -1) strerr_warnwu1sys("relinquish control terminal") ; + + pid = fork() ; + if (pid == -1) strerr_diefu1sys(111, "fork") ; + if (!pid) run_stage2(basedir, argv, argc, newenvp, !!path, envmodifs.s, envmodifs.len, initdefault, tty) ; + + setsid() ; /* just in case our caller is something weird */ if (nologger) { close(notifpipe[0]) ; |