]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/utils.c
secure coding: #2 strcpy => strlcpy
[mirror_lxc.git] / src / lxc / utils.c
index 07257d29a0f4ae806bbc2c7050e2b30978ff546c..1319025a1ba21758f376ce7678b1cbe0efa6d0db 100644 (file)
@@ -31,6 +31,7 @@
 #include <grp.h>
 #include <inttypes.h>
 #include <libgen.h>
+#include <pthread.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include "log.h"
 #include "lxclock.h"
 #include "namespace.h"
+#include "parse.h"
 #include "utils.h"
 
-#ifndef PR_SET_MM
-#define PR_SET_MM 35
-#endif
-
-#ifndef PR_SET_MM_MAP
-#define PR_SET_MM_MAP 14
-
-struct prctl_mm_map {
-        uint64_t   start_code;
-        uint64_t   end_code;
-        uint64_t   start_data;
-        uint64_t   end_data;
-        uint64_t   start_brk;
-        uint64_t   brk;
-        uint64_t   start_stack;
-        uint64_t   arg_start;
-        uint64_t   arg_end;
-        uint64_t   env_start;
-        uint64_t   env_end;
-        uint64_t   *auxv;
-        uint32_t   auxv_size;
-        uint32_t   exe_fd;
-};
+#ifndef HAVE_STRLCPY
+#include "include/strlcpy.h"
 #endif
 
 #ifndef O_PATH
@@ -89,7 +70,7 @@ lxc_log_define(lxc_utils, lxc);
  */
 extern bool btrfs_try_remove_subvol(const char *path);
 
-static int _recursive_rmdir(char *dirname, dev_t pdev,
+static int _recursive_rmdir(const char *dirname, dev_t pdev,
                            const char *exclude, int level, bool onedev)
 {
        struct dirent *direntp;
@@ -108,9 +89,6 @@ static int _recursive_rmdir(char *dirname, dev_t pdev,
                struct stat mystat;
                int rc;
 
-               if (!direntp)
-                       break;
-
                if (!strcmp(direntp->d_name, ".") ||
                    !strcmp(direntp->d_name, ".."))
                        continue;
@@ -204,18 +182,18 @@ static bool is_native_overlayfs(const char *path)
 }
 
 /* returns 0 on success, -1 if there were any failures */
-extern int lxc_rmdir_onedev(char *path, const char *exclude)
+extern int lxc_rmdir_onedev(const char *path, const char *exclude)
 {
        struct stat mystat;
        bool onedev = true;
 
-       if (is_native_overlayfs(path)) {
+       if (is_native_overlayfs(path))
                onedev = false;
-       }
 
        if (lstat(path, &mystat) < 0) {
                if (errno == ENOENT)
                        return 0;
+
                ERROR("Failed to stat %s", path);
                return -1;
        }
@@ -269,8 +247,13 @@ char *get_rundir()
 {
        char *rundir;
        const char *homedir;
+       struct stat sb;
+
+       if (stat(RUNTIME_PATH, &sb) < 0) {
+               return NULL;
+       }
 
-       if (geteuid() == 0) {
+       if (geteuid() == sb.st_uid || getegid() == sb.st_gid) {
                rundir = strdup(RUNTIME_PATH);
                return rundir;
        }
@@ -470,137 +453,115 @@ const char** lxc_va_arg_list_to_argv_const(va_list ap, size_t skip)
        return (const char**)lxc_va_arg_list_to_argv(ap, skip, 0);
 }
 
-extern struct lxc_popen_FILE *lxc_popen(const char *command)
+struct lxc_popen_FILE *lxc_popen(const char *command)
 {
-       struct lxc_popen_FILE *fp = NULL;
-       int parent_end = -1, child_end = -1;
+       int ret;
        int pipe_fds[2];
        pid_t child_pid;
+       struct lxc_popen_FILE *fp = NULL;
 
-       int r = pipe2(pipe_fds, O_CLOEXEC);
-
-       if (r < 0) {
-               ERROR("pipe2 failure");
+       ret = pipe2(pipe_fds, O_CLOEXEC);
+       if (ret < 0)
                return NULL;
-       }
-
-       parent_end = pipe_fds[0];
-       child_end = pipe_fds[1];
 
        child_pid = fork();
+       if (child_pid < 0)
+               goto on_error;
 
-       if (child_pid == 0) {
-               /* child */
-               int child_std_end = STDOUT_FILENO;
-
-               close(parent_end);
-               parent_end = -1;
+       if (!child_pid) {
+               sigset_t mask;
 
-               if (child_end != child_std_end) {
-                       /* dup2() doesn't dup close-on-exec flag */
-                       dup2(child_end, child_std_end);
+               close(pipe_fds[0]);
 
-                       /* it's safe not to close child_end here
-                        * as it's marked close-on-exec anyway
-                        */
-               } else {
-                       /*
-                        * The descriptor is already the one we will use.
-                        * But it must not be marked close-on-exec.
-                        * Undo the effects.
-                        */
-                       if (fcntl(child_end, F_SETFD, 0) != 0) {
-                               SYSERROR("Failed to remove FD_CLOEXEC from fd.");
-                               exit(127);
-                       }
-               }
-
-               /*
-                * Unblock signals.
-                * This is the main/only reason
-                * why we do our lousy popen() emulation.
-                */
-               {
-                       sigset_t mask;
-                       sigfillset(&mask);
-                       sigprocmask(SIG_UNBLOCK, &mask, NULL);
+               /* duplicate stdout */
+               if (pipe_fds[1] != STDOUT_FILENO)
+                       ret = dup2(pipe_fds[1], STDOUT_FILENO);
+               else
+                       ret = fcntl(pipe_fds[1], F_SETFD, 0);
+               if (ret < 0) {
+                       close(pipe_fds[1]);
+                       _exit(EXIT_FAILURE);
                }
 
-               execl("/bin/sh", "sh", "-c", command, (char *) NULL);
-               exit(127);
-       }
+               /* duplicate stderr */
+               if (pipe_fds[1] != STDERR_FILENO)
+                       ret = dup2(pipe_fds[1], STDERR_FILENO);
+               else
+                       ret = fcntl(pipe_fds[1], F_SETFD, 0);
+               close(pipe_fds[1]);
+               if (ret < 0)
+                       _exit(EXIT_FAILURE);
 
-       /* parent */
+               /* unblock all signals */
+               ret = sigfillset(&mask);
+               if (ret < 0)
+                       _exit(EXIT_FAILURE);
 
-       close(child_end);
-       child_end = -1;
+               ret = pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
+               if (ret < 0)
+                       _exit(EXIT_FAILURE);
 
-       if (child_pid < 0) {
-               ERROR("fork failure");
-               goto error;
+               execl("/bin/sh", "sh", "-c", command, (char *)NULL);
+               _exit(127);
        }
 
-       fp = calloc(1, sizeof(*fp));
-       if (!fp) {
-               ERROR("failed to allocate memory");
-               goto error;
-       }
+       close(pipe_fds[1]);
+       pipe_fds[1] = -1;
 
-       fp->f = fdopen(parent_end, "r");
-       if (!fp->f) {
-               ERROR("fdopen failure");
-               goto error;
-       }
+       fp = malloc(sizeof(*fp));
+       if (!fp)
+               goto on_error;
+       memset(fp, 0, sizeof(*fp));
 
        fp->child_pid = child_pid;
+       fp->pipe = pipe_fds[0];
+
+       /* From now on, closing fp->f will also close fp->pipe. So only ever
+        * call fclose(fp->f).
+        */
+       fp->f = fdopen(pipe_fds[0], "r");
+       if (!fp->f)
+               goto on_error;
 
        return fp;
 
-error:
+on_error:
+       /* We can only close pipe_fds[0] if fdopen() didn't succeed or wasn't
+        * called yet. Otherwise the fd belongs to the file opened by fdopen()
+        * since it isn't dup()ed.
+        */
+       if (fp && !fp->f && pipe_fds[0] >= 0)
+               close(pipe_fds[0]);
 
-       if (fp) {
-               if (fp->f) {
-                       fclose(fp->f);
-                       parent_end = -1; /* so we do not close it second time */
-               }
+       if (pipe_fds[1] >= 0)
+               close(pipe_fds[1]);
 
-               free(fp);
-       }
+       if (fp && fp->f)
+               fclose(fp->f);
 
-       if (parent_end != -1)
-               close(parent_end);
+       if (fp)
+               free(fp);
 
        return NULL;
 }
 
-extern int lxc_pclose(struct lxc_popen_FILE *fp)
+int lxc_pclose(struct lxc_popen_FILE *fp)
 {
-       FILE *f = NULL;
-       pid_t child_pid = 0;
-       int wstatus = 0;
        pid_t wait_pid;
+       int wstatus = 0;
 
-       if (fp) {
-               f = fp->f;
-               child_pid = fp->child_pid;
-               /* free memory (we still need to close file stream) */
-               free(fp);
-               fp = NULL;
-       }
-
-       if (!f || fclose(f)) {
-               ERROR("fclose failure");
+       if (!fp)
                return -1;
-       }
 
        do {
-               wait_pid = waitpid(child_pid, &wstatus, 0);
-       } while (wait_pid == -1 && errno == EINTR);
+               wait_pid = waitpid(fp->child_pid, &wstatus, 0);
+       } while (wait_pid < 0 && errno == EINTR);
+
+       fclose(fp->f);
+       free(fp);
 
-       if (wait_pid == -1) {
-               ERROR("waitpid failure");
+       if (wait_pid < 0)
                return -1;
-       }
 
        return wstatus;
 }
@@ -684,7 +645,8 @@ char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix)
                return NULL;
 
        if (use_as_prefix)
-               strcpy(result, sep);
+               (void)strlcpy(result, sep, result_len + 1);
+
        for (p = (char **)parts; *p; p++) {
                if (p > (char **)parts)
                        strcat(result, sep);
@@ -773,10 +735,12 @@ char *lxc_deslashify(const char *path)
 
 char *lxc_append_paths(const char *first, const char *second)
 {
-       size_t len = strlen(first) + strlen(second) + 1;
-       const char *pattern = "%s%s";
+       int ret;
+       size_t len;
        char *result = NULL;
+       const char *pattern = "%s%s";
 
+       len = strlen(first) + strlen(second) + 1;
        if (second[0] != '/') {
                len += 1;
                pattern = "%s/%s";
@@ -786,7 +750,12 @@ char *lxc_append_paths(const char *first, const char *second)
        if (!result)
                return NULL;
 
-       snprintf(result, len, pattern, first, second);
+       ret = snprintf(result, len, pattern, first, second);
+       if (ret < 0 || (size_t)ret >= len) {
+               free(result);
+               return NULL;
+       }
+
        return result;
 }
 
@@ -794,12 +763,15 @@ bool lxc_string_in_list(const char *needle, const char *haystack, char _sep)
 {
        char *token, *str, *saveptr = NULL;
        char sep[2] = { _sep, '\0' };
+       size_t len;
 
        if (!haystack || !needle)
                return 0;
 
-       str = alloca(strlen(haystack)+1);
-       strcpy(str, haystack);
+       len = strlen(haystack);
+       str = alloca(len + 1);
+       (void)strlcpy(str, haystack, len + 1);
+
        for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
                if (strcmp(needle, token) == 0)
                        return 1;
@@ -816,12 +788,15 @@ char **lxc_string_split(const char *string, char _sep)
        size_t result_capacity = 0;
        size_t result_count = 0;
        int r, saved_errno;
+       size_t len;
 
        if (!string)
                return calloc(1, sizeof(char *));
 
-       str = alloca(strlen(string) + 1);
-       strcpy(str, string);
+       len = strlen(string);
+       str = alloca(len + 1);
+       (void)strlcpy(str, string, len + 1);
+
        for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
                r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
                if (r < 0)
@@ -848,6 +823,74 @@ error_out:
        return NULL;
 }
 
+static bool complete_word(char ***result, char *start, char *end, size_t *cap, size_t *cnt)
+{
+       int r;
+
+       r = lxc_grow_array((void ***)result, cap, 2 + *cnt, 16);
+       if (r < 0)
+               return false;
+       (*result)[*cnt] = strndup(start, end - start);
+       if (!(*result)[*cnt])
+               return false;
+       (*cnt)++;
+
+       return true;
+}
+
+/*
+ * Given a a string 'one two "three four"', split into three words,
+ * one, two, and "three four"
+ */
+char **lxc_string_split_quoted(char *string)
+{
+       char *nextword = string, *p, state;
+       char **result = NULL;
+       size_t result_capacity = 0;
+       size_t result_count = 0;
+
+       if (!string || !*string)
+               return calloc(1, sizeof(char *));
+
+       // TODO I'm *not* handling escaped quote
+       state = ' ';
+       for (p = string; *p; p++) {
+               switch(state) {
+               case ' ':
+                       if (isspace(*p))
+                               continue;
+                       else if (*p == '"' || *p == '\'') {
+                               nextword = p;
+                               state = *p;
+                               continue;
+                       }
+                       nextword = p;
+                       state = 'a';
+                       continue;
+               case 'a':
+                       if (isspace(*p)) {
+                               complete_word(&result, nextword, p, &result_capacity, &result_count);
+                               state = ' ';
+                               continue;
+                       }
+                       continue;
+               case '"':
+               case '\'':
+                       if (*p == state) {
+                               complete_word(&result, nextword+1, p, &result_capacity, &result_count);
+                               state = ' ';
+                               continue;
+                       }
+                       continue;
+               }
+       }
+
+       if (state == 'a')
+               complete_word(&result, nextword, p, &result_capacity, &result_count);
+
+       return realloc(result, (result_count + 1) * sizeof(char *));
+}
+
 char **lxc_string_split_and_trim(const char *string, char _sep)
 {
        char *token, *str, *saveptr = NULL;
@@ -857,12 +900,15 @@ char **lxc_string_split_and_trim(const char *string, char _sep)
        size_t result_count = 0;
        int r, saved_errno;
        size_t i = 0;
+       size_t len;
 
        if (!string)
                return calloc(1, sizeof(char *));
 
-       str = alloca(strlen(string)+1);
-       strcpy(str, string);
+       len = strlen(string);
+       str = alloca(len + 1);
+       (void)strlcpy(str, string, len + 1);
+
        for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
                while (token[0] == ' ' || token[0] == '\t')
                        token++;
@@ -937,12 +983,13 @@ size_t lxc_array_len(void **array)
        return result;
 }
 
-int lxc_write_to_file(const char *filename, const void* buf, size_t count, bool add_newline)
+int lxc_write_to_file(const char *filename, const void *buf, size_t count,
+                     bool add_newline, mode_t mode)
 {
        int fd, saved_errno;
        ssize_t ret;
 
-       fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0666);
+       fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
        if (fd < 0)
                return -1;
        ret = lxc_write_nointr(fd, buf, count);
@@ -1402,110 +1449,6 @@ char *get_template_path(const char *t)
        return tpath;
 }
 
-/*
- * Sets the process title to the specified title. Note that this may fail if
- * the kernel doesn't support PR_SET_MM_MAP (kernels <3.18).
- */
-int setproctitle(char *title)
-{
-       static char *proctitle = NULL;
-       char buf[2048], *tmp;
-       FILE *f;
-       int i, len, ret = 0;
-
-       /* We don't really need to know all of this stuff, but unfortunately
-        * PR_SET_MM_MAP requires us to set it all at once, so we have to
-        * figure it out anyway.
-        */
-       unsigned long start_data, end_data, start_brk, start_code, end_code,
-                       start_stack, arg_start, arg_end, env_start, env_end,
-                       brk_val;
-       struct prctl_mm_map prctl_map;
-
-       f = fopen_cloexec("/proc/self/stat", "r");
-       if (!f) {
-               return -1;
-       }
-
-       tmp = fgets(buf, sizeof(buf), f);
-       fclose(f);
-       if (!tmp) {
-               return -1;
-       }
-
-       /* Skip the first 25 fields, column 26-28 are start_code, end_code,
-        * and start_stack */
-       tmp = strchr(buf, ' ');
-       for (i = 0; i < 24; i++) {
-               if (!tmp)
-                       return -1;
-               tmp = strchr(tmp+1, ' ');
-       }
-       if (!tmp)
-               return -1;
-
-       i = sscanf(tmp, "%lu %lu %lu", &start_code, &end_code, &start_stack);
-       if (i != 3)
-               return -1;
-
-       /* Skip the next 19 fields, column 45-51 are start_data to arg_end */
-       for (i = 0; i < 19; i++) {
-               if (!tmp)
-                       return -1;
-               tmp = strchr(tmp+1, ' ');
-       }
-
-       if (!tmp)
-               return -1;
-
-       i = sscanf(tmp, "%lu %lu %lu %*u %*u %lu %lu",
-               &start_data,
-               &end_data,
-               &start_brk,
-               &env_start,
-               &env_end);
-       if (i != 5)
-               return -1;
-
-       /* Include the null byte here, because in the calculations below we
-        * want to have room for it. */
-       len = strlen(title) + 1;
-
-       proctitle = realloc(proctitle, len);
-       if (!proctitle)
-               return -1;
-
-       arg_start = (unsigned long) proctitle;
-       arg_end = arg_start + len;
-
-       brk_val = syscall(__NR_brk, 0);
-
-       prctl_map = (struct prctl_mm_map) {
-               .start_code = start_code,
-               .end_code = end_code,
-               .start_stack = start_stack,
-               .start_data = start_data,
-               .end_data = end_data,
-               .start_brk = start_brk,
-               .brk = brk_val,
-               .arg_start = arg_start,
-               .arg_end = arg_end,
-               .env_start = env_start,
-               .env_end = env_end,
-               .auxv = NULL,
-               .auxv_size = 0,
-               .exe_fd = -1,
-       };
-
-       ret = prctl(PR_SET_MM, PR_SET_MM_MAP, (long) &prctl_map, sizeof(prctl_map), 0);
-       if (ret == 0)
-               strcpy((char*)arg_start, title);
-       else
-               INFO("setting cmdline failed - %s", strerror(errno));
-
-       return ret;
-}
-
 /*
  * @path:    a pathname where / replaced with '\0'.
  * @offsetp: pointer to int showing which path segment was last seen.
@@ -1736,7 +1679,7 @@ int safe_mount(const char *src, const char *dest, const char *fstype,
        close(destfd);
        if (ret < 0) {
                errno = saved_errno;
-               SYSERROR("Failed to mount %s onto %s", src, dest);
+               SYSERROR("Failed to mount %s onto %s", src ? src : "(null)", dest);
                return ret;
        }
 
@@ -1786,7 +1729,7 @@ int lxc_mount_proc_if_needed(const char *rootfs)
                return -1;
        }
 
-       mypid = getpid();
+       mypid = lxc_raw_getpid();
        INFO("I am %d, /proc/self points to \"%s\"", mypid, link);
 
        if (lxc_safe_int(link, &link_to_pid) < 0)
@@ -1880,46 +1823,18 @@ int lxc_count_file_lines(const char *fn)
        return n;
 }
 
-void *lxc_strmmap(void *addr, size_t length, int prot, int flags, int fd,
-                 off_t offset)
-{
-       void *tmp = NULL, *overlap = NULL;
-
-       /* We establish an anonymous mapping that is one byte larger than the
-        * underlying file. The pages handed to us are zero filled. */
-       tmp = mmap(addr, length + 1, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-       if (tmp == MAP_FAILED)
-               return tmp;
-
-       /* Now we establish a fixed-address mapping starting at the address we
-        * received from our anonymous mapping and replace all bytes excluding
-        * the additional \0-byte with the file. This allows us to use normal
-        * string-handling functions. */
-       overlap = mmap(tmp, length, prot, MAP_FIXED | flags, fd, offset);
-       if (overlap == MAP_FAILED)
-               munmap(tmp, length + 1);
-
-       return overlap;
-}
-
-int lxc_strmunmap(void *addr, size_t length)
-{
-       return munmap(addr, length + 1);
-}
-
 /* Check whether a signal is blocked by a process. */
 /* /proc/pid-to-str/status\0 = (5 + 21 + 7 + 1) */
-#define __PROC_STATUS_LEN (5 + (LXC_NUMSTRLEN64) + 7 + 1)
-bool task_blocking_signal(pid_t pid, int signal)
+#define __PROC_STATUS_LEN (6 + (LXC_NUMSTRLEN64) + 7 + 1)
+bool task_blocks_signal(pid_t pid, int signal)
 {
-       bool bret = false;
-       char *line = NULL;
-       long unsigned int sigblk = 0;
-       size_t n = 0;
        int ret;
-       FILE *f;
-
        char status[__PROC_STATUS_LEN];
+       FILE *f;
+       uint64_t sigblk = 0, one = 1;
+       size_t n = 0;
+       bool bret = false;
+       char *line = NULL;
 
        ret = snprintf(status, __PROC_STATUS_LEN, "/proc/%d/status", pid);
        if (ret < 0 || ret >= __PROC_STATUS_LEN)
@@ -1930,14 +1845,20 @@ bool task_blocking_signal(pid_t pid, int signal)
                return bret;
 
        while (getline(&line, &n, f) != -1) {
-               if (strncmp(line, "SigBlk:\t", 8))
+               char *numstr;
+
+               if (strncmp(line, "SigBlk:", 7))
                        continue;
 
-               if (sscanf(line + 8, "%lx", &sigblk) != 1)
+               numstr = lxc_trim_whitespace_in_place(line + 7);
+               ret = lxc_safe_uint64(numstr, &sigblk, 16);
+               if (ret < 0)
                        goto out;
+
+               break;
        }
 
-       if (sigblk & (1LU << (signal - 1)))
+       if (sigblk & (one << (signal - 1)))
                bret = true;
 
 out:
@@ -1998,8 +1919,9 @@ int lxc_preserve_ns(const int pid, const char *ns)
        ret = snprintf(path, __NS_PATH_LEN, "/proc/%d/ns%s%s", pid,
                       !ns || strcmp(ns, "") == 0 ? "" : "/",
                       !ns || strcmp(ns, "") == 0 ? "" : ns);
+       errno = EFBIG;
        if (ret < 0 || (size_t)ret >= __NS_PATH_LEN)
-               return -1;
+               return -EFBIG;
 
        return open(path, O_RDONLY | O_CLOEXEC);
 }
@@ -2053,6 +1975,29 @@ int lxc_safe_ulong(const char *numstr, unsigned long *converted)
        return 0;
 }
 
+int lxc_safe_uint64(const char *numstr, uint64_t *converted, int base)
+{
+       char *err = NULL;
+       uint64_t u;
+
+       while (isspace(*numstr))
+               numstr++;
+
+       if (*numstr == '-')
+               return -EINVAL;
+
+       errno = 0;
+       u = strtoull(numstr, &err, base);
+       if (errno == ERANGE && u == ULLONG_MAX)
+               return -ERANGE;
+
+       if (err == numstr || *err != '\0')
+               return -EINVAL;
+
+       *converted = u;
+       return 0;
+}
+
 int lxc_safe_int(const char *numstr, int *converted)
 {
        char *err = NULL;
@@ -2096,6 +2041,26 @@ int lxc_safe_long(const char *numstr, long int *converted)
        return 0;
 }
 
+int lxc_safe_long_long(const char *numstr, long long int *converted)
+{
+       char *err = NULL;
+       signed long long int sli;
+
+       errno = 0;
+       sli = strtoll(numstr, &err, 0);
+       if (errno == ERANGE && (sli == LLONG_MAX || sli == LLONG_MIN))
+               return -ERANGE;
+
+       if (errno != 0 && sli == 0)
+               return -EINVAL;
+
+       if (err == numstr || *err != '\0')
+               return -EINVAL;
+
+       *converted = sli;
+       return 0;
+}
+
 int lxc_switch_uid_gid(uid_t uid, gid_t gid)
 {
        if (setgid(gid) < 0) {
@@ -2137,9 +2102,6 @@ static int lxc_get_unused_loop_dev_legacy(char *loop_name)
                return -1;
 
        while ((dp = readdir(dir))) {
-               if (!dp)
-                       break;
-
                if (strncmp(dp->d_name, "loop", 4) != 0)
                        continue;
 
@@ -2285,7 +2247,7 @@ int run_command(char *buf, size_t buf_size, int (*child_fn)(void *), void *args)
        int ret, fret, pipefd[2];
        ssize_t bytes;
 
-       /* Make sure our callers do not receive unitialized memory. */
+       /* Make sure our callers do not receive uninitialized memory. */
        if (buf_size > 0 && buf)
                buf[0] = '\0';
 
@@ -2294,7 +2256,7 @@ int run_command(char *buf, size_t buf_size, int (*child_fn)(void *), void *args)
                return -1;
        }
 
-       child = fork();
+       child = lxc_raw_clone(0);
        if (child < 0) {
                close(pipefd[0]);
                close(pipefd[1]);
@@ -2318,21 +2280,23 @@ int run_command(char *buf, size_t buf_size, int (*child_fn)(void *), void *args)
 
                if (ret < 0) {
                        SYSERROR("failed to duplicate std{err,out} file descriptor");
-                       exit(EXIT_FAILURE);
+                       _exit(EXIT_FAILURE);
                }
 
                /* Does not return. */
                child_fn(args);
                ERROR("failed to exec command");
-               exit(EXIT_FAILURE);
+               _exit(EXIT_FAILURE);
        }
 
        /* close the write-end of the pipe */
        close(pipefd[1]);
 
-       bytes = read(pipefd[0], buf, (buf_size > 0) ? (buf_size - 1) : 0);
-       if (bytes > 0)
-               buf[bytes - 1] = '\0';
+       if (buf && buf_size > 0) {
+               bytes = read(pipefd[0], buf, buf_size - 1);
+               if (bytes > 0)
+                       buf[bytes - 1] = '\0';
+       }
 
        fret = wait_for_pid(child);
        /* close the read-end of the pipe */
@@ -2364,6 +2328,33 @@ char *must_make_path(const char *first, ...)
        return dest;
 }
 
+char *must_append_path(char *first, ...)
+{
+       char *cur;
+       size_t full_len;
+       va_list args;
+       char *dest = first;
+
+       full_len = strlen(first);
+       va_start(args, first);
+       while ((cur = va_arg(args, char *)) != NULL) {
+               full_len += strlen(cur);
+
+               if (cur[0] != '/')
+                       full_len++;
+
+               dest = must_realloc(dest, full_len + 1);
+
+               if (cur[0] != '/')
+                       strcat(dest, "/");
+
+               strcat(dest, cur);
+       }
+       va_end(args);
+
+       return dest;
+}
+
 char *must_copy_string(const char *entry)
 {
        char *ret;
@@ -2430,3 +2421,143 @@ bool lxc_nic_exists(char *nic)
 
        return true;
 }
+
+int lxc_make_tmpfile(char *template, bool rm)
+{
+       int fd, ret;
+       mode_t msk;
+
+       msk = umask(0022);
+       fd = mkstemp(template);
+       umask(msk);
+       if (fd < 0)
+               return -1;
+
+       if (!rm)
+               return fd;
+
+       ret = unlink(template);
+       if (ret < 0) {
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+int parse_byte_size_string(const char *s, int64_t *converted)
+{
+       int ret, suffix_len;
+       long long int conv;
+       int64_t mltpl, overflow;
+       char *end;
+       char dup[LXC_NUMSTRLEN64 + 2];
+       char suffix[3] = {0};
+
+       if (!s || !strcmp(s, ""))
+               return -EINVAL;
+
+       end = stpncpy(dup, s, sizeof(dup) - 1);
+       if (*end != '\0')
+               return -EINVAL;
+
+       if (isdigit(*(end - 1)))
+               suffix_len = 0;
+       else if (isalpha(*(end - 1)))
+               suffix_len = 1;
+       else
+               return -EINVAL;
+
+       if (suffix_len > 0 && (end - 2) == dup && !isdigit(*(end - 2)))
+               return -EINVAL;
+
+       if (suffix_len > 0 && isalpha(*(end - 2)))
+               suffix_len++;
+
+       if (suffix_len > 0) {
+               memcpy(suffix, end - suffix_len, suffix_len);
+               *(suffix + suffix_len) = '\0';
+               *(end - suffix_len) = '\0';
+       }
+       dup[lxc_char_right_gc(dup, strlen(dup))] = '\0';
+
+       ret = lxc_safe_long_long(dup, &conv);
+       if (ret < 0)
+               return -ret;
+
+       if (suffix_len != 2) {
+               *converted = conv;
+               return 0;
+       }
+
+       if (strcasecmp(suffix, "KB") == 0)
+               mltpl = 1024;
+       else if (strcasecmp(suffix, "MB") == 0)
+               mltpl = 1024 * 1024;
+       else if (strcasecmp(suffix, "GB") == 0)
+               mltpl = 1024 * 1024 * 1024;
+       else
+               return -EINVAL;
+
+       overflow = conv * mltpl;
+       if (conv != 0 && (overflow / conv) != mltpl)
+               return -ERANGE;
+
+       *converted = overflow;
+       return 0;
+}
+
+uint64_t lxc_find_next_power2(uint64_t n)
+{
+       /* 0 is not valid input. We return 0 to the caller since 0 is not a
+        * valid power of two.
+        */
+       if (n == 0)
+               return 0;
+
+       if (!(n & (n - 1)))
+               return n;
+
+       while (n & (n - 1))
+               n = n & (n - 1);
+
+       n = n << 1;
+       return n;
+}
+
+int lxc_set_death_signal(int signal)
+{
+       int ret;
+       pid_t ppid;
+
+       ret = prctl(PR_SET_PDEATHSIG, signal, 0, 0, 0);
+
+       /* Check whether we have been orphaned. */
+       ppid = (pid_t)syscall(SYS_getppid);
+       if (ppid == 1) {
+               pid_t self;
+
+               self = lxc_raw_getpid();
+               ret = kill(self, SIGKILL);
+               if (ret < 0)
+                       return -1;
+       }
+
+       if (ret < 0) {
+               SYSERROR("Failed to set PR_SET_PDEATHSIG to %d", signal);
+               return -1;
+       }
+
+       return 0;
+}
+
+void remove_trailing_newlines(char *l)
+{
+       char *p = l;
+
+       while (*p)
+               p++;
+
+       while (--p >= l && *p == '\n')
+               *p = '\0';
+}