fix(controller,worker): sched worker resval UAF + execuser fallback to nobody
bug-1506 (controller): sched_worker_change pointed w->host.resvals_to_sched
at resvalist.data, then xlist_fini freed it — a concurrent reader (the
WORKER_JOIN hook encoding the worker's resvals) hit an ASAN
heap-use-after-free that crashed the controller and failed every job. Take
ownership of the resval data via MOVE_PTR (mirrors collect_resvals_workers);
the prior array is intentionally leaked (freeing it races the same readers).
bug-1507 (worker): the apiserver's bug-1500 execuser fix sent the submit
user ("admin") as execuser, but that user does not exist in the worker
host's /etc/passwd. systemd failed the worker unit with EXIT_USER (217),
so every job died immediately after submit. job_start_local_task now
checks the execuser with getpwnam() and falls back to "nobody" when the
user does not exist.
Verified with a full job lifecycle (submit -> RUN as nobody -> DONE) on
the clean build: all 4 daemons healthy, zero ASAN.
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
c630809116
commit
c091a8dae0
4 changed files with 95 additions and 3 deletions
|
|
@ -4,6 +4,7 @@
|
|||
#include "cluster.h"
|
||||
#include "controller.capnp.h"
|
||||
#include "request.h"
|
||||
#include "utils.h" /* MOVE_PTR (bug-1506) */
|
||||
#include "worker.h"
|
||||
#include "xce/cluster_def.h"
|
||||
#include "xce/types.h"
|
||||
|
|
@ -500,8 +501,22 @@ static int sched_worker_change(int type, int situation, void* data,
|
|||
|
||||
xlist_init(&resvalist, 256);
|
||||
collect_resval(c->resmgr, &(w->host.resvals), &resvalist);
|
||||
w->host.nresvals_to_sched = resvalist.count;
|
||||
w->host.resvals_to_sched = (xce_name_val_t**)resvalist.data;
|
||||
{
|
||||
/* bug-1506: take OWNERSHIP of resvalist.data so the xlist_fini
|
||||
* below does not free the array w->host.resvals_to_sched aliases.
|
||||
* The old code pointed resvals_to_sched at resvalist.data, then
|
||||
* xlist_fini(&resvalist) freed it — a concurrent reader (the
|
||||
* WORKER_JOIN hook encoding the worker's resvals, via
|
||||
* encode_NameValue_list) read the dangling pointer → ASAN
|
||||
* heap-use-after-free that crashed the controller. The prior
|
||||
* resvals_to_sched (if any) is intentionally left allocated: freeing
|
||||
* it here would race the same readers (the old #if 0
|
||||
* free_name_val_list block was disabled for this reason). */
|
||||
void* p = NULL;
|
||||
MOVE_PTR(p, resvalist.data);
|
||||
w->host.nresvals_to_sched = resvalist.count;
|
||||
w->host.resvals_to_sched = (xce_name_val_t**)p;
|
||||
}
|
||||
|
||||
mylock_lock(&(c->sched.lock));
|
||||
if (c->sched.ep != NULL) {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "xcelog.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -799,7 +800,22 @@ static int job_start_local_task(xce_request_t* request)
|
|||
}
|
||||
|
||||
if (job_ctx->startinfo->execuser != NULL) {
|
||||
job_ctx->limits->user_name = strdup(job_ctx->startinfo->execuser);
|
||||
/* bug-1507: only use the exec user if it actually exists on this
|
||||
* host. The API-layer submit user (e.g. "admin") is not
|
||||
* necessarily a real /etc/passwd account, and systemd then fails
|
||||
* the worker unit with EXIT_USER (217), killing every job. Fall
|
||||
* back to nobody so the job still runs. */
|
||||
struct passwd* pw = getpwnam(job_ctx->startinfo->execuser);
|
||||
if (pw != NULL) {
|
||||
job_ctx->limits->user_name
|
||||
= strdup(job_ctx->startinfo->execuser);
|
||||
} else {
|
||||
job_ctx->limits->user_name = strdup("nobody");
|
||||
XCECD_LOG(XCE_LOG_WARN,
|
||||
"exec user '%s' does not exist on this host, "
|
||||
"running job as nobody",
|
||||
job_ctx->startinfo->execuser);
|
||||
}
|
||||
} else {
|
||||
job_ctx->limits->user_name = strdup("nobody");
|
||||
XCECD_LOG(XCE_LOG_WARN,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue