nodejs / postject

Easily inject arbitrary read-only resources into executable formats (Mach-O, PE, ELF) and use it at runtime.
Other
187 stars 14 forks source link

SEA created following Node.js documentation doesn't work #76

Closed targos closed 1 year ago

targos commented 1 year ago

Doing exactly as documented in https://nodejs.org/api/single-executable-applications.html

On macOS arm64

$ cat hello.js
console.log(`Hello, ${process.argv[2]}!`);

$ ./hello -v
v19.7.0

$ npx postject hello NODE_JS_CODE hello.js \
    --sentinel-fuse NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2 \
    --macho-segment-name NODE_JS

$ ./hello
[1]    20992 killed     ./hello

$ ./hello world
[1]    21015 killed     ./hello world

On Linux x64

$ cat hello.js
console.log(`Hello, ${process.argv[2]}!`);

$ ./hello -v
v19.7.0

$ npx postject hello NODE_JS_CODE hello.js \
    --sentinel-fuse NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2
Can't find string offset for section name '.note.100'
Can't find string offset for section name '.note.100'
Can't find string offset for section name '.note.100'
Can't find string offset for section name '.note.100'
Can't find string offset for section name '.note.100'
Can't find string offset for section name '.note'
Can't find string offset for section name '.note.100'
Can't find string offset for section name '.note.100'
Can't find string offset for section name '.note.100'

$ ./hello
[1]    2517236 segmentation fault (core dumped)  ./hello

$ ./hello world
[1]    2517265 segmentation fault (core dumped)  ./hello world
RaisinTen commented 1 year ago

Regarding the macOS issue, could you try running codesign --sign - hello and then try again? I think it segfaults because the binary isn't signed anymore after postject processes it and having executables signed is a hard requirement on arm64.

targos commented 1 year ago

Regarding the macOS issue, could you try running codesign --sign - hello and then try again?

That works! I think it should be documented somewhere.

RaisinTen commented 1 year ago

Done - https://github.com/nodejs/node/pull/46764!

RaisinTen commented 1 year ago

I'm able to reproduce the Linux issue. Just wondering why we weren't able to catch this when the change was in a PR state. @targos do we use some non-default configure flags to build Node.js for official releases? Also, what compiler did we use for the release?

targos commented 1 year ago

Based on https://ci-release.nodejs.org/job/iojs+release/9167/nodes=rhel8-x64-release/consoleFull

System: RHEL 8.7 Compiler: gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-16) Configure:

python3 ./configure \
    --prefix=/ \
    --dest-cpu=x64 \
    --tag= \
    --release-urlbase=https://nodejs.org/download/release/ \
    --download-path=/home/iojs/node-icu/ --verbose --download=all --with-intl=full-icu

Compile:

make install DESTDIR=node-v19.7.0-linux-x64 V=0 PORTABLE=1
make -C out BUILDTYPE=Release V=0

Edit: found the release build for 19.7.0

RaisinTen commented 1 year ago

@targos I wasn't able to repro this locally when I built node using the same options on an x64 ubuntu. Maybe this has something to do with the compiler / system where the build took place. GDB tells me that the crash took place somewhere inside:

0x0000000000c7df55 in (anonymous namespace)::GetSingleExecutableCode(v8::FunctionCallbackInfo<v8::Value> const&) ()

This is the topmost frame in the stack trace, so I would need some more info.

(I have a hunch that this crash source is the same as https://github.com/nodejs/postject/issues/70 but I don't have a way to confirm without having access to the system.)

I'll open an issue asking for access in the build repo - https://github.com/nodejs/build/issues/3207.

RaisinTen commented 1 year ago

I've confirmed that https://github.com/nodejs/postject/pull/77 fixes the issue.

targos commented 1 year ago

I confirm that the binary created with postject@1.0.0-alpha.5 and Node.js 19.8.1 works.

There are still warnings printed, though:

$ npx postject@latest hello NODE_JS_CODE hello.js \
    --sentinel-fuse NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2
Start injection of NODE_JS_CODE in hello...
warning: Can't find string offset for section name '.note.100'
warning: Can't find string offset for section name '.note.100'
warning: Can't find string offset for section name '.note.100'
warning: Can't find string offset for section name '.note.100'
warning: Can't find string offset for section name '.note.100'
warning: Can't find string offset for section name '.note'
warning: Can't find string offset for section name '.note.100'
warning: Can't find string offset for section name '.note.100'
warning: Can't find string offset for section name '.note.100'
šŸ’‰ Injection done!
Oman395 commented 3 months ago

Experiencing this issue with node v22.5.1, npm 10.8.2, and postject 1.0.0-alpha.6 (the version NPM is installing), with arch linux kernel 6.10.1-arch1-1 Logs:

āžœ  miscjs mkdir sea
āžœ  miscjs cd sea
āžœ  sea echo 'console.log(`Hello, ${process.argv[2]}!`);' > hello.js
āžœ  sea echo '{ "main": "hello.js", "output": "sea-prep.blob" }' > sea-config.json
āžœ  sea node --experimental-sea-config sea-config.json
Wrote single executable preparation blob to sea-prep.blob
āžœ  sea cp $(command -v node) hello
āžœ  sea ls
hello  hello.js  sea-config.json  sea-prep.blob
āžœ  sea npx postject hello NODE_SEA_BLOB sea-prep.blob \
    --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
Start injection of NODE_SEA_BLOB in hello...
warning: Can't find string offset for section name '.note'
šŸ’‰ Injection done!
āžœ  sea ls
hello  hello.js  sea-config.json  sea-prep.blob
āžœ  sea file hello
hello: ELF 64-bit LSB pie executable, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=8ddabc56835c0401f47b7e9ea29c375bff5d8ebc, for GNU/Linux 4.4.0, stripped
āžœ  sea ./hello
[1]    94256 segmentation fault (core dumped)  ./hello
āžœ  sea echo $?
139