Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
    npro  
 Modern all-safe Rust Network Protocol library supporting h1, h2, h3, ws, wt sans-IO and with socket IO + tls
git clone https://npro.rs/repo/npro
 
root / assets / linux-fedora-32.svg
Author[]Andy Green <andy@warmcat.com> 2026-09-25 02:05 UTC
Committer[]Andy Green <andy@warmcat.com> 2026-09-25 02:05 UTC
Tree319845b725729a7bfe551424aa37a0014be4fc1f   Raw Patch
 
builder: fix nspawn lifecycle NULL derefs and the reap cb success path
builder: fix nspawn lifecycle NULL derefs and the reap cb success path

Three NULL derefs:

 - the stdwsi CLOSE handler reads ns->reap_cb_called inside
   if (op && op->lsp), but ns is op->ns, which saib_sub_cleaner_cb()
   deliberately clears when it gives up on a child that refused to die
 - the nspawn census loop dereferences xns->task->uuid, which the
   sai-device log proxy UDS failures below could leave NULL
 - those UDS failures returned -1 with the nspawn already on
   sp->nspawn_owner and no task bound, leaking it onto the list forever
   and leaving the server waiting on a task nothing would ever finish.
   Fail the task through bail: instead

And two flow bugs in sai_lsp_reap_cb()'s success path, either of which
could turn a step that exited 0 into a failure or a hang:

 - sai_metrics_hash() failing did goto fail, reporting "FAILED, exit
   code: 0" for a step that succeeded
 - failing to queue the metrics did a bare return, leaving the ns in
   EXECUTING_STEPS with a dead child, no final log chunk, no grace timer
   and no status update, so the task hung on the server until something
   else knocked it over

Neither is a reason not to complete a step, so both just skip the
metrics now.  ns->spm->ss is also checked before the send: only ns->spm
was, and saib_srv_queue_tx() dereferences the handle straight away, so a
server link that had dropped was a NULL deref.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
diff --git a/src/builder/b-nspawn.c b/src/builder/b-nspawn.c index d0bd5c5..da79338 100644 --- a/src/builder/b-nspawn.c +++ b/src/builder/b-nspawn.c @@ -268,8 +268,13 @@ callback_sai_stdwsi(struct lws *wsi, enum lws_callback_reasons reason, op->ns->stdwsi[ch] = NULL; } if (op && op->lsp) { + /* + * ns is op->ns, which saib_sub_cleaner_cb() clears + * when it gives up on a child that refused to die, so + * it can legitimately be NULL here + */ if (lws_spawn_stdwsi_closed(op->lsp, wsi) && - ns->reap_cb_called) { + ns && ns->reap_cb_called) { lwsl_notice("%s: freeing op from stdwsi_cb\n", __func__); free(op); } @@ -476,14 +481,20 @@ sai_lsp_reap_cb(void *opaque, const lws_spawn_resource_us_t *res, siginfo_t *si, * server so it can store them. */ - if (!op->spawn || !ns->spm) + if (!op->spawn || !ns->spm || !ns->spm->ss) goto skip; memset(&m, 0, sizeof(m)); + /* + * Not being able to key the metrics is not a reason to fail a step + * that exited 0... the metrics are just bookkeeping + */ if (sai_metrics_hash((uint8_t *)m.key, sizeof(m.key), - ns->sp->name, ns->task->build, ns->project_name, ns->ref)) - goto fail; + ns->sp->name, ns->task->build, ns->project_name, ns->ref)) { + lwsl_notice("%s: unable to hash metrics key\n", __func__); + goto skip; + } lws_strncpy(m.builder_name, ns->sp->name, sizeof(m.builder_name)); lws_strncpy(m.project_name, ns->project_name, sizeof(m.project_name)); @@ -499,10 +510,16 @@ sai_lsp_reap_cb(void *opaque, const lws_spawn_resource_us_t *res, siginfo_t *si, m.parallel = ns->task->parallel; m.step = ns->task->build_step + 1; + /* + * Likewise: if we can't get the metrics away, complete the step + * anyway. Returning here used to leave the ns in EXECUTING_STEPS with + * a dead child, no grace timer and no status update, so the task hung + * on the server until something else knocked it over. + */ if (saib_srv_queue_json_fragments_helper(ns->spm->ss, lsm_schema_map_build_metric, LWS_ARRAY_SIZE(lsm_schema_map_build_metric), &m)) - return; + lwsl_notice("%s: unable to queue step metrics\n", __func__); skip: diff --git a/src/builder/b-task.c b/src/builder/b-task.c index f423e06..ed89401 100644 --- a/src/builder/b-task.c +++ b/src/builder/b-task.c @@ -922,7 +922,8 @@ saib_consider_allocating_task(struct sai_plat_server *spm, lws_struct_args_t *a, lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, sp->nspawn_owner.head) { struct sai_nspawn *xns = lws_container_of(d, struct sai_nspawn, list); - lwsl_notice("%s: nspawn_census: %s\n", __func__, xns->task->uuid); + lwsl_notice("%s: nspawn_census: %s\n", __func__, + xns->task ? xns->task->uuid : "(no task)"); } lws_end_foreach_dll_safe(d, d1); lwsl_notice("%s:\n", __func__); @@ -1050,9 +1051,11 @@ saib_consider_allocating_task(struct sai_plat_server *spm, lws_struct_args_t *a, if (saib_create_listen_uds(builder.context, &ns->slp_control, &ns->vhosts[0])) { - lwsl_err("%s: Failed to create ctl log proxy listen UDS %s\n", - __func__, ns->slp_control.sockpath); - return -1; + saib_task_logf(spm, ns, NULL, + "Unable to create the sai-device control " + "log proxy socket %s", + ns->slp_control.sockpath); + goto bail; } for (n = 0; n < (int)LWS_ARRAY_SIZE(ns->slp); n++) { @@ -1070,9 +1073,11 @@ saib_consider_allocating_task(struct sai_plat_server *spm, lws_struct_args_t *a, if (saib_create_listen_uds(builder.context, &ns->slp[n], &ns->vhosts[n + 1])) { - lwsl_err("%s: Failed to create log proxy listen UDS %s\n", - __func__, ns->slp[n].sockpath); - return -1; + saib_task_logf(spm, ns, NULL, + "Unable to create the sai-device " + "tty%d log proxy socket %s", + n, ns->slp[n].sockpath); + goto bail; } } }
Page fetched 0s ago, creation time: 2ms (vhost etag hits: 0%, cache hits: 0%)