Skip to content

postject silently succeeds when injecting into an ELF with no PT_NOTE program header #107

@awbx

Description

@awbx

On ELF binaries that have no PT_NOTE program header (e.g. those built with a toolchain that doesn't pass --build-id to ld), postject currently:

  1. Prints 💉 Injection done! and exits 0
  2. Doesn't actually modify the binary (file size and content are byte-identical before/after)
  3. Produces a binary where postject_find_resource() returns NULL at runtime

This makes downstream failures (SEGV in BlobDeserializer, "resource not found" errors in user code) look unrelated to postject and was the single biggest time-sink in diagnosing nodejs/unofficial-builds#200.

Reproduction

Using a musl-cross-make-built aarch64-linux-musl-gcc (or any toolchain that doesn't pass --build-id by default):

// test.c
#include <stdio.h>
#define POSTJECT_SENTINEL_FUSE "NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2"
#include "postject-api.h"
int main(void) {
    size_t size; const void* p = postject_find_resource("FOO", &size, NULL);
    return p == NULL ? 2 : 0;
}
gcc test.c -o test                                  # no --build-id by default on this toolchain
readelf -lW test | grep '^[[:space:]]*NOTE'         # (no output — no PT_NOTE)

ls -la test                                         # 8848 bytes
npx postject test FOO some.txt \
  --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
# → 💉 Injection done!  (exit 0)
ls -la test                                         # 8848 bytes  (unchanged!)
./test                                              # exit 2 (find_resource returned NULL)

Same source built with -Wl,--build-id=sha1 → postject grows the binary (8848 → 67408 bytes) and ./test returns 0.

Suggested fix

In inject_into_elf (src/postject.cpp), if the parsed ELF has no PT_NOTE segment, either:

  • Return InjectResult::kError and surface a clear error from the JS wrapper (e.g. "target has no PT_NOTE program header — rebuild with -Wl,--build-id or equivalent"), or
  • Have LIEF synthesize a PT_NOTE segment so the injection actually succeeds

Either is better than the current "exit 0, do nothing, produce broken downstream binary" behavior.

Context

Hit while diagnosing nodejs/unofficial-builds#200 (unofficial-builds arm64-musl tarball ships a binary with no PT_NOTE). Root-cause fix for that at nodejs/unofficial-builds#233. The silent-no-op behavior here was load-bearing in masking the actual problem during diagnosis.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions