diff --git a/TODO b/TODO index 57c07bea7a..3f69c24fc3 100644 --- a/TODO +++ b/TODO @@ -209,9 +209,6 @@ Features: /etc/resolv.conf. Should be smart and do something useful on read-only images, for example fallback to read-only bind mounting the file instead. -* nspawn's console TTY should be allocated from within the container, not - mounted in from the outside - * show invocation ID in systemd-run output * bypass SIGTERM state in unit files if KillSignal is SIGKILL diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 3713daa1fb..085a9806ce 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2037,32 +2037,41 @@ static int setup_pts(const char *dest) { return 0; } -static int setup_dev_console(const char *dest, const char *console) { - _cleanup_umask_ mode_t u; - const char *to; +static int setup_stdio_as_dev_console(void) { + int terminal; int r; - assert(dest); + terminal = open_terminal("/dev/console", O_RDWR); + if (terminal < 0) + return log_error_errno(terminal, "Failed to open console: %m"); - u = umask(0000); - - if (!console) - return 0; - - r = chmod_and_chown(console, 0600, arg_uid_shift, arg_uid_shift); + /* Make sure we can continue logging to the original stderr, even if + * stderr points elsewhere now */ + r = log_dup_console(); if (r < 0) - return log_error_errno(r, "Failed to correct access mode for TTY: %m"); + return log_error_errno(r, "Failed to duplicate stderr: %m"); - /* We need to bind mount the right tty to /dev/console since - * ptys can only exist on pts file systems. To have something - * to bind mount things on we create a empty regular file. */ - - to = prefix_roota(dest, "/dev/console"); - r = touch(to); + /* invalidates 'terminal' on success and failure */ + r = rearrange_stdio(terminal, terminal, terminal); if (r < 0) - return log_error_errno(r, "touch() for /dev/console failed: %m"); + return log_error_errno(r, "Failed to move console to stdin/stdout/stderr: %m"); - return mount_verbose(LOG_ERR, console, to, NULL, MS_BIND, NULL); + return 0; +} + +static int setup_dev_console(const char *console) { + _cleanup_free_ char *p = NULL; + int r; + + /* Create /dev/console symlink */ + r = path_make_relative("/dev", console, &p); + if (r < 0) + return log_error_errno(r, "Failed to create relative path: %m"); + + if (symlink(p, "/dev/console") < 0) + return log_error_errno(errno, "Failed to create /dev/console symlink: %m"); + + return 0; } static int setup_keyring(void) { @@ -2775,8 +2784,10 @@ static int inner_child( bool secondary, int kmsg_socket, int rtnl_socket, + int master_pty_socket, FDSet *fds) { + _cleanup_close_ int master = -1; _cleanup_free_ char *home = NULL; char as_uuid[37]; size_t n_env = 1; @@ -2908,6 +2919,36 @@ static int inner_child( rtnl_socket = safe_close(rtnl_socket); } + if (arg_console_mode != CONSOLE_PIPE) { + _cleanup_free_ char *console = NULL; + + /* Allocate a pty and make it available as /dev/console. */ + + master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK); + if (master < 0) + return log_error_errno(errno, "Failed to acquire pseudo tty: %m"); + + r = ptsname_malloc(master, &console); + if (r < 0) + return log_error_errno(r, "Failed to determine tty name: %m"); + + if (unlockpt(master) < 0) + return log_error_errno(errno, "Failed to unlock tty: %m"); + + r = setup_dev_console(console); + if (r < 0) + return log_error_errno(r, "Failed to setup /dev/console: %m"); + + r = send_one_fd(master_pty_socket, master, 0); + if (r < 0) + return log_error_errno(r, "Failed to send master fd: %m"); + master_pty_socket = safe_close(master_pty_socket); + + r = setup_stdio_as_dev_console(); + if (r < 0) + return r; + } + r = patch_sysctl(); if (r < 0) return r; @@ -3129,7 +3170,6 @@ static int setup_sd_notify_child(void) { static int outer_child( Barrier *barrier, const char *directory, - const char *console, DissectedImage *dissected_image, bool secondary, int pid_socket, @@ -3138,6 +3178,7 @@ static int outer_child( int kmsg_socket, int rtnl_socket, int uid_shift_socket, + int master_pty_socket, int unified_cgroup_hierarchy_socket, FDSet *fds, int netns_fd) { @@ -3157,6 +3198,7 @@ static int outer_child( assert(pid_socket >= 0); assert(uuid_socket >= 0); assert(notify_socket >= 0); + assert(master_pty_socket >= 0); assert(kmsg_socket >= 0); log_debug("Outer child is initializing."); @@ -3164,25 +3206,6 @@ static int outer_child( if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0) return log_error_errno(errno, "PR_SET_PDEATHSIG failed: %m"); - if (arg_console_mode != CONSOLE_PIPE) { - int terminal; - - assert(console); - - terminal = open_terminal(console, O_RDWR); - if (terminal < 0) - return log_error_errno(terminal, "Failed to open console: %m"); - - /* Make sure we can continue logging to the original stderr, even if stderr points elsewhere now */ - r = log_dup_console(); - if (r < 0) - return log_error_errno(r, "Failed to duplicate stderr: %m"); - - r = rearrange_stdio(terminal, terminal, terminal); /* invalidates 'terminal' on success and failure */ - if (r < 0) - return log_error_errno(r, "Failed to move console to stdin/stdout/stderr: %m"); - } - r = reset_audit_loginuid(); if (r < 0) return r; @@ -3337,10 +3360,6 @@ static int outer_child( if (r < 0) return r; - r = setup_dev_console(directory, console); - if (r < 0) - return r; - r = setup_keyring(); if (r < 0) return r; @@ -3415,7 +3434,7 @@ static int outer_child( return log_error_errno(r, "Failed to join network namespace: %m"); } - r = inner_child(barrier, directory, secondary, kmsg_socket, rtnl_socket, fds); + r = inner_child(barrier, directory, secondary, kmsg_socket, rtnl_socket, master_pty_socket, fds); if (r < 0) _exit(EXIT_FAILURE); @@ -3443,6 +3462,7 @@ static int outer_child( pid_socket = safe_close(pid_socket); uuid_socket = safe_close(uuid_socket); notify_socket = safe_close(notify_socket); + master_pty_socket = safe_close(master_pty_socket); kmsg_socket = safe_close(kmsg_socket); rtnl_socket = safe_close(rtnl_socket); netns_fd = safe_close(netns_fd); @@ -4042,14 +4062,13 @@ static int load_oci_bundle(void) { return merge_settings(settings, arg_oci_bundle); } -static int run_container(int master, - const char* console, +static int run_container( DissectedImage *dissected_image, bool secondary, FDSet *fds, char veth_name[IFNAMSIZ], bool *veth_created, union in_addr_union *exposed, - pid_t *pid, int *ret) { + int *master, pid_t *pid, int *ret) { static const struct sigaction sa = { .sa_handler = nop_signal_handler, @@ -4065,9 +4084,10 @@ static int run_container(int master, uuid_socket_pair[2] = { -1, -1 }, notify_socket_pair[2] = { -1, -1 }, uid_shift_socket_pair[2] = { -1, -1 }, + master_pty_socket_pair[2] = { -1, -1 }, unified_cgroup_hierarchy_socket_pair[2] = { -1, -1}; - _cleanup_close_ int notify_socket= -1; + _cleanup_close_ int notify_socket = -1; _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL; _cleanup_(sd_event_source_unrefp) sd_event_source *notify_event_source = NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL; @@ -4115,6 +4135,9 @@ static int run_container(int master, if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, notify_socket_pair) < 0) return log_error_errno(errno, "Failed to create notify socket pair: %m"); + if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, master_pty_socket_pair) < 0) + return log_error_errno(errno, "Failed to create console socket pair: %m"); + if (arg_userns_mode != USER_NAMESPACE_NO) if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0) return log_error_errno(errno, "Failed to create uid shift socket pair: %m"); @@ -4158,13 +4181,12 @@ static int run_container(int master, /* The outer child only has a file system namespace. */ barrier_set_role(&barrier, BARRIER_CHILD); - master = safe_close(master); - kmsg_socket_pair[0] = safe_close(kmsg_socket_pair[0]); rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); pid_socket_pair[0] = safe_close(pid_socket_pair[0]); uuid_socket_pair[0] = safe_close(uuid_socket_pair[0]); notify_socket_pair[0] = safe_close(notify_socket_pair[0]); + master_pty_socket_pair[0] = safe_close(master_pty_socket_pair[0]); uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]); unified_cgroup_hierarchy_socket_pair[0] = safe_close(unified_cgroup_hierarchy_socket_pair[0]); @@ -4173,7 +4195,6 @@ static int run_container(int master, r = outer_child(&barrier, arg_directory, - console, dissected_image, secondary, pid_socket_pair[1], @@ -4182,6 +4203,7 @@ static int run_container(int master, kmsg_socket_pair[1], rtnl_socket_pair[1], uid_shift_socket_pair[1], + master_pty_socket_pair[1], unified_cgroup_hierarchy_socket_pair[1], fds, netns_fd); @@ -4200,6 +4222,7 @@ static int run_container(int master, pid_socket_pair[1] = safe_close(pid_socket_pair[1]); uuid_socket_pair[1] = safe_close(uuid_socket_pair[1]); notify_socket_pair[1] = safe_close(notify_socket_pair[1]); + master_pty_socket_pair[1] = safe_close(master_pty_socket_pair[1]); uid_shift_socket_pair[1] = safe_close(uid_shift_socket_pair[1]); unified_cgroup_hierarchy_socket_pair[1] = safe_close(unified_cgroup_hierarchy_socket_pair[1]); @@ -4474,17 +4497,40 @@ static int run_container(int master, rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); - if (IN_SET(arg_console_mode, CONSOLE_INTERACTIVE, CONSOLE_READ_ONLY)) { - assert(master >= 0); + if (arg_console_mode != CONSOLE_PIPE) { + _cleanup_close_ int fd = -1; + PTYForwardFlags flags = 0; - r = pty_forward_new(event, master, - PTY_FORWARD_IGNORE_VHANGUP | (arg_console_mode == CONSOLE_READ_ONLY ? PTY_FORWARD_READ_ONLY : 0), - &forward); - if (r < 0) - return log_error_errno(r, "Failed to create PTY forwarder: %m"); + /* Retrieve the master pty allocated by inner child */ + fd = receive_one_fd(master_pty_socket_pair[0], 0); + if (fd < 0) + return log_error_errno(fd, "Failed to receive master pty from the inner child: %m"); - if (arg_console_width != (unsigned) -1 || arg_console_height != (unsigned) -1) - (void) pty_forward_set_width_height(forward, arg_console_width, arg_console_height); + switch (arg_console_mode) { + + case CONSOLE_READ_ONLY: + flags |= PTY_FORWARD_READ_ONLY; + + _fallthrough_; + + case CONSOLE_INTERACTIVE: + flags |= PTY_FORWARD_IGNORE_VHANGUP; + + r = pty_forward_new(event, fd, flags, &forward); + if (r < 0) + return log_error_errno(r, "Failed to create PTY forwarder: %m"); + + if (arg_console_width != (unsigned) -1 || arg_console_height != (unsigned) -1) + (void) pty_forward_set_width_height(forward, + arg_console_width, + arg_console_height); + break; + + default: + assert(arg_console_mode == CONSOLE_PASSIVE); + } + + *master = TAKE_FD(fd); } r = sd_event_loop(event); @@ -4614,7 +4660,6 @@ static int initialize_rlimits(void) { } static int run(int argc, char *argv[]) { - _cleanup_free_ char *console = NULL; _cleanup_close_ int master = -1; _cleanup_fdset_free_ FDSet *fds = NULL; int r, n_fd_passed, ret = EXIT_SUCCESS; @@ -4929,31 +4974,6 @@ static int run(int argc, char *argv[]) { if (arg_console_mode == CONSOLE_PIPE) /* if we pass STDERR on to the container, don't add our own logs into it too */ arg_quiet = true; - if (arg_console_mode != CONSOLE_PIPE) { - master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK); - if (master < 0) { - r = log_error_errno(errno, "Failed to acquire pseudo tty: %m"); - goto finish; - } - - r = ptsname_malloc(master, &console); - if (r < 0) { - r = log_error_errno(r, "Failed to determine tty name: %m"); - goto finish; - } - - if (arg_selinux_apifs_context) { - r = mac_selinux_apply(console, arg_selinux_apifs_context); - if (r < 0) - goto finish; - } - - if (unlockpt(master) < 0) { - r = log_error_errno(errno, "Failed to unlock tty: %m"); - goto finish; - } - } - if (!arg_quiet) log_info("Spawning container %s on %s.\nPress ^] three times within 1s to kill container.", arg_machine, arg_image ?: arg_directory); @@ -4966,13 +4986,11 @@ static int run(int argc, char *argv[]) { } for (;;) { - r = run_container(master, - console, - dissected_image, + r = run_container(dissected_image, secondary, fds, veth_name, &veth_created, - &exposed, + &exposed, &master, &pid, &ret); if (r <= 0) break;