]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
conf: fd-only tty setup
authorChristian Brauner <christian.brauner@ubuntu.com>
Mon, 8 Feb 2021 13:52:50 +0000 (14:52 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Mon, 8 Feb 2021 20:59:19 +0000 (21:59 +0100)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/conf.c

index ef6ad00ee69ac2228b81f42d51e2e993b6e048bf..71c886e811a1c719c09c858b2c927ca875cdddec 100644 (file)
@@ -806,70 +806,101 @@ static bool append_ttyname(char **pp, char *name)
 
 static int lxc_setup_ttys(struct lxc_conf *conf)
 {
-       int i, ret;
+       int ret;
+       struct lxc_rootfs *rootfs = &conf->rootfs;
        const struct lxc_tty_info *ttys = &conf->ttys;
        char *ttydir = ttys->dir;
-       char path[PATH_MAX], lxcpath[PATH_MAX];
 
        if (!conf->rootfs.path)
                return 0;
 
-       for (i = 0; i < ttys->max; i++) {
+       for (int i = 0; i < ttys->max; i++) {
+               __do_close int fd_to = -EBADF;
                struct lxc_terminal_info *tty = &ttys->tty[i];
 
-               ret = snprintf(path, sizeof(path), "/dev/tty%d", i + 1);
-               if (ret < 0 || (size_t)ret >= sizeof(path))
-                       return -1;
-
                if (ttydir) {
-                       /* create dev/lxc/tty%d" */
-                       ret = snprintf(lxcpath, sizeof(lxcpath),
-                                      "/dev/%s/tty%d", ttydir, i + 1);
-                       if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
-                               return -1;
-
-                       ret = mknod(lxcpath, S_IFREG | 0000, 0);
-                       if (ret < 0 && errno != EEXIST) {
-                               SYSERROR("Failed to create \"%s\"", lxcpath);
-                               return -1;
-                       }
-
-                       ret = unlink(path);
-                       if (ret < 0 && errno != ENOENT) {
-                               SYSERROR("Failed to unlink \"%s\"", path);
-                               return -1;
-                       }
+                       char *tty_name, *tty_path;
 
-                       ret = mount(tty->name, lxcpath, "none", MS_BIND, 0);
-                       if (ret < 0) {
-                               SYSWARN("Failed to bind mount \"%s\" onto \"%s\"", tty->name, lxcpath);
-                               continue;
+                       ret = snprintf(rootfs->buf, sizeof(rootfs->buf),
+                                      "/dev/%s/tty%d", ttydir, i + 1);
+                       if (ret < 0 || (size_t)ret >= sizeof(rootfs->buf))
+                               return ret_errno(-EIO);
+
+                       tty_path = &rootfs->buf[STRLITERALLEN("/dev/")];
+                       tty_name = tty_path + strlen(ttydir) + 1;
+
+                       /* create bind-mount target */
+                       fd_to = open_at(rootfs->dfd_dev, tty_path,
+                                       PROTECT_OPEN_W | O_CREAT,
+                                       PROTECT_LOOKUP_BENEATH, 0);
+                       if (fd_to < 0)
+                               return log_error_errno(-errno, errno,
+                                                      "Failed to create tty mount target %d(%s)",
+                                                      rootfs->dfd_dev, tty_path);
+
+                       ret = unlinkat(rootfs->dfd_dev, tty_name, 0);
+                       if (ret < 0 && errno != ENOENT)
+                               return log_error_errno(-errno, errno,
+                                                      "Failed to unlink %d(%s)",
+                                                      rootfs->dfd_dev, tty_name);
+
+                       if (new_mount_api()) {
+                               ret = fd_bind_mount(tty->pty, "",
+                                                   PROTECT_OPATH_FILE,
+                                                   PROTECT_LOOKUP_BENEATH_XDEV,
+                                                   fd_to, "",
+                                                   PROTECT_OPATH_FILE,
+                                                   PROTECT_LOOKUP_BENEATH_XDEV, 0,
+                                                   false);
+                       } else {
+                               ret = mount(tty->name, rootfs->buf, "none", MS_BIND, 0);
                        }
-                       DEBUG("Bind mounted \"%s\" onto \"%s\"", tty->name, lxcpath);
-
-                       ret = snprintf(lxcpath, sizeof(lxcpath), "%s/tty%d",
-                                      ttydir, i + 1);
-                       if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
-                               return -1;
+                       if (ret < 0)
+                               return log_error_errno(-errno, errno,
+                                                      "Failed to bind mount \"%s\" onto \"%s\"",
+                                                      tty->name, rootfs->buf);
+                       DEBUG("Bind mounted \"%s\" onto \"%s\"", tty->name, rootfs->buf);
 
-                       ret = symlink(lxcpath, path);
+                       ret = symlinkat(tty_path, rootfs->dfd_dev, tty_name);
                        if (ret < 0)
-                               return log_error_errno(-1, errno, "Failed to create symlink \"%s\" -> \"%s\"", path, lxcpath);
+                               return log_error_errno(-errno, errno,
+                                                      "Failed to create symlink \"%d(%s)\" -> \"%d(%s)\"",
+                                                      rootfs->dfd_dev, tty_name,
+                                                      rootfs->dfd_dev, tty_path);
                } else {
-                       /* If we populated /dev, then we need to create
-                        * /dev/ttyN
-                        */
-                       ret = mknod(path, S_IFREG | 0000, 0);
-                       if (ret < 0) /* this isn't fatal, continue */
-                               SYSERROR("Failed to create \"%s\"", path);
-
-                       ret = mount(tty->name, path, "none", MS_BIND, 0);
-                       if (ret < 0) {
-                               SYSERROR("Failed to mount '%s'->'%s'", tty->name, path);
-                               continue;
+                       ret = snprintf(rootfs->buf, sizeof(rootfs->buf), "tty%d", i + 1);
+                       if (ret < 0 || (size_t)ret >= sizeof(rootfs->buf))
+                               return ret_errno(-EIO);
+
+                       /* If we populated /dev, then we need to create /dev/tty<idx>. */
+                       fd_to = open_at(rootfs->dfd_dev, rootfs->buf,
+                                       PROTECT_OPEN_W | O_CREAT,
+                                       PROTECT_LOOKUP_BENEATH, 0);
+                       if (fd_to < 0)
+                               return log_error_errno(-errno, errno,
+                                                      "Failed to create tty mount target %d(%s)",
+                                                      rootfs->dfd_dev, rootfs->buf);
+
+                       if (new_mount_api()) {
+                               ret = fd_bind_mount(tty->pty, "",
+                                                   PROTECT_OPATH_FILE,
+                                                   PROTECT_LOOKUP_BENEATH_XDEV,
+                                                   fd_to, "",
+                                                   PROTECT_OPATH_FILE,
+                                                   PROTECT_LOOKUP_BENEATH, 0,
+                                                   false);
+                       } else {
+                               ret = snprintf(rootfs->buf, sizeof(rootfs->buf), "/dev/tty%d", i + 1);
+                               if (ret < 0 || (size_t)ret >= sizeof(rootfs->buf))
+                                       return ret_errno(-EIO);
+
+                               ret = mount(tty->name, rootfs->buf, "none", MS_BIND, 0);
                        }
-
-                       DEBUG("Bind mounted \"%s\" onto \"%s\"", tty->name, path);
+                       if (ret < 0)
+                               return log_error_errno(-errno, errno,
+                                                      "Failed to bind mount \"%s\" onto \"%s\"",
+                                                      tty->name, rootfs->buf);
+                       DEBUG("Bind mounted \"%s\" onto \"%s\"", tty->name, rootfs->buf);
                }
 
                if (!append_ttyname(&conf->ttys.tty_names, tty->name))
@@ -880,13 +911,11 @@ static int lxc_setup_ttys(struct lxc_conf *conf)
        return 0;
 }
 
-define_cleanup_function(struct lxc_tty_info *, lxc_delete_tty);
-
 static int lxc_allocate_ttys(struct lxc_conf *conf)
 {
        struct lxc_terminal_info *tty_new = NULL;
        int ret;
-       call_cleaner(lxc_delete_tty) struct lxc_tty_info *ttys = &conf->ttys;
+       struct lxc_tty_info *ttys = &conf->ttys;
 
        /* no tty in the configuration */
        if (ttys->max == 0)
@@ -895,27 +924,25 @@ static int lxc_allocate_ttys(struct lxc_conf *conf)
        tty_new = malloc(sizeof(struct lxc_terminal_info) * ttys->max);
        if (!tty_new)
                return -ENOMEM;
-       ttys->tty = tty_new;
 
-       for (size_t i = 0; i < ttys->max; i++) {
-               struct lxc_terminal_info *tty = &ttys->tty[i];
+       for (size_t i = 0; i < conf->ttys.max; i++) {
+               struct lxc_terminal_info *tty = &tty_new[i];
 
                tty->ptx = -EBADF;
                tty->pty = -EBADF;
                ret = openpty(&tty->ptx, &tty->pty, NULL, NULL, NULL);
                if (ret < 0) {
-                       ttys->max = i;
+                       conf->ttys.max = i;
                        return log_error_errno(-ENOTTY, ENOTTY, "Failed to create tty %zu", i);
                }
 
                ret = ttyname_r(tty->pty, tty->name, sizeof(tty->name));
                if (ret < 0) {
-                       ttys->max = i;
+                       conf->ttys.max = i;
                        return log_error_errno(-ENOTTY, ENOTTY, "Failed to retrieve name of tty %zu pty", i);
                }
 
-               DEBUG("Created tty \"%s\" with ptx fd %d and pty fd %d",
-                     tty->name, tty->ptx, tty->pty);
+               DEBUG("Created tty with ptx fd %d and pty fd %d", tty->ptx, tty->pty);
 
                /* Prevent leaking the file descriptors to the container */
                ret = fd_cloexec(tty->ptx, true);
@@ -932,7 +959,7 @@ static int lxc_allocate_ttys(struct lxc_conf *conf)
        }
 
        INFO("Finished creating %zu tty devices", ttys->max);
-       move_ptr(ttys);
+       conf->ttys.tty = move_ptr(tty_new);
        return 0;
 }