]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/conf.c
Merge pull request #3235 from xinhua9569/master
[mirror_lxc.git] / src / lxc / conf.c
index 986cb89b024bf6bbeedc84a75a36460eda497e98..457e1e16585b71db1069e7baf4fa86ec5b1acfd8 100644 (file)
@@ -1,25 +1,4 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+/* SPDX-License-Identifier: LGPL-2.1+ */
 
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE 1
@@ -57,6 +36,7 @@
 #include "af_unix.h"
 #include "caps.h"
 #include "cgroup.h"
+#include "cgroup2_devices.h"
 #include "conf.h"
 #include "config.h"
 #include "confile.h"
@@ -79,6 +59,7 @@
 #include "syscall_wrappers.h"
 #include "terminal.h"
 #include "utils.h"
+#include "uuid.h"
 
 #ifdef MAJOR_IN_MKDEV
 #include <sys/mkdev.h>
@@ -1025,7 +1006,7 @@ int lxc_allocate_ttys(struct lxc_conf *conf)
                        SYSWARN("Failed to set FD_CLOEXEC flag on slave fd %d of "
                                "tty device \"%s\"", tty->slave, tty->name);
 
-               tty->busy = 0;
+               tty->busy = -1;
        }
 
        INFO("Finished creating %zu tty devices", ttys->max);
@@ -1134,18 +1115,21 @@ on_error:
  * error, log it but don't fail yet.
  */
 static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs,
-                        const char *lxcpath)
+                        int autodevtmpfssize, const char *lxcpath)
 {
        __do_free char *path = NULL;
        int ret;
        size_t clen;
        mode_t cur_mask;
+        char mount_options[128];
 
        INFO("Preparing \"/dev\"");
 
        /* $(rootfs->mount) + "/dev/pts" + '\0' */
        clen = (rootfs->path ? strlen(rootfs->mount) : 0) + 9;
        path = must_realloc(NULL, clen);
+       sprintf(mount_options, "size=%d,mode=755", (autodevtmpfssize != 0) ? autodevtmpfssize : 500000);
+       DEBUG("Using mount options: %s", mount_options);
 
        ret = snprintf(path, clen, "%s/dev", rootfs->path ? rootfs->mount : "");
        if (ret < 0 || (size_t)ret >= clen)
@@ -1159,8 +1143,8 @@ static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs,
                goto reset_umask;
        }
 
