build: fix invocation of bundled ld.so in SDK and Imagebuilder
Commit 72d751cba9
"build: rework library bundling" introduced a new helper
binary "runas" whose sole purpose was mangling the argv vector passed to
the actual called ELF image so that the renamed executable could obtain the
proper name from argv[0].
This approach, however totally defeated the purpose of calling bundled ELF
executables through the shipped ld.so loader since the execv() invocation
performed by "runas" would cause the kernel the interprete the final program
image through the system ELF loader again.
To solve the problem, use an alternative approach of shipping a shared object
"runas.so" which uses an ELF ".init_array" function pointer to obtain the
argv[] vector of the to-be-executed main() function and mangle it in-place.
The actual argv[0] value to use is communicated out-of-band using an
environment variable "RUNAS_ARG0" by the shell wrapper script. The wrapper
script also takes care of setting LD_PRELOAD to instruct the shipped ELF
loader to preload the actual ELF program image with the "runas.so" helper
library.
Fixes FS#909.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
parent
f2fdd68664
commit
ef1cafa736
1 changed files with 18 additions and 15 deletions
|
@ -70,26 +70,27 @@ _relpath() {
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
_wrapper() {
|
_runas_so() {
|
||||||
cat <<-EOT | ${CC:-gcc} -x c -o "$1" -
|
cat <<-EOT | ${CC:-gcc} -x c -fPIC -shared -o "$1" -
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int mangle_arg0(int argc, char **argv, char **env) {
|
||||||
const char *self = argv[0];
|
char *arg0 = getenv("RUNAS_ARG0");
|
||||||
const char *target = argv[1];
|
|
||||||
|
|
||||||
if (argc < 3) {
|
if (arg0)
|
||||||
fprintf(stderr, "Usage: %s executable arg0 [args...]\n", self);
|
argv[0] = arg0;
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return execv(target, argv + 2);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__((section(".init_array")))
|
||||||
|
static void *mangle_arg0_constructor = &mangle_arg0;
|
||||||
EOT
|
EOT
|
||||||
|
|
||||||
[ -x "$1" ] || {
|
[ -x "$1" ] || {
|
||||||
echo "compiling wrapper failed" >&2
|
echo "compiling preload library failed" >&2
|
||||||
exit 5
|
exit 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,13 +114,13 @@ for BIN in "$@"; do
|
||||||
_ln "../lib" "$DIR/usr/lib"
|
_ln "../lib" "$DIR/usr/lib"
|
||||||
}
|
}
|
||||||
|
|
||||||
[ ! -x "$DIR/lib/runas" ] && {
|
[ ! -x "$DIR/lib/runas.so" ] && {
|
||||||
_wrapper "$DIR/lib/runas"
|
_runas_so "$DIR/lib/runas.so"
|
||||||
}
|
}
|
||||||
|
|
||||||
LDSO=""
|
LDSO=""
|
||||||
|
|
||||||
[ -n "$LDD" ] && [ -x "$BIN" ] && file "$BIN" | grep -sqE "ELF.*executable" && {
|
[ -n "$LDD" ] && [ -x "$BIN" ] && file "$BIN" | grep -sqE "ELF.*(executable|interpreter)" && {
|
||||||
for token in $("$LDD" "$BIN" 2>/dev/null); do
|
for token in $("$LDD" "$BIN" 2>/dev/null); do
|
||||||
case "$token" in */*.so*)
|
case "$token" in */*.so*)
|
||||||
case "$token" in
|
case "$token" in
|
||||||
|
@ -150,7 +151,9 @@ for BIN in "$@"; do
|
||||||
cat <<-EOF > "$BIN"
|
cat <<-EOF > "$BIN"
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
dir="\$(dirname "\$0")"
|
dir="\$(dirname "\$0")"
|
||||||
exec "\$dir/${REL:+$REL/}$LDSO" --library-path "\$dir/${REL:+$REL/}" "\$dir/${REL:+$REL/}runas" "\$dir/.${BIN##*/}.bin" "\$0" "\$@"
|
export RUNAS_ARG0="\$0"
|
||||||
|
export LD_PRELOAD="\$dir/${REL:+$REL/}runas.so"
|
||||||
|
exec "\$dir/${REL:+$REL/}$LDSO" --library-path "\$dir/${REL:+$REL/}" "\$dir/.${BIN##*/}.bin" "\$@"
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
chmod ${VERBOSE:+-v} 0755 "$BIN"
|
chmod ${VERBOSE:+-v} 0755 "$BIN"
|
||||||
|
|
Loading…
Reference in a new issue