nodejs / nodejs/node

SEA: BlobDeserializer SIGSEGVs when fuse byte is set but no NODE_SEA_BLOB is present

Ouverte Adaptée aux débutants
#63,466 2 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

stale
Langage dominant
JavaScript
Étoiles
122k
Forks
37.4k
Merge moyen
4 j 3 h
PR mergées (30 j)
272

Description

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:

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez dans src/node_sea_bin.cc, au niveau de node::sea::FindSingleExecutableBlob(), et suivez le résultat de postject_find_resource("NODE_SEA_BLOB", ...) avant l’exécution de BlobDeserializer. Reproduisez le problème avec la commande fournie qui inverse le fuse, puis vérifiez que l’absence du blob produit une erreur de démarrage claire et une sortie non nulle au lieu d’un SIGSEGV.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
cpp, linux, nodejs
Domaine
operating-systems
Type d'issue
Bug
Difficulté
2/5
Temps estimé
1-3 heures
Activité
Active
Clarté
Clairement spécifiée
Accessibilité débutants
76/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.