-/*
- * 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
#include "af_unix.h"
#include "caps.h"
#include "cgroup.h"
+#include "cgroup2_devices.h"
#include "conf.h"
#include "config.h"
#include "confile.h"
#include "syscall_wrappers.h"
#include "terminal.h"
#include "utils.h"
+#include "uuid.h"
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
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);
* 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)
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;
{
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;
+ }
}
}
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);
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;
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;
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");
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]) {
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;
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);
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);
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;