]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
confile: use mmap() to parse config file
authorChristian Brauner <christian.brauner@ubuntu.com>
Fri, 23 Feb 2018 12:24:35 +0000 (13:24 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Sat, 24 Feb 2018 20:37:39 +0000 (21:37 +0100)
Sigh, this is going to be fun. Essentially, dynamic memory allocation through
malloc() and friends is unsafe when fork()ing in threads. The locking state
that glibc maintains internally might get messed up when the process that
fork()ed calls malloc or calls functions that malloc() internally. Functions
that internally malloc() include fopen(). One solution here is to use open() +
mmap() instead of fopen() + getline().

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/Makefile.am
src/lxc/cmd/lxc_user_nic.c
src/lxc/confile.c
src/lxc/lxccontainer.c
src/lxc/parse.c
src/lxc/parse.h
src/lxc/utils.c
src/lxc/utils.h

index 8e7c64c46ee59852aa96ea91cb02daf2b8bd5380..bee9538084d20d252a7ee7e577cccded1812d18f 100644 (file)
@@ -278,7 +278,7 @@ lxc_checkpoint_SOURCES = tools/lxc_checkpoint.c tools/arguments.c tools/tool_uti
 # Binaries shipping with liblxc
 init_lxc_SOURCES = cmd/lxc_init.c
 lxc_monitord_SOURCES = cmd/lxc_monitord.c
-lxc_user_nic_SOURCES = cmd/lxc_user_nic.c namespace.c network.c
+lxc_user_nic_SOURCES = cmd/lxc_user_nic.c namespace.c network.c parse.c
 lxc_usernsexec_SOURCES = cmd/lxc_usernsexec.c
 
 if ENABLE_DEPRECATED
index 2a5c3a43a09f3ac2dedc5d0508a249ed4e03a948..d071ce0b5af30ee619a25a74aa2ea2a33c571ba6 100644 (file)
@@ -48,6 +48,7 @@
 #include "config.h"
 #include "namespace.h"
 #include "network.h"
+#include "parse.h"
 #include "utils.h"
 
 #define usernic_debug_stream(stream, format, ...)                              \
index a9db536307d483967b210d52a7115f23ad0d16d3..effff93dd385a0f9530cf8334c024cb925b248ed 100644 (file)
@@ -2334,7 +2334,7 @@ int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include)
        if (!conf->rcfile)
                conf->rcfile = strdup(file);
 
-       return lxc_file_for_each_line(file, parse_line, &c);
+       return lxc_file_for_each_line_mmap(file, parse_line, &c);
 }
 
 int lxc_config_define_add(struct lxc_list *defines, char *arg)
index 26fdc23bf91ca0dd2342762116d63a89b1c5a3fc..e6ad6d50130a2d361dc522a213107dbeff452f2f 100644 (file)
@@ -57,6 +57,7 @@
 #include "monitor.h"
 #include "namespace.h"
 #include "network.h"
+#include "parse.h"
 #include "start.h"
 #include "state.h"
 #include "storage.h"
index 9242763e991b21f3b346641a52f4fdc7590f029a..fba250683b74887ef212fa072961eb12034bda09 100644 (file)
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
+
 #define _GNU_SOURCE
 #include <stdio.h>
 #undef _GNU_SOURCE
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
 #include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
 
 #include "parse.h"
 #include "config.h"
 
 lxc_log_define(lxc_parse, lxc);
 
+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);
+}
+
+int lxc_file_for_each_line_mmap(const char *file, lxc_file_cb callback,
+                               void *data)
+{
+       int fd, ret;
+       char *buf, *line;
+       struct stat st;
+       char *saveptr = NULL;
+
+       fd = open(file, O_RDONLY | O_CLOEXEC);
+       if (fd < 0)
+               return -1;
+
+       ret = fstat(fd, &st);
+       if (ret < 0) {
+               close(fd);
+               return -1;
+       }
+
+       if (st.st_size == 0)
+               return 0;
+
+       buf = lxc_strmmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+       if (buf == MAP_FAILED) {
+               close(fd);
+               return -1;
+       }
+
+       for (; (line = strtok_r(buf, "\n\0", &saveptr)); buf = NULL) {
+               ret = callback(line, data);
+               if (ret) {
+                       /* Callback rv > 0 means stop here callback rv < 0 means
+                        * error.
+                        */
+                       if (ret < 0)
+                               ERROR("Failed to parse config: %s", line);
+                       break;
+               }
+       }
+
+       lxc_strmunmap(buf, st.st_size);
+       close(fd);
+       return 0;
+}
+
 int lxc_file_for_each_line(const char *file, lxc_file_cb callback, void *data)
 {
        FILE *f;
index 8f753198b8fd3ee818646029367f45428d0477ff..361ad33ea33c6d7fac825f53a5c12365984f2e58 100644 (file)
@@ -23,6 +23,9 @@
 #ifndef __LXC_PARSE_H
 #define __LXC_PARSE_H
 
+#include <stdio.h>
+#include <sys/types.h>
+
 typedef int (*lxc_dir_cb)(const char *name, const char *directory,
                          const char *file, void *data);
 
@@ -31,10 +34,20 @@ typedef int (*lxc_file_cb)(char *buffer, void *data);
 extern int lxc_file_for_each_line(const char *file, lxc_file_cb callback,
                                  void* data);
 
+extern int lxc_file_for_each_line_mmap(const char *file, lxc_file_cb callback,
+                                      void *data);
+
 extern int lxc_char_left_gc(const char *buffer, size_t len);
 
 extern int lxc_char_right_gc(const char *buffer, size_t len);
 
 extern int lxc_is_line_empty(const char *line);
 
+/* mmap() wrapper. lxc_strmmap() will take care to \0-terminate files so that
+ * normal string-handling functions can be used on the buffer. */
+extern void *lxc_strmmap(void *addr, size_t length, int prot, int flags, int fd,
+                        off_t offset);
+/* munmap() wrapper. Use it to free memory mmap()ed with lxc_strmmap(). */
+extern int lxc_strmunmap(void *addr, size_t length);
+
 #endif
index d7527b42947a38b9a3f2f84de8d012a216089d63..c824e9b99abca95b8c1475ad89a61a09794552bc 100644 (file)
@@ -1810,33 +1810,6 @@ 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)
index 87b5a22b4da5b9acdad024c6e15434f9308ba4e3..f013ef23edcfc61e72a0f285f455a4bfaf707ee8 100644 (file)
@@ -426,13 +426,6 @@ extern size_t lxc_array_len(void **array);
 
 extern void **lxc_append_null_to_array(void **array, size_t count);
 
-/* mmap() wrapper. lxc_strmmap() will take care to \0-terminate files so that
- * normal string-handling functions can be used on the buffer. */
-extern void *lxc_strmmap(void *addr, size_t length, int prot, int flags, int fd,
-                        off_t offset);
-/* munmap() wrapper. Use it to free memory mmap()ed with lxc_strmmap(). */
-extern int lxc_strmunmap(void *addr, size_t length);
-
 /* initialize rand with urandom */
 extern int randseed(bool);