-       ret = safe_mount("none", path, "tmpfs", 0, "size=500000,mode=755",
-                        rootfs->path ? rootfs->mount : NULL);
+       ret = safe_mount("none", path, "tmpfs", 0, mount_options,
+                        rootfs->path ? rootfs->mount : NULL );
        if (ret < 0) {
                SYSERROR("Failed to mount tmpfs on \"%s\"", path);
                goto reset_umask;
@@ -1869,16 +1853,21 @@ static void parse_mntopt(char *opt, unsigned long *flags, char **data, size_t si
 {
        struct mount_opt *mo;
 
-       /* If opt is found in mount_opt, set or clear flags.
-        * Otherwise append it to data. */
-
-       for (mo = &mount_opt[0]; mo->name != NULL; mo++) {
-               if (strncmp(opt, mo->name, strlen(mo->name)) == 0) {
-                       if (mo->clear)
-                               *flags &= ~mo->flag;
-                       else
-                               *flags |= mo->flag;
-                       return;
+       /* If '=' is contained in opt, the option must go into data. */
+       if (!strchr(opt, '=')) {
+
+               /* If opt is found in mount_opt, set or clear flags.
+                * Otherwise append it to data. */
+               size_t opt_len = strlen(opt);
+               for (mo = &mount_opt[0]; mo->name != NULL; mo++) {
+                       size_t mo_name_len = strlen(mo->name);
+                       if (opt_len == mo_name_len && strncmp(opt, mo->name, mo_name_len) == 0) {
+                               if (mo->clear)
+                                       *flags &= ~mo->flag;
+                               else
+                                       *flags |= mo->flag;
+                               return;
+                       }
                }
        }
 
@@ -2731,6 +2720,7 @@ struct lxc_conf *lxc_conf_init(void)
        new->logfd = -1;
        lxc_list_init(&new->cgroup);
        lxc_list_init(&new->cgroup2);
+       lxc_list_init(&new->devices);
        lxc_list_init(&new->network);
        lxc_list_init(&new->mount_list);
        lxc_list_init(&new->caps);
@@ -2763,6 +2753,7 @@ struct lxc_conf *lxc_conf_init(void)
        new->init_gid = 0;
        memset(&new->cgroup_meta, 0, sizeof(struct lxc_cgroup));
        memset(&new->ns_share, 0, sizeof(char *) * LXC_NS_MAX);
+       seccomp_conf_init(new);
 
        return new;
 }
@@ -3487,6 +3478,56 @@ static bool execveat_supported(void)
        return true;
 }
 
+static int lxc_setup_boot_id(void)
+{
+       int ret;
+       const char *boot_id_path = "/proc/sys/kernel/random/boot_id";
+       const char *mock_boot_id_path = "/dev/.lxc-boot-id";
+       lxc_id128_t n;
+
+       if (access(boot_id_path, F_OK))
+               return 0;
+
+       memset(&n, 0, sizeof(n));
+       if (lxc_id128_randomize(&n)) {
+               SYSERROR("Failed to generate random data for uuid");
+               return -1;
+       }
+
+       ret = lxc_id128_write(mock_boot_id_path, n);
+       if (ret < 0) {
+               SYSERROR("Failed to write uuid to %s", mock_boot_id_path);
+               return -1;
+       }
+
+       ret = chmod(mock_boot_id_path, 0444);
+       if (ret < 0) {
+               SYSERROR("Failed to chown %s", mock_boot_id_path);
+               (void)unlink(mock_boot_id_path);
+               return -1;
+       }
+
+       ret = mount(mock_boot_id_path, boot_id_path, NULL, MS_BIND, NULL);
+       if (ret < 0) {
+               SYSERROR("Failed to mount %s to %s", mock_boot_id_path,
+                        boot_id_path);
+               (void)unlink(mock_boot_id_path);
+               return -1;
+       }
+
+       ret = mount(NULL, boot_id_path, NULL,
+                   (MS_BIND | MS_REMOUNT | MS_RDONLY | MS_NOSUID | MS_NOEXEC |
+                    MS_NODEV),
+                   NULL);
+       if (ret < 0) {
+               SYSERROR("Failed to remount %s read-only", boot_id_path);
+               (void)unlink(mock_boot_id_path);
+               return -1;
+       }
+
+       return 0;
+}
+
 int lxc_setup(struct lxc_handler *handler)
 {
        int ret;
@@ -3511,20 +3552,23 @@ int lxc_setup(struct lxc_handler *handler)
        if (ret < 0)
                return -1;
 
-       ret = lxc_setup_network_in_child_namespaces(lxc_conf, &lxc_conf->network);
-       if (ret < 0) {
-               ERROR("Failed to setup network");
-               return -1;
-       }
+       if (handler->ns_clone_flags & CLONE_NEWNET) {
+               ret = lxc_setup_network_in_child_namespaces(lxc_conf,
+                                                           &lxc_conf->network);
+               if (ret < 0) {
+                       ERROR("Failed to setup network");
+                       return -1;
+               }
 
-       ret = lxc_network_send_name_and_ifindex_to_parent(handler);
-       if (ret < 0) {
-               ERROR("Failed to send network device names and ifindices to parent");
-               return -1;
+               ret = lxc_network_send_name_and_ifindex_to_parent(handler);
+               if (ret < 0) {
+                       ERROR("Failed to send network device names and ifindices to parent");
+                       return -1;
+               }
        }
 
        if (lxc_conf->autodev > 0) {
-               ret = mount_autodev(name, &lxc_conf->rootfs, lxcpath);
+               ret = mount_autodev(name, &lxc_conf->rootfs, lxc_conf->autodevtmpfssize, lxcpath);
                if (ret < 0) {
                        ERROR("Failed to mount \"/dev\"");
                        return -1;
@@ -3644,6 +3688,10 @@ int lxc_setup(struct lxc_handler *handler)
                return -1;
        }
 
+       /* Setting the boot-id is best-effort for now. */
+       if (lxc_conf->autodev > 0)
+               (void)lxc_setup_boot_id();
+
        ret = lxc_setup_devpts(lxc_conf);
        if (ret < 0) {
                ERROR("Failed to setup new devpts instance");
@@ -3698,29 +3746,14 @@ int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf,
                  char *argv[])
 {
        struct lxc_list *it;
-       int which = -1;
-
-       if (strcmp(hookname, "pre-start") == 0)
-               which = LXCHOOK_PRESTART;
-       else if (strcmp(hookname, "start-host") == 0)
-               which = LXCHOOK_START_HOST;
-       else if (strcmp(hookname, "pre-mount") == 0)
-               which = LXCHOOK_PREMOUNT;
-       else if (strcmp(hookname, "mount") == 0)
-               which = LXCHOOK_MOUNT;
-       else if (strcmp(hookname, "autodev") == 0)
-               which = LXCHOOK_AUTODEV;
-       else if (strcmp(hookname, "start") == 0)
-               which = LXCHOOK_START;
-       else if (strcmp(hookname, "stop") == 0)
-               which = LXCHOOK_STOP;
-       else if (strcmp(hookname, "post-stop") == 0)
-               which = LXCHOOK_POSTSTOP;
-       else if (strcmp(hookname, "clone") == 0)
-               which = LXCHOOK_CLONE;
-       else if (strcmp(hookname, "destroy") == 0)
-               which = LXCHOOK_DESTROY;
-       else
+       int which;
+
+       for (which = 0; which < NUM_LXC_HOOKS; which ++) {
+               if (strcmp(hookname, lxchook_names[which]) == 0)
+                       break;
+       }
+
+       if (which >= NUM_LXC_HOOKS)
                return -1;
 
        lxc_list_for_each (it, &conf->hooks[which]) {
@@ -3835,6 +3868,17 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version)
        return 0;
 }
 
+static void lxc_clear_devices(struct lxc_conf *conf)
+{
+       struct lxc_list *list = &conf->devices;
+       struct lxc_list *it, *next;
+
+       lxc_list_for_each_safe(it, list, next) {
+               lxc_list_del(it);
+               free(it);
+       }
+}
+
 int lxc_clear_limits(struct lxc_conf *c, const char *key)
 {
        struct lxc_list *it, *next;
@@ -4049,6 +4093,7 @@ void lxc_conf_free(struct lxc_conf *conf)
        free(conf->rootfs.bdev_type);
        free(conf->rootfs.options);
        free(conf->rootfs.path);
+       free(conf->rootfs.data);
        free(conf->logfile);
        if (conf->logfd != -1)
                close(conf->logfd);
@@ -4066,11 +4111,13 @@ void lxc_conf_free(struct lxc_conf *conf)
        free(conf->lsm_aa_profile);
        free(conf->lsm_aa_profile_computed);
        free(conf->lsm_se_context);
-       lxc_seccomp_free(conf);
+       lxc_seccomp_free(&conf->seccomp);
        lxc_clear_config_caps(conf);
        lxc_clear_config_keepcaps(conf);
        lxc_clear_cgroups(conf, "lxc.cgroup", CGROUP_SUPER_MAGIC);
        lxc_clear_cgroups(conf, "lxc.cgroup2", CGROUP2_SUPER_MAGIC);
+       lxc_clear_devices(conf);
+       lxc_clear_cgroup2_devices(conf);
        lxc_clear_hooks(conf, "lxc.hook");
        lxc_clear_mount_entries(conf);
        lxc_clear_idmaps(conf);
@@ -4336,7 +4383,7 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
        d.p[1] = p[1];
 
        /* Clone child in new user namespace. */
-       pid = lxc_raw_clone_cb(run_userns_fn, &d, CLONE_NEWUSER);
+       pid = lxc_raw_clone_cb(run_userns_fn, &d, CLONE_NEWUSER, NULL);
        if (pid < 0) {
                ERROR("Failed to clone process in new user namespace");
                goto on_error;
@@ -4418,7 +4465,7 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
        d.p[1] = p[1];
 
        /* Clone child in new user namespace. */
-       pid = lxc_clone(run_userns_fn, &d, CLONE_NEWUSER);
+       pid = lxc_clone(run_userns_fn, &d, CLONE_NEWUSER, NULL);
        if (pid < 0) {
                ERROR("Failed to clone process in new user namespace");
                goto on_error;