aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2017-07-16 23:43:19 +0200
committerJo-Philipp Wich <jo@mein.io>2017-07-21 08:09:45 +0200
commitef1cafa736679eb035d405bcdf903fd1fb329865 (patch)
tree800864adbf3c53c4c35220fabf6e40d8af63f247
parentf2fdd68664cdf09075e6f18b20946e41a22284b2 (diff)
downloadupstream-ef1cafa736679eb035d405bcdf903fd1fb329865.tar.gz
upstream-ef1cafa736679eb035d405bcdf903fd1fb329865.tar.bz2
upstream-ef1cafa736679eb035d405bcdf903fd1fb329865.zip
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>
-rwxr-xr-xscripts/bundle-libraries.sh33
1 files changed, 18 insertions, 15 deletions
diff --git a/scripts/bundle-libraries.sh b/scripts/bundle-libraries.sh
index dfc2b85a47..b108fd8f77 100755
--- a/scripts/bundle-libraries.sh
+++ b/scripts/bundle-libraries.sh
@@ -70,26 +70,27 @@ _relpath() {
done
}
-_wrapper() {
- cat <<-EOT | ${CC:-gcc} -x c -o "$1" -
+_runas_so() {
+ cat <<-EOT | ${CC:-gcc} -x c -fPIC -shared -o "$1" -
#include <unistd.h>
#include <stdio.h>
+ #include <stdlib.h>
- int main(int argc, char **argv) {
- const char *self = argv[0];
- const char *target = argv[1];
+ int mangle_arg0(int argc, char **argv, char **env) {
+ char *arg0 = getenv("RUNAS_ARG0");
- if (argc < 3) {
- fprintf(stderr, "Usage: %s executable arg0 [args...]\n", self);
- return 1;
- }
+ if (arg0)
+ argv[0] = arg0;
- return execv(target, argv + 2);
+ return 0;
}
+
+ __attribute__((section(".init_array")))
+ static void *mangle_arg0_constructor = &mangle_arg0;
EOT
[ -x "$1" ] || {
- echo "compiling wrapper failed" >&2
+ echo "compiling preload library failed" >&2
exit 5
}
}
@@ -113,13 +114,13 @@ for BIN in "$@"; do
_ln "../lib" "$DIR/usr/lib"
}
- [ ! -x "$DIR/lib/runas" ] && {
- _wrapper "$DIR/lib/runas"
+ [ ! -x "$DIR/lib/runas.so" ] && {
+ _runas_so "$DIR/lib/runas.so"
}
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
case "$token" in */*.so*)
case "$token" in
@@ -150,7 +151,9 @@ for BIN in "$@"; do
cat <<-EOF > "$BIN"
#!/usr/bin/env bash
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
chmod ${VERBOSE:+-v} 0755 "$BIN"