]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
conf: use new mount api for devpts setup
authorChristian Brauner <christian.brauner@ubuntu.com>
Wed, 28 Jul 2021 14:38:36 +0000 (16:38 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Wed, 28 Jul 2021 16:40:13 +0000 (18:40 +0200)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/conf.c
src/lxc/mount_utils.c
src/lxc/mount_utils.h
src/lxc/string_utils.h

index 10971e7a439b5bd0438541f00e5983bdbf858555..d893328c7680434d9c4bce1bcf568fc27a29d5f4 100644 (file)
@@ -1663,9 +1663,58 @@ static int lxc_setup_devpts_parent(struct lxc_handler *handler)
        return 0;
 }
 
-static int lxc_setup_devpts_child(struct lxc_handler *handler)
+static int lxc_prepare_devpts_child(struct lxc_handler *handler)
+{
+       __do_close int fd_fs = -EBADF, fd_fsmnt = -EBADF;
+       struct lxc_conf *conf = handler->conf;
+       int ret;
+
+       if (!can_use_mount_api())
+               return 0;
+
+       if (conf->pty_max <= 0)
+               return log_debug(0, "No new devpts instance will be mounted since no pts devices are requested");
+
+       fd_fs = fs_prepare("devpts", -EBADF, "", 0, 0);
+       if (fd_fs < 0)
+               return syserror("Failed to prepare filesystem context for devpts");
+
+       ret = fs_set_property(fd_fs, "gid", "5");
+       if (ret < 0)
+               SYSTRACE("Failed to set \"gid=5\" on devpts filesystem context %d", fd_fs);
+
+       ret = fs_set_flag(fd_fs, "newinstance");
+       if (ret < 0)
+               return syserror("Failed to set \"newinstance\" property on devpts filesystem context %d", fd_fs);
+
+       ret = fs_set_property(fd_fs, "ptmxmode", "0666");
+       if (ret < 0)
+               return syserror("Failed to set \"ptmxmode=0666\" property on devpts filesystem context %d", fd_fs);
+
+       ret = fs_set_property(fd_fs, "mode", "0620");
+       if (ret < 0)
+               return syserror("Failed to set \"mode=0620\" property on devpts filesystem context %d", fd_fs);
+
+       ret = fs_set_property(fd_fs, "max", fdstr(conf->pty_max));
+       if (ret < 0)
+               return syserror("Failed to set \"max=%zu\" property on devpts filesystem context %d", conf->pty_max, fd_fs);
+
+       ret = fsconfig(fd_fs, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
+       if (ret < 0)
+               return syserror("Failed to finalize filesystem context %d", fd_fs);
+
+       fd_fsmnt = fsmount(fd_fs, FSMOUNT_CLOEXEC, MOUNT_ATTR_NOSUID | MOUNT_ATTR_NOEXEC);
+       if (fd_fsmnt < 0)
+               return syserror("Failed to create new mount for filesystem context %d", fd_fs);
+
+       TRACE("Created detached devpts mount %d", fd_fsmnt);
+       handler->conf->devpts_fd = move_fd(fd_fsmnt);
+
+       return 0;
+}
+
+static int lxc_finalize_devpts_child(struct lxc_handler *handler)
 {
-       __do_close int devpts_fd = -EBADF;
        int ret;
        char **opts;
        char devpts_mntopts[256];
@@ -1677,51 +1726,65 @@ static int lxc_setup_devpts_child(struct lxc_handler *handler)
        if (conf->pty_max <= 0)
                return log_debug(0, "No new devpts instance will be mounted since no pts devices are requested");
 
-       ret = strnprintf(devpts_mntopts, sizeof(devpts_mntopts), "%s,max=%zu",
-                      default_devpts_mntopts, conf->pty_max);
-       if (ret < 0)
-               return -1;
+       /*
+        * Fallback codepath in case the new mount API can't be used to create
+        * detached mounts.
+        */
+       if (conf->devpts_fd >= 0) {
+               ret = move_mount(conf->devpts_fd, "", rootfs->dfd_dev, "pts", MOVE_MOUNT_F_EMPTY_PATH);
+               if (ret)
+                       return syserror("Failed to attach devpts mount %d to %d/pts", conf->devpts_fd, rootfs->dfd_dev);
 
-       (void)umount2("/dev/pts", MNT_DETACH);
+               DEBUG("Attached detached devpts mount %d to %d/pts", conf->devpts_fd, rootfs->dfd_dev);
+       } else {
+               __do_close int devpts_fd = -EBADF;
 
-       /* Create mountpoint for devpts instance. */
-       ret = mkdirat(rootfs->dfd_dev, "pts", 0755);
-       if (ret < 0 && errno != EEXIST)
-               return log_error_errno(-1, errno, "Failed to create \"/dev/pts\" directory");
+               ret = strnprintf(devpts_mntopts, sizeof(devpts_mntopts), "%s,max=%zu",
+                               default_devpts_mntopts, conf->pty_max);
+               if (ret < 0)
+                       return -1;
 
-       /* gid=5 && max= */
-       mntopt_sets[0] = devpts_mntopts;
+               (void)umount2("/dev/pts", MNT_DETACH);
 
-       /* !gid=5 && max= */
-       mntopt_sets[1] = devpts_mntopts + STRLITERALLEN("gid=5") + 1;
+               /* Create mountpoint for devpts instance. */
+               ret = mkdirat(rootfs->dfd_dev, "pts", 0755);
+               if (ret < 0 && errno != EEXIST)
+                       return log_error_errno(-1, errno, "Failed to create \"/dev/pts\" directory");
 
-       /* gid=5 && !max= */
-       mntopt_sets[2] = default_devpts_mntopts;
+               /* gid=5 && max= */
+               mntopt_sets[0] = devpts_mntopts;
 
-       /* !gid=5 && !max= */
-       mntopt_sets[3] = default_devpts_mntopts + STRLITERALLEN("gid=5") + 1;
+               /* !gid=5 && max= */
+               mntopt_sets[1] = devpts_mntopts + STRLITERALLEN("gid=5") + 1;
 
-       /* end */
-       mntopt_sets[4] = NULL;
+               /* gid=5 && !max= */
+               mntopt_sets[2] = default_devpts_mntopts;
 
-       for (ret = -1, opts = mntopt_sets; opts && *opts; opts++) {
-               /* mount new devpts instance */
-               ret = mount("devpts", "/dev/pts", "devpts", MS_NOSUID | MS_NOEXEC, *opts);
-               if (ret == 0)
-                       break;
-       }
+               /* !gid=5 && !max= */
+               mntopt_sets[3] = default_devpts_mntopts + STRLITERALLEN("gid=5") + 1;
 
-       if (ret < 0)
-               return log_error_errno(-1, errno, "Failed to mount new devpts instance");
-       DEBUG("Mount new devpts instance with options \"%s\"", *opts);
+               /* end */
+               mntopt_sets[4] = NULL;
 
-       devpts_fd = open_at(rootfs->dfd_dev, "pts", PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_BENEATH_XDEV, 0);
-       if (devpts_fd < 0) {
-               devpts_fd = -EBADF;
-               TRACE("Failed to create detached devpts mount");
-       }
+               for (ret = -1, opts = mntopt_sets; opts && *opts; opts++) {
+                       /* mount new devpts instance */
+                       ret = mount("devpts", "/dev/pts", "devpts", MS_NOSUID | MS_NOEXEC, *opts);
+                       if (ret == 0)
+                               break;
+               }
 
-       handler->conf->devpts_fd = move_fd(devpts_fd);
+               if (ret < 0)
+                       return log_error_errno(-1, errno, "Failed to mount new devpts instance");
+
+               devpts_fd = open_at(rootfs->dfd_dev, "pts", PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_BENEATH_XDEV, 0);
+               if (devpts_fd < 0) {
+                       devpts_fd = -EBADF;
+                       TRACE("Failed to create detached devpts mount");
+               }
+
+               handler->conf->devpts_fd = move_fd(devpts_fd);
+               DEBUG("Mounted new devpts instance with options \"%s\"", *opts);
+       }
 
        /* Remove any pre-existing /dev/ptmx file. */
        ret = unlinkat(rootfs->dfd_dev, "ptmx", 0);
@@ -4155,6 +4218,10 @@ int lxc_setup(struct lxc_handler *handler)
        if (ret < 0)
                return log_error(-1, "Failed to mount transient procfs instance for LSMs");
 
+       ret = lxc_prepare_devpts_child(handler);
+       if (ret < 0)
+               return log_error(-1, "Failed to prepare new devpts instance");
+
        ret = lxc_setup_console(handler, &lxc_conf->rootfs, &lxc_conf->console,
                                lxc_conf->ttys.dir);
        if (ret < 0)
@@ -4172,7 +4239,7 @@ int lxc_setup(struct lxc_handler *handler)
        if (lxc_conf->autodev > 0)
                (void)lxc_setup_boot_id();
 
-       ret = lxc_setup_devpts_child(handler);
+       ret = lxc_finalize_devpts_child(handler);
        if (ret < 0)
                return log_error(-1, "Failed to setup new devpts instance");
 
index f6032af9e5b05d8c6e636bba3a054bfaf79ad302..b8aadaea673ba8ac21ee700707f5091da4d9fa09 100644 (file)
@@ -197,6 +197,18 @@ int fs_set_property(int fd_fs, const char *key, const char *val)
        return 0;
 }
 
+int fs_set_flag(int fd_fs, const char *key)
+{
+       int ret;
+
+       ret = fsconfig(fd_fs, FSCONFIG_SET_FLAG, key, NULL, 0);
+       if (ret < 0)
+               return syserror("Failed to set \"%s\" flag on filesystem context %d", key, fd_fs);
+
+       TRACE("Set \"%s\" flag on filesystem context %d", key, fd_fs);
+       return 0;
+}
+
 int fs_attach(int fd_fs,
              int dfd_to, const char *path_to,
              __u64 o_flags_to, __u64 resolve_flags_to,
index 722f80b338409f8e9304b5eacd035d44199f72f0..dcc786f283bd09abd8d7b1785438b3df5f85059e 100644 (file)
@@ -164,6 +164,7 @@ __hidden extern int fs_prepare(const char *fs_name, int dfd_from,
                               const char *path_from, __u64 o_flags_from,
                               __u64 resolve_flags_from);
 __hidden extern int fs_set_property(int fd_fs, const char *key, const char *val);
+__hidden extern int fs_set_flag(int fd_fs, const char *key);
 __hidden extern int fs_attach(int fd_fs, int dfd_to, const char *path_to,
                              __u64 o_flags_to, __u64 resolve_flags_to,
                              unsigned int attr_flags);
index 44f2f3e1e92891ed18cf978b9403cb97ecdf0bf9..a31733c18f46f052417fe72bee2d34c964f0dd49 100644 (file)
@@ -168,12 +168,12 @@ static inline const char *proc_self_fd(int fd)
        return buf;
 }
 
-static inline const char *fdstr(int fd)
+static inline const char *fdstr(__s64 fd)
 {
        static const char *fdstr_invalid = "-EBADF";
-       static char buf[INTTYPE_TO_STRLEN(int)];
+       static char buf[INTTYPE_TO_STRLEN(__s64)];
 
-       if (strnprintf(buf, sizeof(buf), "%d", fd) < 0)
+       if (strnprintf(buf, sizeof(buf), "%lld", fd) < 0)
                return fdstr_invalid;
 
        return buf;