]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
execute: use execveat() syscall if supported 2341/head
authorTycho Andersen <tycho@tycho.ws>
Tue, 22 May 2018 23:33:17 +0000 (23:33 +0000)
committerChristian Brauner <christian.brauner@ubuntu.com>
Wed, 23 May 2018 10:05:10 +0000 (12:05 +0200)
The execveat allows us to exec stuff via a fd so we don't have to bind mount
stuff in. See the comment about why we're using the syscall directly.

Closes #2339.

Signed-off-by: Tycho Andersen <tycho@tycho.ws>
[christian.brauner@ubuntu.com: adapt error message and whitespace fixes]
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/conf.c
src/lxc/execute.c
src/lxc/start.h

index 77c134e826ea76feb490783c6d14e31af2fbcb54..220f76c5829f72ce0b4e0d12e5eca874ef95d697 100644 (file)
@@ -3259,6 +3259,7 @@ static int lxc_execute_bind_init(struct lxc_handler *handler)
 
        INFO("Bind mounted lxc.init.static into container at \"%s\"", path);
 out:
+       ((struct execute_args *)handler->data)->init_fd = -1;
        ((struct execute_args *)handler->data)->init_path = p;
        return 0;
 }
@@ -3333,6 +3334,25 @@ static bool verify_start_hooks(struct lxc_conf *conf)
        return true;
 }
 
+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);
+       if (errno == ENOSYS)
+               return false;
+
+       return true;
+#else
+       return false;
+#endif
+}
+
 int lxc_setup(struct lxc_handler *handler)
 {
        int ret;
@@ -3393,10 +3413,30 @@ int lxc_setup(struct lxc_handler *handler)
                return -1;
 
        if (lxc_conf->is_execute) {
-               ret = lxc_execute_bind_init(handler);
-               if (ret < 0) {
-                       ERROR("Failed to bind-mount the lxc init system");
-                       return -1;
+               if (execveat_supported()) {
+                       int fd;
+                       char path[PATH_MAX];
+
+                       ret = snprintf(path, PATH_MAX, SBINDIR "/init.lxc.static");
+                       if (ret < 0 || ret >= PATH_MAX) {
+                               ERROR("Path to init.lxc.static too long");
+                               return -1;
+                       }
+
+                       fd = open(path, O_PATH | O_CLOEXEC);
+                       if (fd < 0) {
+                               SYSERROR("Unable to open lxc.init.static");
+                               return -1;
+                       }
+
+                       ((struct execute_args *)handler->data)->init_fd = fd;
+                       ((struct execute_args *)handler->data)->init_path = NULL;
+               } else {
+                       ret = lxc_execute_bind_init(handler);
+                       if (ret < 0) {
+                               ERROR("Failed to bind-mount the lxc init system");
+                               return -1;
+                       }
                }
        }
 
index b436b6a3f4e847792c53394d260775b924ae5808..d895e5be90f467faf3b4918437062573632b21f7 100644 (file)
@@ -66,12 +66,10 @@ static int execute_start(struct lxc_handler *handler, void* data)
                goto out1;
        }
 
-       if (!my_args->init_path) {
-               ERROR("Init path missing");
-               goto out2;
-       }
-
-       argv[i++] = my_args->init_path;
+       if (my_args->init_path)
+               argv[i++] = my_args->init_path;
+       else
+               argv[i++] = "lxc-init";
 
        argv[i++] = "-n";
        argv[i++] = (char *)handler->name;
@@ -117,7 +115,14 @@ static int execute_start(struct lxc_handler *handler, void* data)
 
        NOTICE("Exec'ing \"%s\"", my_args->argv[0]);
 
-       execvp(argv[0], argv);
+       if (my_args->init_fd >= 0)
+#ifdef __NR_execveat
+               syscall(__NR_execveat, my_args->init_fd, "", argv, environ, AT_EMPTY_PATH);
+#else
+               ERROR("System seems to be missing execveat syscall number");
+#endif
+       else
+               execvp(argv[0], argv);
        SYSERROR("Failed to exec %s", argv[0]);
 
 out3:
index 466dbf5f3059652552fd2db465420547d802afb1..aaa731077a7e41fc22396f75cd835989bb883599 100644 (file)
@@ -138,6 +138,7 @@ struct lxc_handler {
 
 struct execute_args {
        char *init_path;
+       int init_fd;
        char *const *argv;
        int quiet;
 };