|
|
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 |
|