SEA: BlobDeserializer SIGSEGVs when fuse byte is set but no NODE_SEA_BLOB is present
Nadie ha tomado este issue todavía.
- Lenguaje dominante
- JavaScript
- Estrellas
- 122k
- Forks
- 37.4k
- Merge medio
- 4 d 3 h
- PR fusionados (30 d)
- 272
Descripción
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)
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Línea de trabajo
Empieza en src/node_sea_bin.cc, en node::sea::FindSingleExecutableBlob(), y sigue el resultado de postject_find_resource("NODE_SEA_BLOB", ...) antes de que se ejecute BlobDeserializer. Reproduce el problema con el comando proporcionado para cambiar el fuse y verifica después que la ausencia del blob produzca un error de inicio claro y una salida distinta de cero en lugar de un SIGSEGV.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- cpp, linux, nodejs
- Área
- operating-systems
- Tipo de issue
- Error
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Estado de actividad
- Activo
- Claridad
- Bien especificado
- Aptitud para principiantes
- 76/100