-/*
- * 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>
static int run_buffer(char *buffer)
{
__do_free char *output = NULL;
- int ret;
+ int fd, ret;
struct lxc_popen_FILE *f;
f = lxc_popen(buffer);
return -1;
}
- while (fgets(output, LXC_LOG_BUFFER_SIZE, f->f))
- DEBUG("Script %s with output: %s", buffer, output);
+ fd = fileno(f->f);
+ if (fd < 0) {
+ SYSERROR("Failed to retrieve underlying file descriptor");
+ lxc_pclose(f);
+ return -1;
+ }
+
+ for (int i = 0; i < 10; i++) {
+ ssize_t bytes_read;
+
+ bytes_read = lxc_read_nointr(fd, output, LXC_LOG_BUFFER_SIZE - 1);
+ if (bytes_read > 0) {
+ output[bytes_read] = '\0';
+ DEBUG("Script %s produced output: %s", buffer, output);
+ continue;
+ }
+
+ break;
+ }
ret = lxc_pclose(f);
if (ret == -1) {
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;
*/
ret = open(path, O_RDONLY | O_CLOEXEC);
if (ret >= 0) {
- close(ret);
+ close_prot_errno_disarm(ret);
/* Device nodes are fully useable. */
use_mknod = LXC_DEVNODE_OPEN;
continue;
{
__do_free char *nroot = NULL;
int i, ret;
- char *p, *p2;
- char buf[LXC_LINELEN];
- FILE *f;
char *root = rootfs->mount;
nroot = realpath(root, NULL);
* inherited mounts are locked and we should live with all this trash.
*/
for (;;) {
+ __do_fclose FILE *f = NULL;
+ __do_free char *line = NULL;
+ char *slider1, *slider2;
int progress = 0;
+ size_t len = 0;
f = fopen("./proc/self/mountinfo", "r");
if (!f) {
return -1;
}
- while (fgets(buf, LXC_LINELEN, f)) {
- for (p = buf, i=0; p && i < 4; i++)
- p = strchr(p+1, ' ');
+ while (getline(&line, &len, f) > 0) {
+ for (slider1 = line, i = 0; slider1 && i < 4; i++)
+ slider1 = strchr(slider1 + 1, ' ');
- if (!p)
+ if (!slider1)
continue;
- p2 = strchr(p+1, ' ');
- if (!p2)
+ slider2 = strchr(slider1 + 1, ' ');
+ if (!slider2)
continue;
- *p2 = '\0';
- *p = '.';
+ *slider2 = '\0';
+ *slider1 = '.';
- if (strcmp(p + 1, "/") == 0)
+ if (strcmp(slider1 + 1, "/") == 0)
continue;
- if (strcmp(p + 1, "/proc") == 0)
+ if (strcmp(slider1 + 1, "/proc") == 0)
continue;
- ret = umount2(p, MNT_DETACH);
+ ret = umount2(slider1, MNT_DETACH);
if (ret == 0)
progress++;
}
- fclose(f);
-
if (!progress)
break;
}
*/
static int lxc_pivot_root(const char *rootfs)
{
- int oldroot;
- int newroot = -1, ret = -1;
+ __do_close_prot_errno int oldroot = -EBADF, newroot = -EBADF;
+ int ret;
oldroot = open("/", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
if (oldroot < 0) {
newroot = open(rootfs, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
if (newroot < 0) {
SYSERROR("Failed to open new root directory");
- goto on_error;
+ return -1;
}
/* change into new root fs */
ret = fchdir(newroot);
if (ret < 0) {
- ret = -1;
SYSERROR("Failed to change to new rootfs \"%s\"", rootfs);
- goto on_error;
+ return -1;
}
/* pivot_root into our new root fs */
ret = pivot_root(".", ".");
if (ret < 0) {
- ret = -1;
SYSERROR("Failed to pivot_root()");
- goto on_error;
+ return -1;
}
/* At this point the old-root is mounted on top of our new-root. To
*/
ret = fchdir(oldroot);
if (ret < 0) {
- ret = -1;
SYSERROR("Failed to enter old root directory");
- goto on_error;
+ return -1;
}
/* Make oldroot rslave to make sure our umounts don't propagate to the
*/
ret = mount("", ".", "", MS_SLAVE | MS_REC, NULL);
if (ret < 0) {
- ret = -1;
SYSERROR("Failed to make oldroot rslave");
- goto on_error;
+ return -1;
}
ret = umount2(".", MNT_DETACH);
if (ret < 0) {
- ret = -1;
SYSERROR("Failed to detach old root directory");
- goto on_error;
+ return -1;
}
ret = fchdir(newroot);
if (ret < 0) {
- ret = -1;
SYSERROR("Failed to re-enter new root directory");
- goto on_error;
+ return -1;
}
- ret = 0;
-
TRACE("pivot_root(\"%s\") successful", rootfs);
-on_error:
- close(oldroot);
-
- if (newroot >= 0)
- close(newroot);
-
- return ret;
+ return 0;
}
static int lxc_setup_rootfs_switch_root(const struct lxc_rootfs *rootfs)
{
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;
+ }
}
}
const char *lxc_name,
const char *lxc_path)
{
+ __do_free char *mntdata = NULL;
int ret;
unsigned long mntflags;
- char *mntdata;
bool dev, optional, relative;
unsigned long pflags = 0;
char *rootfs_path = NULL;
ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, mntflags,
pflags, mntdata, optional, dev, relative, rootfs_path);
- free(mntdata);
return ret;
}
FILE *make_anonymous_mount_file(struct lxc_list *mount,
bool include_nesting_helpers)
{
+ __do_close_prot_errno int fd = -EBADF;
int ret;
char *mount_entry;
struct lxc_list *iterator;
- int fd = -1;
fd = memfd_create(".lxc_mount_file", MFD_CLOEXEC);
if (fd < 0) {
ret = lxc_write_nointr(fd, mount_entry, len);
if (ret != len)
- goto on_error;
+ return NULL;
ret = lxc_write_nointr(fd, "\n", 1);
if (ret != 1)
- goto on_error;
+ return NULL;
}
if (include_nesting_helpers) {
ret = lxc_write_nointr(fd, nesting_helpers,
STRARRAYLEN(nesting_helpers));
if (ret != STRARRAYLEN(nesting_helpers))
- goto on_error;
+ return NULL;
}
ret = lseek(fd, 0, SEEK_SET);
if (ret < 0)
- goto on_error;
-
- return fdopen(fd, "r+");
+ return NULL;
-on_error:
- SYSERROR("Failed to write mount entry to temporary mount file");
- close(fd);
- return NULL;
+ return fdopen(move_fd(fd), "r+");
}
static int setup_mount_entries(const struct lxc_conf *conf,
struct lxc_list *mount, const char *lxc_name,
const char *lxc_path)
{
- int ret;
- FILE *f;
+ __do_fclose FILE *f = NULL;
f = make_anonymous_mount_file(mount, conf->lsm_aa_allow_nesting);
if (!f)
return -1;
- ret = mount_file_entries(conf, rootfs, f, lxc_name, lxc_path);
- fclose(f);
-
- return ret;
+ return mount_file_entries(conf, rootfs, f, lxc_name, lxc_path);
}
static int parse_cap(const char *cap)
int setup_sysctl_parameters(struct lxc_list *sysctls)
{
+ __do_free char *tmp = NULL;
struct lxc_list *it;
struct lxc_sysctl *elem;
int ret = 0;
- char *tmp = NULL;
char filename[PATH_MAX] = {0};
lxc_list_for_each (it, sysctls) {
}
ret = snprintf(filename, sizeof(filename), "/proc/sys/%s", tmp);
- free(tmp);
if (ret < 0 || (size_t)ret >= sizeof(filename)) {
ERROR("Error setting up sysctl parameters path");
return -1;
int setup_proc_filesystem(struct lxc_list *procs, pid_t pid)
{
+ __do_free char *tmp = NULL;
struct lxc_list *it;
struct lxc_proc *elem;
int ret = 0;
- char *tmp = NULL;
char filename[PATH_MAX] = {0};
lxc_list_for_each (it, procs) {
}
ret = snprintf(filename, sizeof(filename), "/proc/%d/%s", pid, tmp);
- free(tmp);
if (ret < 0 || (size_t)ret >= sizeof(filename)) {
ERROR("Error setting up proc filesystem path");
return -1;
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);
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;
}
int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
size_t buf_size)
{
- int fd, ret;
+ __do_close_prot_errno int fd = -EBADF;
+ int ret;
char path[PATH_MAX];
if (geteuid() != 0 && idtype == ID_TYPE_GID) {
- size_t buflen;
+ __do_close_prot_errno int setgroups_fd = -EBADF;
ret = snprintf(path, PATH_MAX, "/proc/%d/setgroups", pid);
if (ret < 0 || ret >= PATH_MAX)
return -E2BIG;
- fd = open(path, O_WRONLY);
- if (fd < 0 && errno != ENOENT) {
+ setgroups_fd = open(path, O_WRONLY);
+ if (setgroups_fd < 0 && errno != ENOENT) {
SYSERROR("Failed to open \"%s\"", path);
return -1;
}
- if (fd >= 0) {
- buflen = STRLITERALLEN("deny\n");
- errno = 0;
- ret = lxc_write_nointr(fd, "deny\n", buflen);
- close(fd);
- if (ret != buflen) {
- SYSERROR("Failed to write \"deny\" to "
- "\"/proc/%d/setgroups\"", pid);
+ if (setgroups_fd >= 0) {
+ ret = lxc_write_nointr(setgroups_fd, "deny\n",
+ STRLITERALLEN("deny\n"));
+ if (ret != STRLITERALLEN("deny\n")) {
+ SYSERROR("Failed to write \"deny\" to \"/proc/%d/setgroups\"", pid);
return -1;
}
TRACE("Wrote \"deny\" to \"/proc/%d/setgroups\"", pid);
return -1;
}
- errno = 0;
ret = lxc_write_nointr(fd, buf, buf_size);
- close(fd);
if (ret != buf_size) {
SYSERROR("Failed to write %cid mapping to \"%s\"",
idtype == ID_TYPE_UID ? 'u' : 'g', path);
*/
static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
{
- char *path;
+ __do_free char *path = NULL;
int ret;
struct stat st;
- int fret = 0;
+ errno = EINVAL;
if (cap != CAP_SETUID && cap != CAP_SETGID)
- return -EINVAL;
+ return -1;
+ errno = ENOENT;
path = on_path(binary, NULL);
if (!path)
- return -ENOENT;
+ return -1;
ret = stat(path, &st);
- if (ret < 0) {
- fret = -errno;
- goto cleanup;
- }
+ if (ret < 0)
+ return -1;
/* Check if the binary is setuid. */
if (st.st_mode & S_ISUID) {
DEBUG("The binary \"%s\" does have the setuid bit set", path);
- fret = 1;
- goto cleanup;
+ return 1;
}
#if HAVE_LIBCAP && LIBCAP_SUPPORTS_FILE_CAPABILITIES
lxc_file_cap_is_set(path, CAP_SETUID, CAP_PERMITTED)) {
DEBUG("The binary \"%s\" has CAP_SETUID in its CAP_EFFECTIVE "
"and CAP_PERMITTED sets", path);
- fret = 1;
- goto cleanup;
+ return 1;
}
/* Check if it has the CAP_SETGID capability. */
lxc_file_cap_is_set(path, CAP_SETGID, CAP_PERMITTED)) {
DEBUG("The binary \"%s\" has CAP_SETGID in its CAP_EFFECTIVE "
"and CAP_PERMITTED sets", path);
- fret = 1;
- goto cleanup;
+ return 1;
}
#else
/* If we cannot check for file capabilities we need to give the benefit
*/
DEBUG("Cannot check for file capabilities as full capability support is "
"missing. Manual intervention needed");
- fret = 1;
#endif
-cleanup:
- free(path);
- return fret;
+ return 1;
}
int lxc_map_ids_exec_wrapper(void *args)
/* Walk /proc/mounts and change any shared entries to slave. */
void remount_all_slave(void)
{
- int memfd, mntinfo_fd, ret;
+ __do_free char *line = NULL;
+ __do_fclose FILE *f = NULL;
+ __do_close_prot_errno int memfd = -EBADF, mntinfo_fd = -EBADF;
+ int ret;
ssize_t copied;
- FILE *f;
size_t len = 0;
- char *line = NULL;
mntinfo_fd = open("/proc/self/mountinfo", O_RDONLY | O_CLOEXEC);
if (mntinfo_fd < 0) {
if (errno != ENOSYS) {
SYSERROR("Failed to create temporary in-memory file");
- close(mntinfo_fd);
return;
}
memfd = lxc_make_tmpfile(template, true);
if (memfd < 0) {
- close(mntinfo_fd);
WARN("Failed to create temporary file");
return;
}
goto again;
SYSERROR("Failed to copy \"/proc/self/mountinfo\"");
- close(mntinfo_fd);
- close(memfd);
return;
}
- close(mntinfo_fd);
- /* After a successful fdopen() memfd will be closed when calling
- * fclose(f). Calling close(memfd) afterwards is undefined.
- */
ret = lseek(memfd, 0, SEEK_SET);
if (ret < 0) {
SYSERROR("Failed to reset file descriptor offset");
- close(memfd);
return;
}
f = fdopen(memfd, "r");
if (!f) {
- SYSERROR("Failed to open copy of \"/proc/self/mountinfo\" to mark "
- "all shared. Continuing");
- close(memfd);
+ SYSERROR("Failed to open copy of \"/proc/self/mountinfo\" to mark all shared. Continuing");
return;
}
+ /*
+ * After a successful fdopen() memfd will be closed when calling
+ * fclose(f). Calling close(memfd) afterwards is undefined.
+ */
+ move_fd(memfd);
+
while (getline(&line, &len, f) != -1) {
char *opts, *target;
}
TRACE("Remounted \"%s\" as MS_SLAVE", target);
}
- fclose(f);
- free(line);
TRACE("Remounted all mount table entries as MS_SLAVE");
}
/* If init exists in the container, don't bind mount a static one */
p = choose_init(conf->rootfs.mount);
if (p) {
- char *old = p;
+ __do_free char *old = p;
p = strdup(old + strlen(conf->rootfs.mount));
- free(old);
if (!p)
return -ENOMEM;
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;
}
+ if (!lxc_list_empty(&lxc_conf->mount_list)) {
+ ret = setup_mount_entries(lxc_conf, &lxc_conf->rootfs,
+ &lxc_conf->mount_list, name, lxcpath);
+ if (ret < 0) {
+ ERROR("Failed to setup mount entries");
+ return -1;
+ }
+ }
+
if (lxc_conf->is_execute) {
if (execveat_supported()) {
int fd;
}
}
- if (!lxc_list_empty(&lxc_conf->mount_list)) {
- ret = setup_mount_entries(lxc_conf, &lxc_conf->rootfs,
- &lxc_conf->mount_list, name, lxcpath);
- if (ret < 0) {
- ERROR("Failed to setup mount entries");
- return -1;
- }
- }
-
/* Make sure any start hooks are in the container */
if (!verify_start_hooks(lxc_conf)) {
ERROR("Failed to verify start hooks");
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);
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);
struct lxc_list *get_minimal_idmap(struct lxc_conf *conf)
{
+ __do_free struct id_map *container_root_uid = NULL,
+ *container_root_gid = NULL,
+ *host_uid_map = NULL, *host_gid_map = NULL;
+ __do_free struct lxc_list *idmap = NULL;
uid_t euid, egid;
uid_t nsuid = (conf->root_nsuid_map != NULL) ? 0 : conf->init_uid;
gid_t nsgid = (conf->root_nsgid_map != NULL) ? 0 : conf->init_gid;
- struct lxc_list *idmap = NULL, *tmplist = NULL;
- struct id_map *container_root_uid = NULL, *container_root_gid = NULL,
- *host_uid_map = NULL, *host_gid_map = NULL;
+ struct lxc_list *tmplist = NULL;
/* Find container root mappings. */
container_root_uid = mapped_nsid_add(conf, nsuid, ID_TYPE_UID);
if (!container_root_uid) {
DEBUG("Failed to find mapping for namespace uid %d", 0);
- goto on_error;
+ return NULL;
}
euid = geteuid();
if (euid >= container_root_uid->hostid &&
container_root_gid = mapped_nsid_add(conf, nsgid, ID_TYPE_GID);
if (!container_root_gid) {
DEBUG("Failed to find mapping for namespace gid %d", 0);
- goto on_error;
+ return NULL;
}
egid = getegid();
if (egid >= container_root_gid->hostid &&
host_uid_map = mapped_hostid_add(conf, euid, ID_TYPE_UID);
if (!host_uid_map) {
DEBUG("Failed to find mapping for uid %d", euid);
- goto on_error;
+ return NULL;
}
if (!host_gid_map)
host_gid_map = mapped_hostid_add(conf, egid, ID_TYPE_GID);
if (!host_gid_map) {
DEBUG("Failed to find mapping for gid %d", egid);
- goto on_error;
+ return NULL;
}
/* Allocate new {g,u}id map list. */
idmap = malloc(sizeof(*idmap));
if (!idmap)
- goto on_error;
+ return NULL;
lxc_list_init(idmap);
/* Add container root to the map. */
tmplist = malloc(sizeof(*tmplist));
if (!tmplist)
- goto on_error;
+ return NULL;
lxc_list_add_elem(tmplist, container_root_uid);
lxc_list_add_tail(idmap, tmplist);
if (host_uid_map && (host_uid_map != container_root_uid)) {
/* idmap will now keep track of that memory. */
- container_root_uid = NULL;
+ move_ptr(container_root_uid);
/* Add container root to the map. */
tmplist = malloc(sizeof(*tmplist));
if (!tmplist)
- goto on_error;
+ return NULL;
lxc_list_add_elem(tmplist, host_uid_map);
lxc_list_add_tail(idmap, tmplist);
}
/* idmap will now keep track of that memory. */
- container_root_uid = NULL;
+ move_ptr(container_root_uid);
/* idmap will now keep track of that memory. */
- host_uid_map = NULL;
+ move_ptr(host_uid_map);
tmplist = malloc(sizeof(*tmplist));
if (!tmplist)
- goto on_error;
+ return NULL;
lxc_list_add_elem(tmplist, container_root_gid);
lxc_list_add_tail(idmap, tmplist);
if (host_gid_map && (host_gid_map != container_root_gid)) {
/* idmap will now keep track of that memory. */
- container_root_gid = NULL;
+ move_ptr(container_root_gid);
tmplist = malloc(sizeof(*tmplist));
if (!tmplist)
- goto on_error;
+ return NULL;
lxc_list_add_elem(tmplist, host_gid_map);
lxc_list_add_tail(idmap, tmplist);
}
/* idmap will now keep track of that memory. */
- container_root_gid = NULL;
+ move_ptr(container_root_gid);
/* idmap will now keep track of that memory. */
- host_gid_map = NULL;
+ move_ptr(host_gid_map);
TRACE("Allocated minimal idmapping");
- return idmap;
-
-on_error:
- if (idmap) {
- lxc_free_idmap(idmap);
- free(idmap);
- }
- if (container_root_uid)
- free(container_root_uid);
- if (container_root_gid)
- free(container_root_gid);
- if (host_uid_map && (host_uid_map != container_root_uid))
- free(host_uid_map);
- if (host_gid_map && (host_gid_map != container_root_gid))
- free(host_gid_map);
-
- return NULL;
+ return move_ptr(idmap);
}
/* Run a function in a new user namespace.
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;
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;
/* not thread-safe, do not use from api without first forking */
static char *getuname(void)
{
+ __do_free char *buf = NULL;
struct passwd pwent;
struct passwd *pwentp = NULL;
- char *buf;
- char *username;
size_t bufsize;
int ret;
WARN("Could not find matched password record.");
ERROR("Failed to get password record - %u", geteuid());
- free(buf);
return NULL;
}
- username = strdup(pwent.pw_name);
- free(buf);
-
- return username;
+ return strdup(pwent.pw_name);
}
/* not thread-safe, do not use from api without first forking */
static char *getgname(void)
{
+ __do_free char *buf = NULL;
struct group grent;
struct group *grentp = NULL;
- char *buf;
- char *grname;
size_t bufsize;
int ret;
WARN("Could not find matched group record");
ERROR("Failed to get group record - %u", getegid());
- free(buf);
return NULL;
}
- grname = strdup(grent.gr_name);
- free(buf);
-
- return grname;
+ return strdup(grent.gr_name);
}
/* not thread-safe, do not use from api without first forking */
void suggest_default_idmap(void)
{
- char *uname, *gname;
- FILE *f;
+ __do_free char *gname = NULL, *line = NULL, *uname = NULL;
+ __do_fclose FILE *subuid_f = NULL, *subgid_f = NULL;
unsigned int uid = 0, urange = 0, gid = 0, grange = 0;
size_t len = 0;
- char *line = NULL;
uname = getuname();
if (!uname)
return;
gname = getgname();
- if (!gname) {
- free(uname);
+ if (!gname)
return;
- }
- f = fopen(subuidfile, "r");
- if (!f) {
+ subuid_f = fopen(subuidfile, "r");
+ if (!subuid_f) {
ERROR("Your system is not configured with subuids");
- free(gname);
- free(uname);
return;
}
- while (getline(&line, &len, f) != -1) {
+ while (getline(&line, &len, subuid_f) != -1) {
char *p, *p2;
size_t no_newline = 0;
if (lxc_safe_uint(p2, &urange) < 0)
WARN("Could not parse UID range");
}
- fclose(f);
- f = fopen(subgidfile, "r");
- if (!f) {
+ subgid_f = fopen(subgidfile, "r");
+ if (!subgid_f) {
ERROR("Your system is not configured with subgids");
- free(gname);
- free(uname);
return;
}
- while (getline(&line, &len, f) != -1) {
+ while (getline(&line, &len, subgid_f) != -1) {
char *p, *p2;
size_t no_newline = 0;
if (lxc_safe_uint(p2, &grange) < 0)
WARN("Could not parse GID range");
}
- fclose(f);
-
- free(line);
if (!urange || !grange) {
ERROR("You do not have subuids or subgids allocated");
ERROR("Unprivileged containers require subuids and subgids");
- free(uname);
- free(gname);
return;
}
ERROR("lxc.include = %s", LXC_DEFAULT_CONFIG);
ERROR("lxc.idmap = u 0 %u %u", uid, urange);
ERROR("lxc.idmap = g 0 %u %u", gid, grange);
-
- free(gname);
- free(uname);
}
static void free_cgroup_settings(struct lxc_list *result)