Skip to content

Commit 3acc84e

Browse files
committed
nspawn: allocate the pty used for /dev/console within the container
The console tty is now allocated from within the container so it's not necessary anymore to allocate it from the host and bind mount the pty slave into the container. The pty master is sent to the host. /dev/console is now a symlink pointing to the pty slave. This might also be less confusing for applications running inside the container and the overall result looks cleaner (we don't need to apply manually the passed selinux context, if any, to the allocated pty for instance).
1 parent ba72801 commit 3acc84e

File tree

2 files changed

+106
-91
lines changed

2 files changed

+106
-91
lines changed

TODO

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,6 @@ Features:
209209
/etc/resolv.conf. Should be smart and do something useful on read-only
210210
images, for example fallback to read-only bind mounting the file instead.
211211

212-
* nspawn's console TTY should be allocated from within the container, not
213-
mounted in from the outside
214-
215212
* show invocation ID in systemd-run output
216213

217214
* bypass SIGTERM state in unit files if KillSignal is SIGKILL

src/nspawn/nspawn.c

Lines changed: 106 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -2037,32 +2037,41 @@ static int setup_pts(const char *dest) {
20372037
return 0;
20382038
}
20392039

2040-
static int setup_dev_console(const char *dest, const char *console) {
2041-
_cleanup_umask_ mode_t u;
2042-
const char *to;
2040+
static int setup_stdio_as_dev_console(void) {
2041+
int terminal;
20432042
int r;
20442043

2045-
assert(dest);
2046-
2047-
u = umask(0000);
2044+
terminal = open_terminal("/dev/console", O_RDWR);
2045+
if (terminal < 0)
2046+
return log_error_errno(terminal, "Failed to open console: %m");
20482047

2049-
if (!console)
2050-
return 0;
2048+
/* Make sure we can continue logging to the original stderr, even if
2049+
* stderr points elsewhere now */
2050+
r = log_dup_console();
2051+
if (r < 0)
2052+
return log_error_errno(r, "Failed to duplicate stderr: %m");
20512053

2052-
r = chmod_and_chown(console, 0600, arg_uid_shift, arg_uid_shift);
2054+
/* invalidates 'terminal' on success and failure */
2055+
r = rearrange_stdio(terminal, terminal, terminal);
20532056
if (r < 0)
2054-
return log_error_errno(r, "Failed to correct access mode for TTY: %m");
2057+
return log_error_errno(r, "Failed to move console to stdin/stdout/stderr: %m");
2058+
2059+
return 0;
2060+
}
20552061

2056-
/* We need to bind mount the right tty to /dev/console since
2057-
* ptys can only exist on pts file systems. To have something
2058-
* to bind mount things on we create a empty regular file. */
2062+
static int setup_dev_console(const char *console) {
2063+
_cleanup_free_ char *p = NULL;
2064+
int r;
20592065

2060-
to = prefix_roota(dest, "/dev/console");
2061-
r = touch(to);
2066+
/* Create /dev/console symlink */
2067+
r = path_make_relative("/dev", console, &p);
20622068
if (r < 0)
2063-
return log_error_errno(r, "touch() for /dev/console failed: %m");
2069+
return log_error_errno(r, "Failed to create relative path: %m");
2070+
2071+
if (symlink(p, "/dev/console") < 0)
2072+
return log_error_errno(errno, "Failed to create /dev/console symlink: %m");
20642073

2065-
return mount_verbose(LOG_ERR, console, to, NULL, MS_BIND, NULL);
2074+
return 0;
20662075
}
20672076

20682077
static int setup_keyring(void) {
@@ -2775,8 +2784,10 @@ static int inner_child(
27752784
bool secondary,
27762785
int kmsg_socket,
27772786
int rtnl_socket,
2787+
int master_pty_socket,
27782788
FDSet *fds) {
27792789

2790+
_cleanup_close_ int master = -1;
27802791
_cleanup_free_ char *home = NULL;
27812792
char as_uuid[37];
27822793
size_t n_env = 1;
@@ -2908,6 +2919,36 @@ static int inner_child(
29082919
rtnl_socket = safe_close(rtnl_socket);
29092920
}
29102921

2922+
if (arg_console_mode != CONSOLE_PIPE) {
2923+
_cleanup_free_ char *console = NULL;
2924+
2925+
/* Allocate a pty and make it available as /dev/console. */
2926+
2927+
master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
2928+
if (master < 0)
2929+
return log_error_errno(errno, "Failed to acquire pseudo tty: %m");
2930+
2931+
r = ptsname_malloc(master, &console);
2932+
if (r < 0)
2933+
return log_error_errno(r, "Failed to determine tty name: %m");
2934+
2935+
if (unlockpt(master) < 0)
2936+
return log_error_errno(errno, "Failed to unlock tty: %m");
2937+
2938+
r = setup_dev_console(console);
2939+
if (r < 0)
2940+
return log_error_errno(r, "Failed to setup /dev/console: %m");
2941+
2942+
r = send_one_fd(master_pty_socket, master, 0);
2943+
if (r < 0)
2944+
return log_error_errno(r, "Failed to send master fd: %m");
2945+
master_pty_socket = safe_close(master_pty_socket);
2946+
2947+
r = setup_stdio_as_dev_console();
2948+
if (r < 0)
2949+
return r;
2950+
}
2951+
29112952
r = patch_sysctl();
29122953
if (r < 0)
29132954
return r;
@@ -3129,7 +3170,6 @@ static int setup_sd_notify_child(void) {
31293170
static int outer_child(
31303171
Barrier *barrier,
31313172
const char *directory,
3132-
const char *console,
31333173
DissectedImage *dissected_image,
31343174
bool secondary,
31353175
int pid_socket,
@@ -3138,6 +3178,7 @@ static int outer_child(
31383178
int kmsg_socket,
31393179
int rtnl_socket,
31403180
int uid_shift_socket,
3181+
int master_pty_socket,
31413182
int unified_cgroup_hierarchy_socket,
31423183
FDSet *fds,
31433184
int netns_fd) {
@@ -3157,32 +3198,14 @@ static int outer_child(
31573198
assert(pid_socket >= 0);
31583199
assert(uuid_socket >= 0);
31593200
assert(notify_socket >= 0);
3201+
assert(master_pty_socket >= 0);
31603202
assert(kmsg_socket >= 0);
31613203

31623204
log_debug("Outer child is initializing.");
31633205

31643206
if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0)
31653207
return log_error_errno(errno, "PR_SET_PDEATHSIG failed: %m");
31663208

3167-
if (arg_console_mode != CONSOLE_PIPE) {
3168-
int terminal;
3169-
3170-
assert(console);
3171-
3172-
terminal = open_terminal(console, O_RDWR);
3173-
if (terminal < 0)
3174-
return log_error_errno(terminal, "Failed to open console: %m");
3175-
3176-
/* Make sure we can continue logging to the original stderr, even if stderr points elsewhere now */
3177-
r = log_dup_console();
3178-
if (r < 0)
3179-
return log_error_errno(r, "Failed to duplicate stderr: %m");
3180-
3181-
r = rearrange_stdio(terminal, terminal, terminal); /* invalidates 'terminal' on success and failure */
3182-
if (r < 0)
3183-
return log_error_errno(r, "Failed to move console to stdin/stdout/stderr: %m");
3184-
}
3185-
31863209
r = reset_audit_loginuid();
31873210
if (r < 0)
31883211
return r;
@@ -3337,10 +3360,6 @@ static int outer_child(
33373360
if (r < 0)
33383361
return r;
33393362

3340-
r = setup_dev_console(directory, console);
3341-
if (r < 0)
3342-
return r;
3343-
33443363
r = setup_keyring();
33453364
if (r < 0)
33463365
return r;
@@ -3415,7 +3434,7 @@ static int outer_child(
34153434
return log_error_errno(r, "Failed to join network namespace: %m");
34163435
}
34173436

3418-
r = inner_child(barrier, directory, secondary, kmsg_socket, rtnl_socket, fds);
3437+
r = inner_child(barrier, directory, secondary, kmsg_socket, rtnl_socket, master_pty_socket, fds);
34193438
if (r < 0)
34203439
_exit(EXIT_FAILURE);
34213440

@@ -3443,6 +3462,7 @@ static int outer_child(
34433462
pid_socket = safe_close(pid_socket);
34443463
uuid_socket = safe_close(uuid_socket);
34453464
notify_socket = safe_close(notify_socket);
3465+
master_pty_socket = safe_close(master_pty_socket);
34463466
kmsg_socket = safe_close(kmsg_socket);
34473467
rtnl_socket = safe_close(rtnl_socket);
34483468
netns_fd = safe_close(netns_fd);
@@ -4042,14 +4062,13 @@ static int load_oci_bundle(void) {
40424062
return merge_settings(settings, arg_oci_bundle);
40434063
}
40444064

4045-
static int run_container(int master,
4046-
const char* console,
4065+
static int run_container(
40474066
DissectedImage *dissected_image,
40484067
bool secondary,
40494068
FDSet *fds,
40504069
char veth_name[IFNAMSIZ], bool *veth_created,
40514070
union in_addr_union *exposed,
4052-
pid_t *pid, int *ret) {
4071+
int *master, pid_t *pid, int *ret) {
40534072

40544073
static const struct sigaction sa = {
40554074
.sa_handler = nop_signal_handler,
@@ -4065,9 +4084,10 @@ static int run_container(int master,
40654084
uuid_socket_pair[2] = { -1, -1 },
40664085
notify_socket_pair[2] = { -1, -1 },
40674086
uid_shift_socket_pair[2] = { -1, -1 },
4087+
master_pty_socket_pair[2] = { -1, -1 },
40684088
unified_cgroup_hierarchy_socket_pair[2] = { -1, -1};
40694089

4070-
_cleanup_close_ int notify_socket= -1;
4090+
_cleanup_close_ int notify_socket = -1;
40714091
_cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
40724092
_cleanup_(sd_event_source_unrefp) sd_event_source *notify_event_source = NULL;
40734093
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
@@ -4115,6 +4135,9 @@ static int run_container(int master,
41154135
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, notify_socket_pair) < 0)
41164136
return log_error_errno(errno, "Failed to create notify socket pair: %m");
41174137

4138+
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, master_pty_socket_pair) < 0)
4139+
return log_error_errno(errno, "Failed to create console socket pair: %m");
4140+
41184141
if (arg_userns_mode != USER_NAMESPACE_NO)
41194142
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0)
41204143
return log_error_errno(errno, "Failed to create uid shift socket pair: %m");
@@ -4158,13 +4181,12 @@ static int run_container(int master,
41584181
/* The outer child only has a file system namespace. */
41594182
barrier_set_role(&barrier, BARRIER_CHILD);
41604183

4161-
master = safe_close(master);
4162-
41634184
kmsg_socket_pair[0] = safe_close(kmsg_socket_pair[0]);
41644185
rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
41654186
pid_socket_pair[0] = safe_close(pid_socket_pair[0]);
41664187
uuid_socket_pair[0] = safe_close(uuid_socket_pair[0]);
41674188
notify_socket_pair[0] = safe_close(notify_socket_pair[0]);
4189+
master_pty_socket_pair[0] = safe_close(master_pty_socket_pair[0]);
41684190
uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]);
41694191
unified_cgroup_hierarchy_socket_pair[0] = safe_close(unified_cgroup_hierarchy_socket_pair[0]);
41704192

@@ -4173,7 +4195,6 @@ static int run_container(int master,
41734195

41744196
r = outer_child(&barrier,
41754197
arg_directory,
4176-
console,
41774198
dissected_image,
41784199
secondary,
41794200
pid_socket_pair[1],
@@ -4182,6 +4203,7 @@ static int run_container(int master,
41824203
kmsg_socket_pair[1],
41834204
rtnl_socket_pair[1],
41844205
uid_shift_socket_pair[1],
4206+
master_pty_socket_pair[1],
41854207
unified_cgroup_hierarchy_socket_pair[1],
41864208
fds,
41874209
netns_fd);
@@ -4200,6 +4222,7 @@ static int run_container(int master,
42004222
pid_socket_pair[1] = safe_close(pid_socket_pair[1]);
42014223
uuid_socket_pair[1] = safe_close(uuid_socket_pair[1]);
42024224
notify_socket_pair[1] = safe_close(notify_socket_pair[1]);
4225+
master_pty_socket_pair[1] = safe_close(master_pty_socket_pair[1]);
42034226
uid_shift_socket_pair[1] = safe_close(uid_shift_socket_pair[1]);
42044227
unified_cgroup_hierarchy_socket_pair[1] = safe_close(unified_cgroup_hierarchy_socket_pair[1]);
42054228

@@ -4474,17 +4497,40 @@ static int run_container(int master,
44744497

44754498
rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
44764499

4477-
if (IN_SET(arg_console_mode, CONSOLE_INTERACTIVE, CONSOLE_READ_ONLY)) {
4478-
assert(master >= 0);
4500+
if (arg_console_mode != CONSOLE_PIPE) {
4501+
_cleanup_close_ int fd = -1;
4502+
PTYForwardFlags flags = 0;
44794503

4480-
r = pty_forward_new(event, master,
4481-
PTY_FORWARD_IGNORE_VHANGUP | (arg_console_mode == CONSOLE_READ_ONLY ? PTY_FORWARD_READ_ONLY : 0),
4482-
&forward);
4483-
if (r < 0)
4484-
return log_error_errno(r, "Failed to create PTY forwarder: %m");
4504+
/* Retrieve the master pty allocated by inner child */
4505+
fd = receive_one_fd(master_pty_socket_pair[0], 0);
4506+
if (fd < 0)
4507+
return log_error_errno(fd, "Failed to receive master pty from the inner child: %m");
4508+
4509+
switch (arg_console_mode) {
44854510

4486-
if (arg_console_width != (unsigned) -1 || arg_console_height != (unsigned) -1)
4487-
(void) pty_forward_set_width_height(forward, arg_console_width, arg_console_height);
4511+
case CONSOLE_READ_ONLY:
4512+
flags |= PTY_FORWARD_READ_ONLY;
4513+
4514+
_fallthrough_;
4515+
4516+
case CONSOLE_INTERACTIVE:
4517+
flags |= PTY_FORWARD_IGNORE_VHANGUP;
4518+
4519+
r = pty_forward_new(event, fd, flags, &forward);
4520+
if (r < 0)
4521+
return log_error_errno(r, "Failed to create PTY forwarder: %m");
4522+
4523+
if (arg_console_width != (unsigned) -1 || arg_console_height != (unsigned) -1)
4524+
(void) pty_forward_set_width_height(forward,
4525+
arg_console_width,
4526+
arg_console_height);
4527+
break;
4528+
4529+
default:
4530+
assert(arg_console_mode == CONSOLE_PASSIVE);
4531+
}
4532+
4533+
*master = TAKE_FD(fd);
44884534
}
44894535

44904536
r = sd_event_loop(event);
@@ -4614,7 +4660,6 @@ static int initialize_rlimits(void) {
46144660
}
46154661

46164662
static int run(int argc, char *argv[]) {
4617-
_cleanup_free_ char *console = NULL;
46184663
_cleanup_close_ int master = -1;
46194664
_cleanup_fdset_free_ FDSet *fds = NULL;
46204665
int r, n_fd_passed, ret = EXIT_SUCCESS;
@@ -4929,31 +4974,6 @@ static int run(int argc, char *argv[]) {
49294974
if (arg_console_mode == CONSOLE_PIPE) /* if we pass STDERR on to the container, don't add our own logs into it too */
49304975
arg_quiet = true;
49314976

4932-
if (arg_console_mode != CONSOLE_PIPE) {
4933-
master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
4934-
if (master < 0) {
4935-
r = log_error_errno(errno, "Failed to acquire pseudo tty: %m");
4936-
goto finish;
4937-
}
4938-
4939-
r = ptsname_malloc(master, &console);
4940-
if (r < 0) {
4941-
r = log_error_errno(r, "Failed to determine tty name: %m");
4942-
goto finish;
4943-
}
4944-
4945-
if (arg_selinux_apifs_context) {
4946-
r = mac_selinux_apply(console, arg_selinux_apifs_context);
4947-
if (r < 0)
4948-
goto finish;
4949-
}
4950-
4951-
if (unlockpt(master) < 0) {
4952-
r = log_error_errno(errno, "Failed to unlock tty: %m");
4953-
goto finish;
4954-
}
4955-
}
4956-
49574977
if (!arg_quiet)
49584978
log_info("Spawning container %s on %s.\nPress ^] three times within 1s to kill container.",
49594979
arg_machine, arg_image ?: arg_directory);
@@ -4966,13 +4986,11 @@ static int run(int argc, char *argv[]) {
49664986
}
49674987

49684988
for (;;) {
4969-
r = run_container(master,
4970-
console,
4971-
dissected_image,
4989+
r = run_container(dissected_image,
49724990
secondary,
49734991
fds,
49744992
veth_name, &veth_created,
4975-
&exposed,
4993+
&exposed, &master,
49764994
&pid, &ret);
49774995
if (r <= 0)
49784996
break;

0 commit comments

Comments
 (0)