SEA: BlobDeserializer SIGSEGVs when fuse byte is set but no NODE_SEA_BLOB is present
Nessuno ha ancora preso questa issue.
- Lingua principale
- JavaScript
- Stelle
- 122k
- Fork
- 37.3k
- Merge medio
- 4g 2h
- PR unite (30g)
- 283
Descrizione
Version
v26.1.0 (also reproduces on v25.6.0)
Platform
Linux arm64 (reproduced on Apple Silicon via Docker Desktop, but the SEGV is platform-independent)
Subsystem
sea
What steps will reproduce the bug?
Binaries where the postject fuse byte is set to 1 but NODE_SEA_BLOB cannot be located at runtime currently die with a NULL-deref SIGSEGV inside BlobDeserializer::ReadArithmetic, with no error message indicating the cause.
Take any Node binary, flip the fuse byte from 0 to 1 without injecting an actual SEA blob:
python3 -c "
sent = b'NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2'
with open('hello','rb') as f: buf = bytearray(f.read())
i = buf.find(sent)
buf[i + len(sent) + 1] = ord('1')
with open('hello','wb') as f: f.write(bytes(buf))
"
chmod +x hello
./hello --version # → Segmentation fault, exit 139
This state arises naturally when postject is run against a host binary with no PT_NOTE program header — postject silently fails to inject the note but still flips the fuse byte. See https://github.com/nodejs/postject/issues/107 and https://github.com/nodejs/unofficial-builds/issues/200.
How often does it reproduce? Is there a required condition?
100% reproducible. Required condition: fuse byte set to 1 AND no NODE_SEA_BLOB discoverable via postject_find_resource().
What is the expected behavior? Why is that the expected behavior?
A clear error indicating that the SEA fuse is set but no blob is present, rather than a bare SIGSEGV at startup. The current behavior makes it look like a crash in OpenSSL or libc (because the SIGILLs from OpenSSL's ARM crypto-extension probes show up first under gdb), when the actual cause is much earlier and recoverable.
What do you see instead?
Program received signal SIGSEGV, Segmentation fault.
#0 memcpy ()
#1 node::BlobDeserializer<...>::ReadArithmetic<unsigned int>()
#2 node::sea::FindSingleExecutableResource()
#3 node::sea::FixupArgsForSEA(int, char**)
#4 node::Start(int, char**)
postject_find_resource("NODE_SEA_BLOB", &size, ...) returns NULL, then BlobDeserializer::ReadArithmetic calls memcpy(dst, NULL, sizeof(uint32_t)) → SIGSEGV.
Additional information
Suggested fix in node::sea::FindSingleExecutableBlob() (src/node_sea_bin.cc) — guard the deserialization on the resource lookup:
const char* blob = static_cast<const char*>(
postject_find_resource("NODE_SEA_BLOB", &size, ...));
if (blob == nullptr) {
fprintf(stderr,
"node: SEA fuse is set but no NODE_SEA_BLOB resource was found "
"in this binary. The host binary may be missing a PT_NOTE program "
"header (run `readelf -lW <binary> | grep NOTE` to check).\n");
exit(static_cast<int>(node::ExitCode::kGenericUserError));
}
Either that or CHECK_NOT_NULL(blob) — anything that surfaces a cause rather than a bare SEGV.
Related:
- https://github.com/nodejs/unofficial-builds/issues/200 — upstream cause (arm64-musl tarball with no PT_NOTE)
- https://github.com/nodejs/unofficial-builds/pull/233 — fix for that root cause
- https://github.com/nodejs/postject/issues/107 — companion postject issue (silent injection failure)
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Inizia in src/node_sea_bin.cc, in node::sea::FindSingleExecutableBlob(), e segui il risultato di postject_find_resource("NODE_SEA_BLOB", ...) prima dell’esecuzione di BlobDeserializer. Riproduci il problema con il comando fornito per invertire il fuse, quindi verifica che l’assenza del blob produca un errore di avvio chiaro e un’uscita diversa da zero invece di un SIGSEGV.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- cpp, linux, nodejs
- Ambito
- operating-systems
- Tipo di issue
- Bug
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Stato di attività
- Attiva
- Chiarezza
- Specificata chiaramente
- Idoneità per principianti
- 76/100