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 <tycho@tycho.ws>
[christian.brauner@ubuntu.com: adapt error message and whitespace fixes]
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
This commit is contained in:
Tycho Andersen 2018-05-22 23:33:17 +00:00 committed by Christian Brauner
parent 394769b16a
commit 4b5b3a2a29
No known key found for this signature in database
GPG Key ID: 8EB056D53EECB12D
3 changed files with 57 additions and 11 deletions

View 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;
}
}
}

View 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:

View File

@ -138,6 +138,7 @@ struct lxc_handler {
struct execute_args {
char *init_path;
int init_fd;
char *const *argv;
int quiet;
};