* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#define _GNU_SOURCE
-#include "config.h"
-#include "confile.h"
-
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
#include <arpa/inet.h>
#include <dirent.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
+#include "af_unix.h"
+#include "caps.h"
+#include "cgroup.h"
+#include "conf.h"
+#include "config.h"
+#include "confile.h"
+#include "confile_utils.h"
+#include "error.h"
+#include "log.h"
+#include "lsm/lsm.h"
+#include "lxclock.h"
+#include "lxcseccomp.h"
+#include "macro.h"
+#include "memory_utils.h"
+#include "namespace.h"
+#include "network.h"
+#include "parse.h"
+#include "raw_syscalls.h"
+#include "ringbuf.h"
+#include "start.h"
+#include "storage.h"
+#include "storage/overlay.h"
+#include "syscall_wrappers.h"
+#include "terminal.h"
+#include "utils.h"
+
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#endif
#include <../include/prlimit.h>
#endif
-#include "af_unix.h"
-#include "caps.h"
-#include "cgroup.h"
-#include "conf.h"
-#include "confile_utils.h"
-#include "error.h"
-#include "log.h"
-#include "lsm/lsm.h"
-#include "lxclock.h"
-#include "lxcseccomp.h"
-#include "macro.h"
-#include "namespace.h"
-#include "network.h"
-#include "parse.h"
-#include "ringbuf.h"
-#include "start.h"
-#include "storage.h"
-#include "storage/overlay.h"
-#include "terminal.h"
-#include "utils.h"
-
lxc_log_define(conf, lxc);
/* The lxc_conf of the container currently being worked on in an API call.
struct lxc_conf *current_config;
#endif
-/* Define pivot_root() if missing from the C library */
-#ifndef HAVE_PIVOT_ROOT
-static int pivot_root(const char *new_root, const char *put_old)
-{
-#ifdef __NR_pivot_root
- return syscall(__NR_pivot_root, new_root, put_old);
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-#else
-extern int pivot_root(const char *new_root, const char *put_old);
-#endif
-
char *lxchook_names[NUM_LXC_HOOKS] = {
"pre-start",
"pre-mount",
static int run_buffer(char *buffer)
{
+ __do_free char *output = NULL;
int ret;
- char *output;
struct lxc_popen_FILE *f;
f = lxc_popen(buffer);
while (fgets(output, LXC_LOG_BUFFER_SIZE, f->f))
DEBUG("Script %s with output: %s", buffer, output);
- free(output);
-
ret = lxc_pclose(f);
if (ret == -1) {
SYSERROR("Script exited with error");
const char *section, const char *script,
const char *hookname, char **argv)
{
+ __do_free char *buffer = NULL;
int buf_pos, i, ret;
- char *buffer;
- int fret = -1;
size_t size = 0;
if (hook_version == 0)
for (i = 0; argv && argv[i]; i++)
size += strlen(argv[i]) + 1;
- size += sizeof("exec");
+ size += STRLITERALLEN("exec");
+ size++;
size += strlen(script);
size++;
buf_pos = snprintf(buffer, size, "exec %s", script);
if (buf_pos < 0 || (size_t)buf_pos >= size) {
ERROR("Failed to create command line for script \"%s\"", script);
- goto on_error;
+ return -1;
}
if (hook_version == 1) {
if (ret < 0) {
SYSERROR("Failed to set environment variable: "
"LXC_HOOK_TYPE=%s", hookname);
- goto on_error;
+ return -1;
}
TRACE("Set environment variable: LXC_HOOK_TYPE=%s", hookname);
if (ret < 0) {
SYSERROR("Failed to set environment variable: "
"LXC_HOOK_SECTION=%s", section);
- goto on_error;
+ return -1;
}
TRACE("Set environment variable: LXC_HOOK_SECTION=%s", section);
char *parent;
if (!argv || !argv[0])
- goto on_error;
+ return -1;
ret = setenv("LXC_NET_TYPE", argv[0], 1);
if (ret < 0) {
SYSERROR("Failed to set environment variable: "
"LXC_NET_TYPE=%s", argv[0]);
- goto on_error;
+ return -1;
}
TRACE("Set environment variable: LXC_NET_TYPE=%s", argv[0]);
if (ret < 0) {
SYSERROR("Failed to set environment "
"variable: LXC_NET_PARENT=%s", parent);
- goto on_error;
+ return -1;
}
TRACE("Set environment variable: LXC_NET_PARENT=%s", parent);
} else if (strcmp(argv[0], "phys") == 0) {
if (ret < 0) {
SYSERROR("Failed to set environment "
"variable: LXC_NET_PARENT=%s", parent);
- goto on_error;
+ return -1;
}
TRACE("Set environment variable: LXC_NET_PARENT=%s", parent);
} else if (strcmp(argv[0], "veth") == 0) {
if (ret < 0) {
SYSERROR("Failed to set environment "
"variable: LXC_NET_PEER=%s", peer);
- goto on_error;
+ return -1;
}
TRACE("Set environment variable: LXC_NET_PEER=%s", peer);
if (ret < 0) {
SYSERROR("Failed to set environment "
"variable: LXC_NET_PARENT=%s", parent);
- goto on_error;
+ return -1;
}
TRACE("Set environment variable: LXC_NET_PARENT=%s", parent);
}
ret = snprintf(buffer + buf_pos, len, " %s", argv[i]);
if (ret < 0 || (size_t)ret >= len) {
ERROR("Failed to create command line for script \"%s\"", script);
- goto on_error;
+ return -1;
}
buf_pos += ret;
}
- fret = run_buffer(buffer);
-
-on_error:
- free(buffer);
- return fret;
+ return run_buffer(buffer);
}
int run_script(const char *name, const char *section, const char *script, ...)
{
+ __do_free char *buffer = NULL;
int ret;
- char *buffer, *p;
+ char *p;
va_list ap;
size_t size = 0;
size += strlen(p) + 1;
va_end(ap);
- size += strlen("exec");
+ size += STRLITERALLEN("exec");
size += strlen(script);
size += strlen(name);
size += strlen(section);
if (size > INT_MAX)
return -1;
- buffer = alloca(size);
+ buffer = must_realloc(NULL, size);
ret = snprintf(buffer, size, "exec %s %s %s", script, name, section);
if (ret < 0 || ret >= size)
return -1;
*/
int pin_rootfs(const char *rootfs)
{
+ __do_free char *absrootfs = NULL;
int fd, ret;
- char absrootfs[MAXPATHLEN], absrootfspin[MAXPATHLEN];
+ char absrootfspin[PATH_MAX];
struct stat s;
struct statfs sfs;
if (rootfs == NULL || strlen(rootfs) == 0)
return -2;
- if (!realpath(rootfs, absrootfs))
+ absrootfs = realpath(rootfs, NULL);
+ if (!absrootfs)
return -2;
ret = stat(absrootfs, &s);
if (!S_ISDIR(s.st_mode))
return -2;
- ret = snprintf(absrootfspin, MAXPATHLEN, "%s/.lxc-keep", absrootfs);
- if (ret >= MAXPATHLEN)
+ ret = snprintf(absrootfspin, PATH_MAX, "%s/.lxc-keep", absrootfs);
+ if (ret < 0 || ret >= PATH_MAX)
return -1;
fd = open(absrootfspin, O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
static int add_shmount_to_list(struct lxc_conf *conf)
{
- char new_mount[MAXPATHLEN];
+ char new_mount[PATH_MAX];
/* Offset for the leading '/' since the path_cont
* is absolute inside the container.
*/
};
for (i = 0; default_mounts[i].match_mask; i++) {
+ __do_free char *destination = NULL, *source = NULL;
int saved_errno;
unsigned long mflags;
- char *destination = NULL;
- char *source = NULL;
if ((flags & default_mounts[i].match_mask) != default_mounts[i].match_flag)
continue;
if (!default_mounts[i].destination) {
ERROR("BUG: auto mounts destination %d was NULL", i);
- free(source);
return -1;
}
/* will act like strdup if %r is not present */
destination = lxc_string_replace("%r", conf->rootfs.path ? conf->rootfs.mount : "", default_mounts[i].destination);
if (!destination) {
- saved_errno = errno;
- free(source);
- errno = saved_errno;
return -1;
}
SYSERROR("Failed to mount \"%s\" on \"%s\" with flags %lu", source, destination, mflags);
}
- free(source);
- free(destination);
if (r < 0) {
errno = saved_errno;
return -1;
static int lxc_setup_dev_symlinks(const struct lxc_rootfs *rootfs)
{
int i, ret;
- char path[MAXPATHLEN];
+ char path[PATH_MAX];
struct stat s;
for (i = 0; i < sizeof(dev_symlinks) / sizeof(dev_symlinks[0]); i++) {
ret = snprintf(path, sizeof(path), "%s/dev/%s",
rootfs->path ? rootfs->mount : "", d->name);
- if (ret < 0 || ret >= MAXPATHLEN)
+ if (ret < 0 || ret >= PATH_MAX)
return -1;
/* Stat the path first. If we don't get an error accept it as
int i, ret;
const struct lxc_tty_info *ttys = &conf->ttys;
char *ttydir = ttys->dir;
- char path[MAXPATHLEN], lxcpath[MAXPATHLEN];
+ char path[PATH_MAX], lxcpath[PATH_MAX];
if (!conf->rootfs.path)
return 0;
if (ret < 0)
break;
- TRACE("Sent ty \"%s\" with master fd %d and slave fd %d to "
+ TRACE("Sent tty \"%s\" with master fd %d and slave fd %d to "
"parent", tty->name, tty->master, tty->slave);
}
static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs,
const char *lxcpath)
{
+ __do_free char *path = NULL;
int ret;
size_t clen;
- char *path;
mode_t cur_mask;
INFO("Preparing \"/dev\"");
/* $(rootfs->mount) + "/dev/pts" + '\0' */
clen = (rootfs->path ? strlen(rootfs->mount) : 0) + 9;
- path = alloca(clen);
+ path = must_realloc(NULL, clen);
ret = snprintf(path, clen, "%s/dev", rootfs->path ? rootfs->mount : "");
if (ret < 0 || (size_t)ret >= clen)
static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
{
int i, ret;
- char path[MAXPATHLEN];
+ char path[PATH_MAX];
mode_t cmask;
int use_mknod = LXC_DEVNODE_MKNOD;
- ret = snprintf(path, MAXPATHLEN, "%s/dev",
+ ret = snprintf(path, PATH_MAX, "%s/dev",
rootfs->path ? rootfs->mount : "");
- if (ret < 0 || ret >= MAXPATHLEN)
+ if (ret < 0 || ret >= PATH_MAX)
return -1;
/* ignore, just don't try to fill in */
cmask = umask(S_IXUSR | S_IXGRP | S_IXOTH);
for (i = 0; i < sizeof(lxc_devices) / sizeof(lxc_devices[0]); i++) {
- char hostpath[MAXPATHLEN];
+ char hostpath[PATH_MAX];
const struct lxc_device_node *device = &lxc_devices[i];
- ret = snprintf(path, MAXPATHLEN, "%s/dev/%s",
+ ret = snprintf(path, PATH_MAX, "%s/dev/%s",
rootfs->path ? rootfs->mount : "", device->name);
- if (ret < 0 || ret >= MAXPATHLEN)
+ if (ret < 0 || ret >= PATH_MAX)
return -1;
if (use_mknod >= LXC_DEVNODE_MKNOD) {
*/
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;
}
/* Fallback to bind-mounting the device from the host. */
- ret = snprintf(hostpath, MAXPATHLEN, "/dev/%s", device->name);
- if (ret < 0 || ret >= MAXPATHLEN)
+ ret = snprintf(hostpath, PATH_MAX, "/dev/%s", device->name);
+ if (ret < 0 || ret >= PATH_MAX)
return -1;
ret = safe_mount(hostpath, path, 0, MS_BIND, NULL,
int lxc_chroot(const struct lxc_rootfs *rootfs)
{
+ __do_free char *nroot = NULL;
int i, ret;
char *p, *p2;
- char buf[LXC_LINELEN], nroot[PATH_MAX];
- FILE *f;
+ char buf[LXC_LINELEN];
char *root = rootfs->mount;
- if (!realpath(root, nroot)) {
+ nroot = realpath(root, NULL);
+ if (!nroot) {
SYSERROR("Failed to resolve \"%s\"", root);
return -1;
}
return -1;
}
- /* The following code cleans up inhereted mounts which are not required
+ /* The following code cleans up inherited mounts which are not required
* for CT.
*
* The mountinfo file shows not all mounts, if a few points have been
* unmounted between read operations from the mountinfo. So we need to
* read mountinfo a few times.
*
- * This loop can be skipped if a container uses unserns, because all
+ * This loop can be skipped if a container uses userns, because all
* inherited mounts are locked and we should live with all this trash.
*/
for (;;) {
+ __do_fclose FILE *f = NULL;
int progress = 0;
f = fopen("./proc/self/mountinfo", "r");
progress++;
}
- fclose(f);
-
if (!progress)
break;
}
- /* This also can be skipped if a container uses unserns. */
+ /* This also can be skipped if a container uses userns. */
(void)umount2("./proc", MNT_DETACH);
/* It is weird, but chdir("..") moves us in a new root */
*/
static int lxc_pivot_root(const char *rootfs)
{
- int newroot = -1, oldroot = -1, ret = -1;
+ __do_close_prot_errno int oldroot = -EBADF, newroot = -EBADF;
+ int ret;
- oldroot = open("/", O_DIRECTORY | O_RDONLY);
+ oldroot = open("/", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
if (oldroot < 0) {
SYSERROR("Failed to open old root directory");
return -1;
}
- newroot = open(rootfs, O_DIRECTORY | O_RDONLY);
+ 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:
- if (oldroot != -1)
- close(oldroot);
- if (newroot != -1)
- close(newroot);
-
- return ret;
+ return 0;
}
static int lxc_setup_rootfs_switch_root(const struct lxc_rootfs *rootfs)
if (ret < 0 || (size_t)ret >= sizeof(devpts_mntopts))
return -1;
- ret = umount2("/dev/pts", MNT_DETACH);
- if (ret < 0)
- SYSWARN("Failed to unmount old devpts instance");
- else
- DEBUG("Unmounted old devpts instance");
+ (void)umount2("/dev/pts", MNT_DETACH);
/* Create mountpoint for devpts instance. */
ret = mkdir("/dev/pts", 0755);
mntopt_sets[0] = devpts_mntopts;
/* !gid=5 && max= */
- mntopt_sets[1] = devpts_mntopts + sizeof("gid=5");
+ mntopt_sets[1] = devpts_mntopts + STRLITERALLEN("gid=5") + 1;
/* gid=5 && !max= */
mntopt_sets[2] = default_devpts_mntopts;
/* !gid=5 && !max= */
- mntopt_sets[3] = default_devpts_mntopts + sizeof("gid=5");
+ mntopt_sets[3] = default_devpts_mntopts + STRLITERALLEN("gid=5") + 1;
/* end */
mntopt_sets[4] = NULL;
const struct lxc_terminal *console)
{
int ret;
- char path[MAXPATHLEN];
+ char path[PATH_MAX];
char *rootfs_path = rootfs->path ? rootfs->mount : "";
if (console->path && !strcmp(console->path, "none"))
char *ttydir)
{
int ret;
- char path[MAXPATHLEN], lxcpath[MAXPATHLEN];
+ char path[PATH_MAX], lxcpath[PATH_MAX];
char *rootfs_path = rootfs->path ? rootfs->mount : "";
if (console->path && !strcmp(console->path, "none"))
int parse_mntopts(const char *mntopts, unsigned long *mntflags, char **mntdata)
{
- char *data, *p, *s;
+ __do_free char *data = NULL, *s = NULL;
+ char *p;
size_t size;
*mntdata = NULL;
size = strlen(s) + 1;
data = malloc(size);
- if (!data) {
- free(s);
+ if (!data)
return -1;
- }
*data = 0;
lxc_iterate_parts(p, s, ",")
parse_mntopt(p, mntflags, &data, size);
if (*data)
- *mntdata = data;
- else
- free(data);
- free(s);
+ *mntdata = move_ptr(data);
return 0;
}
int parse_propagationopts(const char *mntopts, unsigned long *pflags)
{
- char *p, *s;
+ __do_free char *s = NULL;
+ char *p;
if (!mntopts)
return 0;
*pflags = 0L;
lxc_iterate_parts(p, s, ",")
parse_propagationopt(p, pflags);
- free(s);
return 0;
}
bool dev, bool relative, const char *rootfs)
{
int ret;
- char srcbuf[MAXPATHLEN];
+ char srcbuf[PATH_MAX];
const char *srcpath = fsname;
#ifdef HAVE_STATVFS
struct statvfs sb;
#endif
if (relative) {
- ret = snprintf(srcbuf, MAXPATHLEN, "%s/%s", rootfs ? rootfs : "/", fsname ? fsname : "");
- if (ret < 0 || ret >= MAXPATHLEN) {
+ ret = snprintf(srcbuf, PATH_MAX, "%s/%s", rootfs ? rootfs : "/", fsname ? fsname : "");
+ if (ret < 0 || ret >= PATH_MAX) {
ERROR("source path is too long");
return -1;
}
}
}
+#ifdef HAVE_STATVFS
+skipremount:
+#endif
if (pflags) {
ret = mount(NULL, target, NULL, pflags, NULL);
if (ret < 0) {
DEBUG("Changed mount propagation for \"%s\"", target);
}
-
-#ifdef HAVE_STATVFS
-skipremount:
-#endif
DEBUG("Mounted \"%s\" on \"%s\" with filesystem type \"%s\"",
srcpath ? srcpath : "(null)", target, fstype);
const struct lxc_rootfs *rootfs,
const char *lxc_name, const char *lxc_path)
{
+ __do_free char *p1 = NULL;
int ret;
- char *p1, *p2;
+ char *p2;
if (strncmp(mntent->mnt_type, "overlay", 7) == 0) {
ret = ovl_mkdir(mntent, rootfs, lxc_name, lxc_path);
p2 = dirname(p1);
ret = mkdir_p(p2, 0755);
- free(p1);
if (ret < 0 && errno != EEXIST) {
SYSERROR("Failed to create directory \"%s\"", path);
return -1;
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;
}
static inline int mount_entry_on_systemfs(struct mntent *mntent)
{
int ret;
- char path[MAXPATHLEN];
+ char path[PATH_MAX];
/* For containers created without a rootfs all mounts are treated as
* absolute paths starting at / on the host.
int offset;
char *aux;
const char *lxcpath;
- char path[MAXPATHLEN];
+ char path[PATH_MAX];
int ret = 0;
lxcpath = lxc_global_config_value("lxc.lxcpath");
/* If rootfs->path is a blockdev path, allow container fstab to use
* <lxcpath>/<name>/rootfs" as the target prefix.
*/
- ret = snprintf(path, MAXPATHLEN, "%s/%s/rootfs", lxcpath, lxc_name);
- if (ret < 0 || ret >= MAXPATHLEN)
+ ret = snprintf(path, PATH_MAX, "%s/%s/rootfs", lxcpath, lxc_name);
+ if (ret < 0 || ret >= PATH_MAX)
goto skipvarlib;
aux = strstr(mntent->mnt_dir, path);
offset = strlen(rootfs->path);
skipabs:
- ret = snprintf(path, MAXPATHLEN, "%s/%s", rootfs->mount, aux + offset);
- if (ret < 0 || ret >= MAXPATHLEN)
+ ret = snprintf(path, PATH_MAX, "%s/%s", rootfs->mount, aux + offset);
+ if (ret < 0 || ret >= PATH_MAX)
return -1;
return mount_entry_on_generic(mntent, path, rootfs, lxc_name, lxc_path);
const char *lxc_path)
{
int ret;
- char path[MAXPATHLEN];
+ char path[PATH_MAX];
/* relative to root mount point */
ret = snprintf(path, sizeof(path), "%s/%s", rootfs->mount, mntent->mnt_dir);
const struct lxc_rootfs *rootfs, FILE *file,
const char *lxc_name, const char *lxc_path)
{
- char buf[4096];
+ char buf[PATH_MAX];
struct mntent mntent;
- int ret = -1;
while (getmntent_r(file, &mntent, buf, sizeof(buf))) {
+ int ret;
+
if (!rootfs->path)
ret = mount_entry_on_systemfs(&mntent);
else if (mntent.mnt_dir[0] != '/')
lxc_name, lxc_path);
else
ret = mount_entry_on_absolute_rootfs(&mntent, rootfs,
- lxc_name, lxc_path);
+ lxc_name, lxc_path);
if (ret < 0)
return -1;
}
- ret = 0;
- INFO("Finished setting up mounts");
- return ret;
+ if (!feof(file) || ferror(file)) {
+ ERROR("Failed to parse mount entries");
+ return -1;
+ }
+
+ return 0;
}
static int setup_mount(const struct lxc_conf *conf,
* access them as a side effect without explicitly allowing it.
*/
static const char nesting_helpers[] =
-"proc dev/.lxc/proc proc create=dir,optional\n"
-"sys dev/.lxc/sys sysfs create=dir,optional\n"
-;
+"proc dev/.lxc/proc proc create=dir,optional 0 0\n"
+"sys dev/.lxc/sys sysfs create=dir,optional 0 0\n";
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) {
TRACE("Created temporary mount file");
}
- if (fd < 0) {
- SYSERROR("Could not create temporary mount file");
- return NULL;
- }
lxc_list_for_each (iterator, mount) {
size_t len;
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,
- sizeof(nesting_helpers) - 1);
- if (ret != sizeof(nesting_helpers) - 1)
- goto on_error;
+ STRARRAYLEN(nesting_helpers));
+ if (ret != STRARRAYLEN(nesting_helpers))
+ 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)
static int dropcaps_except(struct lxc_list *caps)
{
+ __do_free int *caplist = NULL;
int i, capid, numcaps;
char *keep_entry;
struct lxc_list *iterator;
TRACE("Found %d capabilities", numcaps);
/* caplist[i] is 1 if we keep capability i */
- int *caplist = alloca(numcaps * sizeof(int));
+ caplist = must_realloc(NULL, numcaps * sizeof(int));
memset(caplist, 0, numcaps * sizeof(int));
lxc_list_for_each (iterator, caps) {
SYSERROR("Failed to set limit %s", lim->resource);
return -1;
}
+
+ TRACE("Setup \"%s\" limit", lim->resource);
#else
- ERROR("Cannot set limit %s as prlimit is missing", lim->resource);
+ ERROR("Cannot set limit \"%s\" as prlimit is missing", lim->resource);
return -1;
#endif
}
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[MAXPATHLEN] = {0};
+ char filename[PATH_MAX] = {0};
lxc_list_for_each (it, sysctls) {
elem = it->elem;
}
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;
ret = lxc_write_to_file(filename, elem->value,
strlen(elem->value), false, 0666);
if (ret < 0) {
- ERROR("Failed to setup sysctl parameters %s to %s",
- elem->key, elem->value);
+ SYSERROR("Failed to setup sysctl parameters %s to %s",
+ elem->key, elem->value);
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[MAXPATHLEN] = {0};
+ char filename[PATH_MAX] = {0};
lxc_list_for_each (it, procs) {
elem = it->elem;
}
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;
ret = lxc_write_to_file(filename, elem->value,
strlen(elem->value), false, 0666);
if (ret < 0) {
- ERROR("Failed to setup proc filesystem %s to %s",
- elem->filename, elem->value);
+ SYSERROR("Failed to setup proc filesystem %s to %s",
+ elem->filename, elem->value);
return -1;
}
}
int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
size_t buf_size)
{
- int fd, ret;
- char path[MAXPATHLEN];
+ __do_close_prot_errno int fd;
+ 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, MAXPATHLEN, "/proc/%d/setgroups", pid);
- if (ret < 0 || ret >= MAXPATHLEN)
+ 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 = sizeof("deny\n") - 1;
- 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);
}
}
- ret = snprintf(path, MAXPATHLEN, "/proc/%d/%cid_map", pid,
+ ret = snprintf(path, PATH_MAX, "/proc/%d/%cid_map", pid,
idtype == ID_TYPE_UID ? 'u' : 'g');
- if (ret < 0 || ret >= MAXPATHLEN)
+ if (ret < 0 || ret >= PATH_MAX)
return -E2BIG;
fd = open(path, O_WRONLY);
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
* of the doubt. Otherwise we might fail even though all the necessary
* file capabilities are set.
*/
- DEBUG("Cannot check for file capabilites as full capability support is "
+ 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)
int fill, left;
char u_or_g;
char *pos;
- char cmd_output[MAXPATHLEN];
+ char cmd_output[PATH_MAX];
struct id_map *map;
struct lxc_list *iterator;
enum idtype type;
if (!had_entry)
continue;
- /* Try to catch the ouput of new{g,u}idmap to make debugging
+ /* Try to catch the output of new{g,u}idmap to make debugging
* easier.
*/
if (use_shadow) {
"-m", map5,
"--", "chown", ugid, path,
NULL};
- char cmd_output[MAXPATHLEN];
+ char cmd_output[PATH_MAX];
hostuid = geteuid();
hostgid = getegid();
/* 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;
}
}
-#define __LXC_SENDFILE_MAX 0x7ffff000 /* maximum number of bytes sendfile can handle */
again:
- copied = sendfile(memfd, mntinfo_fd, NULL, __LXC_SENDFILE_MAX);
+ copied = lxc_sendfile_nointr(memfd, mntinfo_fd, NULL, LXC_SENDFILE_MAX);
if (copied < 0) {
if (errno == EINTR)
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) {
- int ret;
char *opts, *target;
target = get_field(line, 4);
}
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;
static bool verify_start_hooks(struct lxc_conf *conf)
{
- char path[MAXPATHLEN];
+ char path[PATH_MAX];
struct lxc_list *it;
lxc_list_for_each (it, &conf->hooks[LXCHOOK_START]) {
int ret;
- struct stat st;
char *hookname = it->elem;
- ret = snprintf(path, MAXPATHLEN, "%s%s",
+ ret = snprintf(path, PATH_MAX, "%s%s",
conf->rootfs.path ? conf->rootfs.mount : "",
hookname);
- if (ret < 0 || ret >= MAXPATHLEN)
+ if (ret < 0 || ret >= PATH_MAX)
return false;
- ret = stat(path, &st);
+ ret = access(path, X_OK);
if (ret < 0) {
- SYSERROR("Start hook %s not found in container",
+ SYSERROR("Start hook \"%s\" not found in container",
hookname);
return false;
}
static bool execveat_supported(void)
{
-#ifdef __NR_execveat
- /*
- * We use the syscall here, because it was introduced in kernel 3.19,
- * while glibc got support for using the syscall much later, in 2.27.
- * We don't want to use glibc because it falls back to /proc, and the
- * container may not have /proc mounted depending on its configuration.
- */
- syscall(__NR_execveat, -1, "", NULL, NULL, AT_EMPTY_PATH);
+ lxc_raw_execveat(-1, "", NULL, NULL, AT_EMPTY_PATH);
if (errno == ENOSYS)
return false;
return true;
-#else
- return false;
-#endif
}
int lxc_setup(struct lxc_handler *handler)
}
}
+ ret = lxc_setup_keyring();
+ 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;
}
- /* Make sure any start hooks are in the container */
- if (!verify_start_hooks(lxc_conf))
- return -1;
-
if (lxc_conf->is_execute) {
if (execveat_supported()) {
int fd;
}
}
+ /* Make sure any start hooks are in the container */
+ if (!verify_start_hooks(lxc_conf)) {
+ ERROR("Failed to verify start hooks");
+ return -1;
+ }
+
ret = lxc_setup_console(&lxc_conf->rootfs, &lxc_conf->console,
lxc_conf->ttys.dir);
if (ret < 0) {
return 0;
}
+int lxc_clear_namespace(struct lxc_conf *c)
+{
+ int i;
+ for (i = 0; i < LXC_NS_MAX; i++) {
+ free(c->ns_share[i]);
+ c->ns_share[i] = NULL;
+ }
+ return 0;
+}
+
int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version)
{
char *global_token, *namespaced_token;
if (version == CGROUP2_SUPER_MAGIC) {
global_token = "lxc.cgroup2";
namespaced_token = "lxc.cgroup2.";
- namespaced_token_len = sizeof("lxc.cgroup2.") - 1;
+ namespaced_token_len = STRLITERALLEN("lxc.cgroup2.");
list = &c->cgroup2;
} else if (version == CGROUP_SUPER_MAGIC) {
global_token = "lxc.cgroup";
namespaced_token = "lxc.cgroup.";
- namespaced_token_len = sizeof("lxc.cgroup.") - 1;
+ namespaced_token_len = STRLITERALLEN("lxc.cgroup.");
list = &c->cgroup;
} else {
return -EINVAL;
if (strcmp(key, global_token) == 0)
all = true;
- else if (strncmp(key, namespaced_token, sizeof(namespaced_token) - 1) == 0)
+ else if (strncmp(key, namespaced_token, namespaced_token_len) == 0)
k += namespaced_token_len;
else
return -EINVAL;
if (strcmp(key, "lxc.limit") == 0 || strcmp(key, "lxc.prlimit") == 0)
all = true;
- else if (strncmp(key, "lxc.limit.", sizeof("lxc.limit.") - 1) == 0)
- k = key + sizeof("lxc.limit.") - 1;
- else if (strncmp(key, "lxc.prlimit.", sizeof("lxc.prlimit.") - 1) == 0)
- k = key + sizeof("lxc.prlimit.") - 1;
+ else if (strncmp(key, "lxc.limit.", STRLITERALLEN("lxc.limit.")) == 0)
+ k = key + STRLITERALLEN("lxc.limit.");
+ else if (strncmp(key, "lxc.prlimit.", STRLITERALLEN("lxc.prlimit.")) == 0)
+ k = key + STRLITERALLEN("lxc.prlimit.");
else
return -1;
if (strcmp(key, "lxc.sysctl") == 0)
all = true;
- else if (strncmp(key, "lxc.sysctl.", sizeof("lxc.sysctl.") - 1) == 0)
- k = key + sizeof("lxc.sysctl.") - 1;
+ else if (strncmp(key, "lxc.sysctl.", STRLITERALLEN("lxc.sysctl.")) == 0)
+ k = key + STRLITERALLEN("lxc.sysctl.");
else
return -1;
if (strcmp(key, "lxc.proc") == 0)
all = true;
- else if (strncmp(key, "lxc.proc.", sizeof("lxc.proc.") - 1) == 0)
- k = key + sizeof("lxc.proc.") - 1;
+ else if (strncmp(key, "lxc.proc.", STRLITERALLEN("lxc.proc.")) == 0)
+ k = key + STRLITERALLEN("lxc.proc.");
else
return -1;
if (strcmp(key, "lxc.hook") == 0)
all = true;
- else if (strncmp(key, "lxc.hook.", sizeof("lxc.hook.") - 1) == 0)
- k = key + sizeof("lxc.hook.") - 1;
+ else if (strncmp(key, "lxc.hook.", STRLITERALLEN("lxc.hook.")) == 0)
+ k = key + STRLITERALLEN("lxc.hook.");
else
return -1;
lxc_clear_sysctls(conf, "lxc.sysctl");
lxc_clear_procs(conf, "lxc.proc");
lxc_clear_apparmor_raw(conf);
+ lxc_clear_namespace(conf);
free(conf->cgroup_meta.dir);
free(conf->cgroup_meta.controllers);
free(conf->shmount.path_host);
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.
* This means we require only to establish a mapping from:
* - the container root {g,u}id as seen from the host > user's host {g,u}id
* - the container root -> some sub{g,u}id
- * The former we add, if the user did not specifiy a mapping. The latter we
- * retrieve from the ontainer's configured {g,u}id mappings as it must have been
+ * The former we add, if the user did not specify a mapping. The latter we
+ * retrieve from the container's configured {g,u}id mappings as it must have been
* there to start the container in the first place.
*/
int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
/* 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)