teknoraver / rpms / systemd

Forked from rpms/systemd 2 months ago
Clone

Blame SOURCES/17082_nspawn_tty_tweaks.patch

d0811f
From 0ead15331dc9414e7d4b3f0b96ed1908ceaf8f8b Mon Sep 17 00:00:00 2001
d0811f
From: Lennart Poettering <lennart@poettering.net>
d0811f
Date: Wed, 16 Sep 2020 22:11:48 +0200
d0811f
Subject: [PATCH 1/5] nspawn: check return of setsid()
d0811f
d0811f
Let's verify that everything works the way we expect it to work, hence
d0811f
check setsid() return code.
d0811f
---
d0811f
 src/nspawn/nspawn-stub-pid1.c | 5 ++++-
d0811f
 1 file changed, 4 insertions(+), 1 deletion(-)
d0811f
d0811f
diff --git a/src/nspawn/nspawn-stub-pid1.c b/src/nspawn/nspawn-stub-pid1.c
d0811f
index d86dd23185..f785a3b248 100644
d0811f
--- a/src/nspawn/nspawn-stub-pid1.c
d0811f
+++ b/src/nspawn/nspawn-stub-pid1.c
d0811f
@@ -66,7 +66,10 @@ int stub_pid1(sd_id128_t uuid) {
d0811f
         if (pid == 0) {
d0811f
                 /* Return in the child */
d0811f
                 assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) >= 0);
d0811f
-                setsid();
d0811f
+
d0811f
+                if (setsid() < 0)
d0811f
+                        return log_error_errno(errno, "Failed to become session leader in payload process: %m");
d0811f
+
d0811f
                 return 0;
d0811f
         }
d0811f
 
d0811f
-- 
d0811f
2.26.2
d0811f
d0811f
d0811f
From b4fa908fbdcbcf01c96e983460689800b8bb76af Mon Sep 17 00:00:00 2001
d0811f
From: Lennart Poettering <lennart@poettering.net>
d0811f
Date: Wed, 16 Sep 2020 22:12:29 +0200
d0811f
Subject: [PATCH 2/5] nspawn: print log notice when we are invoked from a tty
d0811f
 but in "pipe" mode
d0811f
d0811f
If people do this then things are weird, and they should probably use
d0811f
--console=interactive (i.e. the default) instead.
d0811f
d0811f
Prompted-by: #17070
d0811f
---
d0811f
 src/nspawn/nspawn.c | 10 ++++++++--
d0811f
 1 file changed, 8 insertions(+), 2 deletions(-)
