From: Tycho Andersen Date: Tue, 22 May 2018 23:33:17 +0000 (+0000) Subject: execute: use execveat() syscall if supported X-Git-Tag: lxc-3.1.0~297^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F2341%2Fhead;p=thirdparty%2Flxc.git execute: use execveat() syscall if supported 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 [christian.brauner@ubuntu.com: adapt error message and whitespace fixes] Signed-off-by: Christian Brauner --- diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 77c134e82..220f76c58 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -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; + } } } diff --git a/src/lxc/execute.c b/src/lxc/execute.c index b436b6a3f..d895e5be9 100644 --- a/src/lxc/execute.c +++ b/src/lxc/execute.c @@ -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: diff --git a/src/lxc/start.h b/src/lxc/start.h index 466dbf5f3..aaa731077 100644 --- a/src/lxc/start.h +++ b/src/lxc/start.h @@ -138,6 +138,7 @@ struct lxc_handler { struct execute_args { char *init_path; + int init_fd; char *const *argv; int quiet; };