9

Lets say I have a /bin/cat executable that uses the following shared libraries:

linux-vdso.so.1
libc.so.6
/lib64/ld-linux-x86-64.so.2

Is it possible to somehow "join" that stuff together (executable archive or something like that)?

I don't have the code of the program I want to do that to, so I can't just compile it with -static flag.

7

You can copy all of its libraries from their system locations into a subdirectory of where your executable is and use patchelf, to make the executable look for its libdependencies there instead of the system lib directories.

E.g.:

relativize_libs:

#!/bin/bash -e
[ -n "$1" ] || set -- a.out
mkdir -p ./lib/ #<copy the libraries here
#use ldd to resolve the libs and use `patchelf --print-needed to filter out
# "magic" libs kernel-interfacing libs such as linux-vdso.so, ld-linux-x86-65.so or libpthread
# which you probably should not relativize anyway
join \
    <(ldd "$1" |awk '{if(substr($3,0,1)=="/") print $1,$3}' |sort) \
    <(patchelf --print-needed "$1" |sort) |cut -d\  -f2 |

#copy the lib selection to ./lib
xargs -d '\n' -I{} cp --copy-contents {} ./lib 
#make the relative lib paths override the system lib path
patchelf --set-rpath "\$ORIGIN/lib" "$1"

(I believe that unlike LD_LIBRARY_PATH hacking, this should work with setuid executables too).

After that, all you've got to do is move that ./lib directory along with the executable.

1
  • 1
    Nice work! The "join" inputs must be sorted, so you should pipe the ldd and patchelf outputs both through sort.
    – Bklyn
    Oct 25 '17 at 14:34
5

Depends on what you mean by "join". The best way is to recompile the original source as a static binary.

However, you can include all of the libraries in a subdirectory that is controlled by the application (/usr/share/myapp for instance) and then put that directory in the library search order. One way to do this would be (in Linux) to use the LD_LIBRARY_PATH:

LD_LIBRARY_PATH=/usr/share/myapp/lib:/usr/local/lib:/usr/lib/i686-linux-gnu:/lib/i686-linux-gnu

In Linux, you can modify the /etc/ld.so.conf file to do the same thing - and Ubuntu adds the *.conf files in the /etc/ld.so.conf.d directory also.

2
  • +1. For clarification, I believe you'd have to recompile the original binary as a static binary.
    – Kyle Smith
    Feb 21 '12 at 17:15
  • Nope. Just set up the library search path as desired and be done with it.
    – Mei
    Feb 21 '12 at 18:05
4

Converting bunch of shared objects and a shared-lib ELF executable to one statically linked blob is not straight-forward.

The executable archive you mentioned might be possible. Assuming that by 'executable archive' you meant a file that when run un-zips itself and runs a program without dependencies on other files on the system.

This can be done quite simply using shell script and bunch of utilities found in most linux distros (However it adds dependencies on shell and the utilties). Making an ELF 'executable archive' might be much more involved although the principles are the same. If you expect your version of the program to be executed frequently, you should modify the script to 'install' it on to the users system as indicated by David and janneb.

An example using shell script based executable archive

Collect the files you need for the execution, an example using cat program would have the following:

fachas_cat_files/cat
fachas_cat_files/lib/libc.so.6

Base64 encode the tgz file and make it cat.b64, can be done like this after setting up your fachas_cat_files directory.

tar -cz fachas_cat_files | base64 > cat.b64

This makes a representation of the tar file with printable characters so it can be included in the script.

Note down the md5sums of the files you are packaging, which you use to verify whether the untarred files are your own or not, in the shell script.

find fachas_cat_files/ -type f -exec md5sum {} \; > cat.md5

Make a shell script like the following and name it your new "archive" program.

#!/bin/bash

TEMP_DIR=/tmp

# Check Md5sum
md5sum -c --quiet >/dev/null 2>&1 <<EOF 
--- Paste contents of cat.md5 here. ---
EOF

# Untar from base64 encoded tarball.
test $? -eq 0 || base64 -d <<EOF | tar -xz -C ${TEMP_DIR}
--- Paste contents of cat.b64 here. ---
EOF

# Execute the binary.
LD_LIBRARY_PATH=${TEMP_DIR}/fachas_cat_files/lib/ ${TEMP_DIR}/fachas_cat_files/cat $*

# Optionally remove the temporary files, if you do, the whole md5sum set of steps is 
# not necessary.
# rm -fr ${TEMP_DIR}/fachas_cat_files
0

No, it's not possible. What you might do is to create an archive (.tar.gz or whatever) containing

  • The original executable renamed, say bin/cat.real
  • A private directory, say lib/fachas-cat containing copies of all the libraries bin/cat.real needs
  • A shellscript bin/cat which sets LD_LIBRARY_PATH to $SOME_INSTALL_PREFIX/lib/fachas-cat/ and runs bin/cat.real
0

I would say that it should be possible if you are willing to write a modified 'ld-linux'-like bootstrap loader for your executable archive. If you inspect a running dynamic execuable in /proc/xxx/maps filesystem, you can see that a running dynamic executable is nothing more than a bunch of files mapped in the process memory space. These mapped files could be regions of your executable archive instead of separate files and still have exactly the same data visible to the process. You would have to make the regions in your executable archive aligned to PAGE_SIZE. Most of the other functionality than the finding and mapping of files (executable and libraries) in ld-linux can be unchanged.

Complications will arise when your executable uses API like dlopen. If you need those to be included in the executable archive as well, then you will also have to make a modified libdl.so and include that in the archive instead of the system libdl.so.

The executable archive will need to be PAGE_SIZE concatenation of the 'bootstrap ld-linux replacement' (static binary), a list of the included files and their offsets, so that your bootstrap can find them and the files themselves.

I think this would be a useful project if someone wants to take it on. Much lighter weight than a docker container.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy