mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-08-07 15:29:02 +00:00
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:
parent
394769b16a
commit
4b5b3a2a29
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -138,6 +138,7 @@ struct lxc_handler {
|
||||
|
||||
struct execute_args {
|
||||
char *init_path;
|
||||
int init_fd;
|
||||
char *const *argv;
|
||||
int quiet;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user