fix handler use-after-free

The problem here is that __lxc_start frees the handler, so any use
afterwards is invalid. Since we don't have access to the actual struct
lxc_container object in __lxc_start, let's pass a pointer to error_num in
so it can be returned.

Unfortunately, I'm a little too paranoid to change the return type of
lxc_start, since it returns failure if some of the cleanup fails, which
may be useful in some cases. So let's keep this out of band.

Closes #2218
Closes #2219

Reported-by: Felix Abecassis <fabecassis@nvidia.com>
Signed-off-by: Tycho Andersen <tycho@tycho.ws>
This commit is contained in:
Tycho Andersen 2018-03-15 15:29:27 +00:00
parent 93936fbc7b
commit a3b4f3d680
5 changed files with 13 additions and 11 deletions

View File

@ -120,7 +120,7 @@ static struct lxc_operations execute_start_ops = {
int lxc_execute(const char *name, char *const argv[], int quiet, int lxc_execute(const char *name, char *const argv[], int quiet,
struct lxc_handler *handler, const char *lxcpath, struct lxc_handler *handler, const char *lxcpath,
bool backgrounded) bool backgrounded, int *error_num)
{ {
struct execute_args args = {.argv = argv, .quiet = quiet}; struct execute_args args = {.argv = argv, .quiet = quiet};
@ -129,5 +129,5 @@ int lxc_execute(const char *name, char *const argv[], int quiet,
handler->conf->is_execute = 1; handler->conf->is_execute = 1;
return __lxc_start(name, handler, &execute_start_ops, &args, lxcpath, return __lxc_start(name, handler, &execute_start_ops, &args, lxcpath,
backgrounded); backgrounded, error_num);
} }

View File

@ -54,7 +54,7 @@ struct lxc_handler;
*/ */
extern int lxc_start(const char *name, char *const argv[], extern int lxc_start(const char *name, char *const argv[],
struct lxc_handler *handler, const char *lxcpath, struct lxc_handler *handler, const char *lxcpath,
bool backgrounded); bool backgrounded, int *error_num);
/* /*
* Start the specified command inside an application container * Start the specified command inside an application container
@ -67,7 +67,7 @@ extern int lxc_start(const char *name, char *const argv[],
*/ */
extern int lxc_execute(const char *name, char *const argv[], int quiet, extern int lxc_execute(const char *name, char *const argv[], int quiet,
struct lxc_handler *handler, const char *lxcpath, struct lxc_handler *handler, const char *lxcpath,
bool backgrounded); bool backgrounded, int *error_num);
/* /*
* Close the fd associated with the monitoring * Close the fd associated with the monitoring

View File

@ -1066,10 +1066,9 @@ reboot:
} }
if (useinit) if (useinit)
ret = lxc_execute(c->name, argv, 1, handler, c->config_path, daemonize); ret = lxc_execute(c->name, argv, 1, handler, c->config_path, daemonize, &c->error_num);
else else
ret = lxc_start(c->name, argv, handler, c->config_path, daemonize); ret = lxc_start(c->name, argv, handler, c->config_path, daemonize, &c->error_num);
c->error_num = handler->exit_status;
if (conf->reboot == 1) { if (conf->reboot == 1) {
INFO("Container requested reboot"); INFO("Container requested reboot");

View File

@ -1824,7 +1824,7 @@ out_abort:
int __lxc_start(const char *name, struct lxc_handler *handler, int __lxc_start(const char *name, struct lxc_handler *handler,
struct lxc_operations* ops, void *data, const char *lxcpath, struct lxc_operations* ops, void *data, const char *lxcpath,
bool backgrounded) bool backgrounded, int *error_num)
{ {
int ret, status; int ret, status;
struct lxc_conf *conf = handler->conf; struct lxc_conf *conf = handler->conf;
@ -1920,6 +1920,8 @@ int __lxc_start(const char *name, struct lxc_handler *handler,
lxc_monitor_send_exit_code(name, status, handler->lxcpath); lxc_monitor_send_exit_code(name, status, handler->lxcpath);
lxc_error_set_and_log(handler->pid, status); lxc_error_set_and_log(handler->pid, status);
if (error_num)
*error_num = handler->exit_status;
out_fini: out_fini:
lxc_delete_network(handler); lxc_delete_network(handler);
@ -1965,13 +1967,13 @@ static struct lxc_operations start_ops = {
}; };
int lxc_start(const char *name, char *const argv[], struct lxc_handler *handler, int lxc_start(const char *name, char *const argv[], struct lxc_handler *handler,
const char *lxcpath, bool backgrounded) const char *lxcpath, bool backgrounded, int *error_num)
{ {
struct start_args start_arg = { struct start_args start_arg = {
.argv = argv, .argv = argv,
}; };
return __lxc_start(name, handler, &start_ops, &start_arg, lxcpath, backgrounded); return __lxc_start(name, handler, &start_ops, &start_arg, lxcpath, backgrounded, error_num);
} }
static void lxc_destroy_container_on_signal(struct lxc_handler *handler, static void lxc_destroy_container_on_signal(struct lxc_handler *handler,

View File

@ -165,7 +165,8 @@ extern void lxc_fini(const char *name, struct lxc_handler *handler);
extern int lxc_check_inherited(struct lxc_conf *conf, bool closeall, extern int lxc_check_inherited(struct lxc_conf *conf, bool closeall,
int *fds_to_ignore, size_t len_fds); int *fds_to_ignore, size_t len_fds);
extern int __lxc_start(const char *, struct lxc_handler *, extern int __lxc_start(const char *, struct lxc_handler *,
struct lxc_operations *, void *, const char *, bool); struct lxc_operations *, void *, const char *, bool,
int *);
extern int resolve_clone_flags(struct lxc_handler *handler); extern int resolve_clone_flags(struct lxc_handler *handler);