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

Question about the sentinel fuse. #88

Open agnat opened 1 year ago

agnat commented 1 year ago

First, let me thank you guys for making this. It's really fun to work with and it certainly beats appending a zip to the executable. 😁

I'm unsure about the sentinel though. On one hand the goal is compatibility with build-time injection using the linker. On the other hand, the only thing that prevents me from loading link-time resources is the sentinel fuse. I'd have to run sed or something...

Looking at the test.cpp it would seem it is safe to ignore postject_has_resource() since postject_find_resource(...)will return null if no resource is found. And indeed my application works better without postject_has_resource(). Now I can load both, resources injected at build-time and resources injected using postject.

So, my question is what is the sentinel/fuse actually guarding against? It just seems odd to introduce this artificial string substitution step since it breaks one of the main design goals: compatibility with link-time injection.

Unless the fuse has a hidden purpose that I don't understand just yet, I feel postject would be better of without it.

Thanks for looking into this...

mhdawson commented 1 year ago

If it's what I think you are asking about the fuse is to ensure there is as close as possible to 0 impact on Node.js binaries shipped by the project. The furst ensures there is a close to zero overhead check so that when there is no bundled application there is no overhead.

agnat commented 1 year ago

Ah ok... a very low overhead pre-check makes sense. For build-time injection via linker-flags it would also make sense to set the fuse at build time. How about we somehow expose the initial value:

#ifndef POSTJECT_FUSE_VALUE
# define POSTJECT_FUSE_VALUE 0
#endif
// use stringify macros to build the actual string

... or with a bit more API:

#ifdef POSTJECT_INJECT_USING_LINKER  // TODO: better name?
# define POSTJECT_FUSE_VALUE ":1"
#else
# define POSTJECT_FUSE_VALUE ":0"
#endif 

Let me know which style you prefer and I make a PR...

RaisinTen commented 1 year ago

FWIW, the initial value is already exposed as the POSTJECT_SENTINEL_FUSE macro in the header file: https://github.com/nodejs/postject/blob/3c4f2080ee56025716c3add0f6c03b16e2af54ff/postject-api.h#L20-L23

It can be customized at build-time if the POSTJECT_SENTINEL_FUSE macro is defined before the header is included. For reference, this is how it is done in Node.js: https://github.com/nodejs/node/blob/f9737b1b8c96e43cedfff764634524df62cf3109/src/node_sea.cc#L11-L18

// The POSTJECT_SENTINEL_FUSE macro is a string of random characters selected by
// the Node.js project that is present only once in the entire binary. It is
// used by the postject_has_resource() function to efficiently detect if a
// resource has been injected. See
// https://github.com/nodejs/postject/blob/35343439cac8c488f2596d7c4c1dddfec1fddcae/postject-api.h#L42-L45.
#define POSTJECT_SENTINEL_FUSE "NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2"
#include "postject-api.h"
#undef POSTJECT_SENTINEL_FUSE

Is this what you were looking for?

agnat commented 1 year ago

No. The macro POSTJECT_SENTINEL_FUSE defines the fuse name. I'd like to override the initial fuse value, which is currently a string literal. See https://github.com/nodejs/postject/blob/main/postject-api.h#L42

This is useful when embedding resources using the linker.

RaisinTen commented 1 year ago

Ah, okay. I personally like the second option in https://github.com/nodejs/postject/issues/88#issuecomment-1633098251 more than the first one. Feel free to send a PR. :)