d0811f
d0811f
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
d0811f
index 3b9493f232..efc541f512 100644
d0811f
--- a/src/nspawn/nspawn.c
d0811f
+++ b/src/nspawn/nspawn.c
d0811f
@@ -272,9 +272,15 @@ static int handle_arg_console(const char *arg) {
d0811f
                 arg_console_mode = CONSOLE_READ_ONLY;
d0811f
         else if (streq(arg, "passive"))
d0811f
                 arg_console_mode = CONSOLE_PASSIVE;
d0811f
-        else if (streq(arg, "pipe"))
d0811f
+        else if (streq(arg, "pipe")) {
d0811f
+                if (isatty(STDIN_FILENO) > 0 && isatty(STDOUT_FILENO) > 0)
d0811f
+                        log_full(arg_quiet ? LOG_DEBUG : LOG_NOTICE,
d0811f
+                                 "Console mode 'pipe' selected, but standard input/output are connected to an interactive TTY. "
d0811f
+                                 "Most likely you want to use 'interactive' console mode for proper interactivity and shell job control. "
d0811f
+                                 "Proceeding anyway.");
d0811f
+
d0811f
                 arg_console_mode = CONSOLE_PIPE;
d0811f
-        else
d0811f
+        } else
d0811f
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown console mode: %s", optarg);
d0811f
 
d0811f
         arg_settings_mask |= SETTING_CONSOLE_MODE;
d0811f
-- 
d0811f
2.26.2
d0811f
d0811f
d0811f
From 19db1706dadcec4f4c44f9abf8dc33a336f93326 Mon Sep 17 00:00:00 2001
d0811f
From: Lennart Poettering <lennart@poettering.net>
d0811f
Date: Wed, 16 Sep 2020 22:16:10 +0200
d0811f
Subject: [PATCH 3/5] nspawn: fix fd leak on failure path
d0811f
d0811f
---
d0811f
 src/nspawn/nspawn.c | 3 ++-
d0811f
 1 file changed, 2 insertions(+), 1 deletion(-)
d0811f
d0811f
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
d0811f
index efc541f512..15dbdbe738 100644
d0811f
--- a/src/nspawn/nspawn.c
d0811f
+++ b/src/nspawn/nspawn.c
d0811f
@@ -2178,7 +2178,7 @@ static int setup_pts(const char *dest) {
d0811f
 }
d0811f
 
d0811f
 static int setup_stdio_as_dev_console(void) {
d0811f
-        int terminal;
d0811f
+        _cleanup_close_ int terminal = -1;
d0811f
         int r;
d0811f
 
d0811f
         terminal = open_terminal("/dev/console", O_RDWR);
d0811f
@@ -2193,6 +2193,7 @@ static int setup_stdio_as_dev_console(void) {
d0811f
 
d0811f
         /* invalidates 'terminal' on success and failure */
d0811f
         r = rearrange_stdio(terminal, terminal, terminal);
d0811f
+        TAKE_FD(terminal);
d0811f
         if (r < 0)
d0811f
                 return log_error_errno(r, "Failed to move console to stdin/stdout/stderr: %m");
d0811f
 
d0811f
-- 
d0811f
2.26.2
d0811f
d0811f
d0811f
From d297a871ef720227af845fe8b0f1e0fe7560b433 Mon Sep 17 00:00:00 2001
d0811f
From: Lennart Poettering <lennart@poettering.net>
d0811f
Date: Wed, 16 Sep 2020 22:34:43 +0200
d0811f
Subject: [PATCH 4/5] nspawn: don't become TTY controller just to undo it later
d0811f
 again
d0811f
d0811f
Instead of first becoming a controlling process of the payload pty
d0811f
as side effect of opening it (without O_NOCTTY), and then possibly
d0811f
dropping it again, let's do it cleanly an reverse the logic: let's open
d0811f
the pty without becoming its controller first. Only after everything
d0811f
went the way we wanted it to go become the controller explicitly.
d0811f
d0811f
This has the benefit that the PID 1 stub process we run (as effect of
d0811f
--as-pid2) doesn't have to lose the tty explicitly, but can just
d0811f
continue running with things. And we explicitly make the tty controlling
d0811f
right before invoking actual payload.
d0811f
d0811f
In order to make sure everything works as expected validate that the
d0811f
stub PID 1 in the container really has no conrolling tty by issuing the
d0811f
TIOCNOTTY tty and expecting ENOTTY, and log about it.
d0811f
d0811f
This shouldn't change behaviour much, it just makes thins a bit cleaner,
d0811f
in particular as we'll not trigger SIGHUP on ourselves (since we are
d0811f
controller and session leader) due to TIOCNOTTY which we then have to
d0811f
explicitly ignore.
d0811f
---
d0811f
 src/nspawn/nspawn-stub-pid1.c | 12 ++++++------
d0811f
 src/nspawn/nspawn.c           | 16 +++++++++++++---
d0811f
 2 files changed, 19 insertions(+), 9 deletions(-)
d0811f
d0811f
diff --git a/src/nspawn/nspawn-stub-pid1.c b/src/nspawn/nspawn-stub-pid1.c
d0811f
index f785a3b248..60d7439fb1 100644
d0811f
--- a/src/nspawn/nspawn-stub-pid1.c
d0811f
+++ b/src/nspawn/nspawn-stub-pid1.c
d0811f
@@ -53,12 +53,6 @@ int stub_pid1(sd_id128_t uuid) {
d0811f
         assert_se(sigfillset(&fullmask) >= 0);
d0811f
         assert_se(sigprocmask(SIG_BLOCK, &fullmask, &oldmask) >= 0);
d0811f
 
d0811f
-        /* Surrender the terminal this stub may control so that child processes can have a controlling terminal
d0811f
-         * without resorting to setsid hacks. */
d0811f
-        r = ioctl(STDIN_FILENO, TIOCNOTTY);
d0811f
-        if (r < 0 && errno != ENOTTY)
d0811f
-                return log_error_errno(errno, "Failed to surrender controlling terminal: %m");
d0811f
-
d0811f
         pid = fork();
d0811f
         if (pid < 0)
d0811f
                 return log_error_errno(errno, "Failed to fork child pid: %m");
d0811f
@@ -79,6 +73,12 @@ int stub_pid1(sd_id128_t uuid) {
d0811f
         (void) close_all_fds(NULL, 0);
d0811f
         log_open();
d0811f
 
d0811f
+        if (ioctl(STDIN_FILENO, TIOCNOTTY) < 0) {
d0811f
+                if (errno != ENOTTY)
d0811f
+                        log_warning_errno(errno, "Unexpected error from TIOCNOTTY ioctl in init stub process, ignoring: %m");
d0811f
+        } else
d0811f
+                log_warning("Expected TIOCNOTTY to fail, but it succeeded in init stub process, ignoring.");
d0811f
+
d0811f
         /* Flush out /proc/self/environ, so that we don't leak the environment from the host into the container. Also,
d0811f
          * set $container= and $container_uuid= so that clients in the container that query it from /proc/1/environ
d0811f
          * find them set. */
d0811f
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
d0811f
index 15dbdbe738..783147f122 100644
d0811f
--- a/src/nspawn/nspawn.c
d0811f
+++ b/src/nspawn/nspawn.c
d0811f
@@ -11,10 +11,12 @@
d0811f
 #endif
d0811f
 #include <stdlib.h>
d0811f
 #include <sys/file.h>
d0811f
+#include <sys/ioctl.h>
d0811f
 #include <sys/personality.h>
d0811f
 #include <sys/prctl.h>
d0811f
 #include <sys/types.h>
d0811f
 #include <sys/wait.h>
d0811f
+#include <termios.h>
d0811f
 #include <unistd.h>
d0811f
 
d0811f
 #include "sd-bus.h"
d0811f
@@ -2181,7 +2183,9 @@ static int setup_stdio_as_dev_console(void) {
d0811f
         _cleanup_close_ int terminal = -1;
d0811f
         int r;
d0811f
 
d0811f
-        terminal = open_terminal("/dev/console", O_RDWR);
d0811f
+        /* We open the TTY in O_NOCTTY mode, so that we do not become controller yet. We'll do that later
d0811f
+         * explicitly, if we are configured to. */
d0811f
+        terminal = open_terminal("/dev/console", O_RDWR|O_NOCTTY);
d0811f
         if (terminal < 0)
d0811f
                 return log_error_errno(terminal, "Failed to open console: %m");
d0811f
 
d0811f
@@ -3213,8 +3217,7 @@ static int inner_child(
d0811f
          * wait until the parent is ready with the
d0811f
          * setup, too... */
d0811f
         if (!barrier_place_and_sync(barrier)) /* #5 */
d0811f
-                return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
d0811f
-                                       "Parent died too early");
d0811f
+                return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "Parent died too early");
d0811f
 
d0811f
         if (arg_chdir)
d0811f
                 if (chdir(arg_chdir) < 0)
d0811f
@@ -3226,6 +3229,13 @@ static int inner_child(
d0811f
                         return r;
d0811f
         }
d0811f
 
d0811f
+        if (arg_console_mode != CONSOLE_PIPE) {
d0811f
+                /* So far our pty wasn't controlled by any process. Finally, it's time to change that, if we
d0811f
+                 * are configured for that. Acquire it as controlling tty. */
d0811f
+                if (ioctl(STDIN_FILENO, TIOCSCTTY) < 0)
d0811f
+                        return log_error_errno(errno, "Failed to acquire controlling TTY: %m");
d0811f
+        }
d0811f
+
d0811f
         log_debug("Inner child completed, invoking payload.");
d0811f
 
d0811f
         /* Now, explicitly close the log, so that we then can close all remaining fds. Closing the log explicitly first
d0811f
-- 
d0811f
2.26.2
d0811f
d0811f
d0811f
From 196b94c2db3f0b763480e98df98f288bcd044a6e Mon Sep 17 00:00:00 2001
d0811f
From: Lennart Poettering <lennart@poettering.net>
d0811f
Date: Thu, 17 Sep 2020 16:26:14 +0200
d0811f
Subject: [PATCH 5/5] nspawn: add --console=autopipe mode
d0811f
d0811f
By default we'll run a container in --console=interactive and
d0811f
--console=read-only mode depending if we are invoked on a tty or not so
d0811f
that the container always gets a /dev/console allocated, i.e is always
d0811f
suitable to run a full init system /as those typically expect a
d0811f
/dev/console to exist).
d0811f
d0811f
With the new --console=autopipe mode we do something similar, but
d0811f
slightly different: when not invoked on a tty we'll use --console=pipe.
d0811f
This means, if you invoke some tool in a container with this you'll get
d0811f
full inetractivity if you invoke it on a tty but things will also be
d0811f
very nicely pipeable. OTOH you cannot invoke a full init system like
d0811f
this, because you might or might not become a /dev/console this way...
d0811f
d0811f
Prompted-by: #17070
d0811f
d0811f
(I named this "autopipe" rather than "auto" or so, since the default
d0811f
mode probably should be named "auto" one day if we add a name for it,
d0811f
and this is so similar to "auto" except that it uses pipes in the
d0811f
non-tty case).
d0811f
---
d0811f
 man/systemd-nspawn.xml | 21 ++++++++++++---------
d0811f
 src/nspawn/nspawn.c    | 12 +++++++++---
d0811f
 2 files changed, 21 insertions(+), 12 deletions(-)
d0811f
d0811f
diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml
d0811f
index 69558ac85c..b2c2a5006c 100644
d0811f
--- a/man/systemd-nspawn.xml
d0811f
+++ b/man/systemd-nspawn.xml
d0811f
@@ -1370,15 +1370,18 @@
d0811f
 
d0811f
         <listitem><para>Configures how to set up standard input, output and error output for the container
d0811f
         payload, as well as the <filename>/dev/console</filename> device for the container. Takes one of
d0811f
-        <option>interactive</option>, <option>read-only</option>, <option>passive</option>, or
d0811f
-        <option>pipe</option>. If <option>interactive</option>, a pseudo-TTY is allocated and made available
d0811f
-        as <filename>/dev/console</filename> in the container. It is then bi-directionally connected to the
d0811f
-        standard input and output passed to <command>systemd-nspawn</command>. <option>read-only</option> is
d0811f
-        similar but only the output of the container is propagated and no input from the caller is read. If
d0811f
-        <option>passive</option>, a pseudo TTY is allocated, but it is not connected anywhere. Finally, in
d0811f
-        <option>pipe</option> mode no pseudo TTY is allocated, but the standard input, output and error
d0811f
-        output file descriptors passed to <command>systemd-nspawn</command> are passed on — as they are — to
d0811f
-        the container payload, see the following paragraph. Defaults to <option>interactive</option> if
d0811f
+        <option>interactive</option>, <option>read-only</option>, <option>passive</option>,
d0811f
+        <option>pipe</option> or <option>autopipe</option>. If <option>interactive</option>, a pseudo-TTY is
d0811f
+        allocated and made available as <filename>/dev/console</filename> in the container. It is then
d0811f
+        bi-directionally connected to the standard input and output passed to
d0811f
+        <command>systemd-nspawn</command>. <option>read-only</option> is similar but only the output of the
d0811f
+        container is propagated and no input from the caller is read. If <option>passive</option>, a pseudo
d0811f
+        TTY is allocated, but it is not connected anywhere. In <option>pipe</option> mode no pseudo TTY is
d0811f
+        allocated, but the standard input, output and error output file descriptors passed to
d0811f
+        <command>systemd-nspawn</command> are passed on — as they are — to the container payload, see the
d0811f
+        following paragraph. Finally, <option>autopipe</option> mode operates like
d0811f
+        <option>interactive</option> when <command>systemd-nspawn</command> is invoked on a terminal, and
d0811f
+        like <option>pipe</option> otherwise. Defaults to <option>interactive</option> if
d0811f
         <command>systemd-nspawn</command> is invoked from a terminal, and <option>read-only</option>
d0811f
         otherwise.</para>
d0811f
 
d0811f
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
d0811f
index 783147f122..8837371232 100644
d0811f
--- a/src/nspawn/nspawn.c
d0811f
+++ b/src/nspawn/nspawn.c
d0811f
@@ -261,10 +261,11 @@ STATIC_DESTRUCTOR_REGISTER(arg_sysctl, strv_freep);
d0811f
 
d0811f
 static int handle_arg_console(const char *arg) {
d0811f
         if (streq(arg, "help")) {
d0811f
-                puts("interactive\n"
d0811f
-                     "read-only\n"
d0811f
+                puts("autopipe\n"
d0811f
+                     "interactive\n"
d0811f
                      "passive\n"
d0811f
-                     "pipe");
d0811f
+                     "pipe\n"
d0811f
+                     "read-only");
d0811f
                 return 0;
d0811f
         }
d0811f
 
d0811f
@@ -282,6 +283,11 @@ static int handle_arg_console(const char *arg) {
d0811f
                                  "Proceeding anyway.");
d0811f
 
d0811f
                 arg_console_mode = CONSOLE_PIPE;
d0811f
+        } else if (streq(arg, "autopipe")) {
d0811f
+                if (isatty(STDIN_FILENO) > 0 && isatty(STDOUT_FILENO) > 0)
d0811f
+                        arg_console_mode = CONSOLE_INTERACTIVE;
d0811f
+                else
d0811f
+                        arg_console_mode = CONSOLE_PIPE;
d0811f
         } else
d0811f
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown console mode: %s", optarg);
d0811f
 
d0811f
-- 
d0811f
2.26.2
d0811f