[lxc-devel] [PATCH] create lxc.tty ptys from container process
Stéphane Graber
stgraber at ubuntu.com
Thu Jan 29 10:39:51 UTC 2015
On Thu, Jan 29, 2015 at 10:13:36AM +0000, Serge Hallyn wrote:
> Lxc has always created the ptys for use by console and ttys early
> on from the monitor process. This has some advantages, but also
> has disadvantages, namely (1) container ptys counting against the
> max ptys for the host, and (2) not having a /dev/pts/N in the
> container to pass to getty. (2) was not a problem for us historically
> because we bind-mounted the host's /dev/pts/N onto a /dev/ttyN in
> the container. However, systemd hardocdes a check for container_ttys
> that the path have 'pts/' in it. If it were only for (2) I'd have
> opted for a systemd patch to check the device major number, but (1)
> made it worth moving the openpty to the container namespace.
>
> So this patch moves the tty creation into the task which becomes
> the container init. It then passes the fds for the opened ptys
> back to the monitor over a unix socketpair (for use by lxc-console).
> The /dev/console is still created in the monitor process, so that
> it can for instance be used by lxc.logfd.
>
> So now if you have a foreground container with lxc.tty = 4, you
> should end up with one host /dev/pts entry per container rather than 5.
>
> And lxc-console now works with systemd containers.
>
> Note that if the container init mounts its own devpts over the
> one mounted by lxc, the tty /dev/pts/n will be hidden. This is ok
> since it's only systemd that needs it, and systemd won't do that.
>
> Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
Acked-by: Stéphane Graber <stgraber at ubuntu.com>
> ---
> config/apparmor/abstractions/start-container | 1 +
> config/apparmor/profiles/lxc-default-with-nesting | 2 +-
> src/lxc/conf.c | 100 +++++++++++++++-------
> src/lxc/start.c | 61 +++++++++++--
> src/lxc/start.h | 1 +
> 5 files changed, 127 insertions(+), 38 deletions(-)
>
> diff --git a/config/apparmor/abstractions/start-container b/config/apparmor/abstractions/start-container
> index e361968..0d02379 100644
> --- a/config/apparmor/abstractions/start-container
> +++ b/config/apparmor/abstractions/start-container
> @@ -13,6 +13,7 @@
> mount -> /usr/lib/lxc/{**,},
> mount fstype=devpts -> /dev/pts/,
> mount options=bind /dev/pts/ptmx/ -> /dev/ptmx/,
> + mount options=bind /dev/pts/** -> /dev/tty*/,
> mount options=(rw, make-slave) -> **,
> mount fstype=debugfs,
> # allow pre-mount hooks to stage mounts under /var/lib/lxc/<container>/
> diff --git a/config/apparmor/profiles/lxc-default-with-nesting b/config/apparmor/profiles/lxc-default-with-nesting
> index 03325aa..91ad6de 100644
> --- a/config/apparmor/profiles/lxc-default-with-nesting
> +++ b/config/apparmor/profiles/lxc-default-with-nesting
> @@ -10,5 +10,5 @@ profile lxc-container-default-with-nesting flags=(attach_disconnected,mediate_de
>
> mount fstype=proc -> /var/cache/lxc/**,
> mount fstype=sysfs -> /var/cache/lxc/**,
> - mount options=(rw,bind) /var/cache/lxc/**/dev/shm/ -> /var/cache/lxc/**/run/shm/,
> + mount options=(rw,bind),
> }
> diff --git a/src/lxc/conf.c b/src/lxc/conf.c
> index e7def3e..aeabb6c 100644
> --- a/src/lxc/conf.c
> +++ b/src/lxc/conf.c
> @@ -65,6 +65,7 @@
>
> #include "network.h"
> #include "error.h"
> +#include "af_unix.h"
> #include "parse.h"
> #include "utils.h"
> #include "conf.h"
> @@ -968,29 +969,26 @@ static bool append_ptyname(char **pp, char *name)
>
> static int setup_tty(struct lxc_conf *conf)
> {
> - const struct lxc_rootfs *rootfs = &conf->rootfs;
> const struct lxc_tty_info *tty_info = &conf->tty_info;
> char *ttydir = conf->ttydir;
> char path[MAXPATHLEN], lxcpath[MAXPATHLEN];
> int i, ret;
>
> - if (!rootfs->path)
> + if (!conf->rootfs.path)
> return 0;
>
> for (i = 0; i < tty_info->nbtty; i++) {
>
> struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
>
> - ret = snprintf(path, sizeof(path), "%s/dev/tty%d",
> - rootfs->mount, i + 1);
> + ret = snprintf(path, sizeof(path), "/dev/tty%d", i + 1);
> if (ret >= sizeof(path)) {
> ERROR("pathname too long for ttys");
> return -1;
> }
> if (ttydir) {
> /* create dev/lxc/tty%d" */
> - ret = snprintf(lxcpath, sizeof(lxcpath), "%s/dev/%s/tty%d",
> - rootfs->mount, ttydir, i + 1);
> + ret = snprintf(lxcpath, sizeof(lxcpath), "/dev/%s/tty%d", ttydir, i + 1);
> if (ret >= sizeof(lxcpath)) {
> ERROR("pathname too long for ttys");
> return -1;
> @@ -1024,8 +1022,6 @@ static int setup_tty(struct lxc_conf *conf)
> SYSERROR("failed to create symlink for tty %d", i+1);
> return -1;
> }
> - /* Now save the relative path in @path for append_ptyname */
> - sprintf(path, "%s/tty%d", ttydir, i + 1);
> } else {
> /* If we populated /dev, then we need to create /dev/ttyN */
> if (access(path, F_OK)) {
> @@ -1038,14 +1034,11 @@ static int setup_tty(struct lxc_conf *conf)
> }
> }
> if (mount(pty_info->name, path, "none", MS_BIND, 0)) {
> - WARN("failed to mount '%s'->'%s'",
> - pty_info->name, path);
> + SYSERROR("failed to mount '%s'->'%s'", pty_info->name, path);
> continue;
> }
> - /* Now save the relative path in @path for append_ptyname */
> - sprintf(path, "tty%d", i + 1);
> }
> - if (!append_ptyname(&conf->pty_names, path)) {
> + if (!append_ptyname(&conf->pty_names, pty_info->name)) {
> ERROR("Error setting up container_ttys string");
> return -1;
> }
> @@ -3506,20 +3499,9 @@ int chown_mapped_root(char *path, struct lxc_conf *conf)
>
> int ttys_shift_ids(struct lxc_conf *c)
> {
> - int i;
> -
> if (lxc_list_empty(&c->id_map))
> return 0;
>
> - for (i = 0; i < c->tty_info.nbtty; i++) {
> - struct lxc_pty_info *pty_info = &c->tty_info.pty_info[i];
> -
> - if (chown_mapped_root(pty_info->name, c) < 0) {
> - ERROR("Failed to chown %s", pty_info->name);
> - return -1;
> - }
> - }
> -
> if (strcmp(c->console.name, "") !=0 && chown_mapped_root(c->console.name, c) < 0) {
> ERROR("Failed to chown %s", c->console.name);
> return -1;
> @@ -3737,6 +3719,48 @@ static bool verify_start_hooks(struct lxc_conf *conf)
> return true;
> }
>
> +static int send_fd(int sock, int fd)
> +{
> + int ret = lxc_abstract_unix_send_fd(sock, fd, NULL, 0);
> +
> +
> + if (ret < 0) {
> + SYSERROR("Error sending tty fd to parent");
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int send_ttys_to_parent(struct lxc_handler *handler)
> +{
> + struct lxc_conf *conf = handler->conf;
> + const struct lxc_tty_info *tty_info = &conf->tty_info;
> + int i;
> + int sock = handler->ttysock[0];
> +
> + for (i = 0; i < tty_info->nbtty; i++) {
> + struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
> + if (send_fd(sock, pty_info->slave) < 0)
> + goto bad;
> + close(pty_info->slave);
> + pty_info->slave = -1;
> + if (send_fd(sock, pty_info->master) < 0)
> + goto bad;
> + close(pty_info->master);
> + pty_info->master = -1;
> + }
> +
> + close(handler->ttysock[0]);
> + close(handler->ttysock[1]);
> +
> + return 0;
> +
> +bad:
> + ERROR("Error writing tty fd to parent");
> + return -1;
> +}
> +
> int lxc_setup(struct lxc_handler *handler)
> {
> const char *name = handler->name;
> @@ -3827,14 +3851,6 @@ int lxc_setup(struct lxc_handler *handler)
> ERROR("failed to setup kmsg for '%s'", name);
> }
>
> - if (!lxc_conf->is_execute && setup_tty(lxc_conf)) {
> - ERROR("failed to setup the ttys for '%s'", name);
> - return -1;
> - }
> -
> - if (lxc_conf->pty_names && setenv("container_ttys", lxc_conf->pty_names, 1))
> - SYSERROR("failed to set environment variable for container ptys");
> -
> if (!lxc_conf->is_execute && setup_dev_symlinks(&lxc_conf->rootfs)) {
> ERROR("failed to setup /dev symlinks for '%s'", name);
> return -1;
> @@ -3856,6 +3872,26 @@ int lxc_setup(struct lxc_handler *handler)
> return -1;
> }
>
> + if (lxc_create_tty(name, lxc_conf)) {
> + ERROR("failed to create the ttys");
> + return -1;
> + }
> +
> + if (send_ttys_to_parent(handler) < 0) {
> + ERROR("failure sending console info to parent");
> + return -1;
> + }
> +
> +
> + if (!lxc_conf->is_execute && setup_tty(lxc_conf)) {
> + ERROR("failed to setup the ttys for '%s'", name);
> + return -1;
> + }
> +
> + if (lxc_conf->pty_names && setenv("container_ttys", lxc_conf->pty_names, 1))
> + SYSERROR("failed to set environment variable for container ptys");
> +
> +
> if (setup_personality(lxc_conf->personality)) {
> ERROR("failed to setup personality");
> return -1;
> diff --git a/src/lxc/start.c b/src/lxc/start.c
> index 1949886..983f7a3 100644
> --- a/src/lxc/start.c
> +++ b/src/lxc/start.c
> @@ -375,6 +375,7 @@ struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf, const char
>
> memset(handler, 0, sizeof(*handler));
>
> + handler->ttysock[0] = handler->ttysock[1] = -1;
> handler->conf = conf;
> handler->lxcpath = lxcpath;
> handler->pinfd = -1;
> @@ -427,11 +428,6 @@ struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf, const char
> goto out_aborting;
> }
>
> - if (lxc_create_tty(name, conf)) {
> - ERROR("failed to create the ttys");
> - goto out_aborting;
> - }
> -
> /* the signal fd has to be created before forking otherwise
> * if the child process exits before we setup the signal fd,
> * the event will be lost and the command will be stuck */
> @@ -492,6 +488,10 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
> close(handler->conf->maincmd_fd);
> handler->conf->maincmd_fd = -1;
> free(handler->name);
> + if (handler->ttysock[0] != -1) {
> + close(handler->ttysock[0]);
> + close(handler->ttysock[1]);
> + }
> cgroup_destroy(handler);
> free(handler);
> }
> @@ -800,6 +800,46 @@ static int save_phys_nics(struct lxc_conf *conf)
> return 0;
> }
>
> +static int recv_fd(int sock, int *fd)
> +{
> + if (lxc_abstract_unix_recv_fd(sock, fd, NULL, 0) < 0) {
> + SYSERROR("Error receiving tty fd from child");
> + return -1;
> + }
> + if (*fd == -1)
> + return -1;
> + return 0;
> +}
> +
> +static int recv_ttys_from_child(struct lxc_handler *handler)
> +{
> + struct lxc_conf *conf = handler->conf;
> + int i, sock = handler->ttysock[1];
> + struct lxc_tty_info *tty_info = &conf->tty_info;
> +
> + if (!conf->tty)
> + return 0;
> +
> + tty_info->pty_info = malloc(sizeof(*tty_info->pty_info)*conf->tty);
> + if (!tty_info->pty_info) {
> + SYSERROR("failed to allocate pty_info");
> + return -1;
> + }
> +
> + for (i = 0; i < conf->tty; i++) {
> + struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
> + pty_info->busy = 0;
> + if (recv_fd(sock, &pty_info->slave) < 0 ||
> + recv_fd(sock, &pty_info->master) < 0) {
> + ERROR("Error receiving tty info from child");
> + return -1;
> + }
> + }
> + tty_info->nbtty = conf->tty;
> +
> + return 0;
> +}
> +
> static int lxc_spawn(struct lxc_handler *handler)
> {
> int failed_before_rename = 0;
> @@ -824,6 +864,11 @@ static int lxc_spawn(struct lxc_handler *handler)
> handler->clone_flags |= CLONE_NEWUSER;
> }
>
> + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, handler->ttysock) < 0) {
> + lxc_sync_fini(handler);
> + return -1;
> + }
> +
> if (handler->conf->inherit_ns_fd[LXC_NS_NET] == -1) {
> if (!lxc_requests_empty_network(handler))
> handler->clone_flags |= CLONE_NEWNET;
> @@ -991,6 +1036,12 @@ static int lxc_spawn(struct lxc_handler *handler)
> cgroup_disconnect();
> cgroups_connected = false;
>
> + /* read tty fds allocated by child */
> + if (recv_ttys_from_child(handler) < 0) {
> + ERROR("failed to receive tty info from child");
> + goto out_delete_net;
> + }
> +
> /* Tell the child to complete its initialization and wait for
> * it to exec or return an error. (the child will never
> * return LXC_SYNC_POST_CGROUP+1. It will either close the
> diff --git a/src/lxc/start.h b/src/lxc/start.h
> index d39b3b4..92f5b7d 100644
> --- a/src/lxc/start.h
> +++ b/src/lxc/start.h
> @@ -73,6 +73,7 @@ struct lxc_handler {
> int pinfd;
> const char *lxcpath;
> void *cgroup_data;
> + int ttysock[2]; // socketpair for child->parent tty fd passing
> };
>
>
> --
> 2.1.0
>
> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel
--
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20150129/9a32c0be/attachment-0001.sig>
More information about the lxc-devel
mailing list