How to Build The Elf Interpreter (Ld-Linux.So.2/Ld-2.17.So) as Static Library

-jailshell: d-linux-x86-64.so.2: bad ELF interpreter: No such file or directory

I'm trying to install an executable but it gives me the error

This executable is corrupt.

It is trying to use d-linux-x86-64.so.2 as an interpreter, and such a file doesn't exist (nor should it exist) on your machine.

Chances are this executable was transferred over FTP in ASCII mode, or corrupted in some other way.

I have already checked if I have the glib 32-bit version

That is irrelevant: the binary you are trying to build is a 64-bit binary.

Also, there is a difference between glib and glibc.

Why is ld.so a shared object?

Can a dynamic linker be a simple ELF executable (ET_EXEC) ?

Yes, it can.

However, an ET_EXEC must be loaded at the address it was linked at, and that address may conflict with the address at which a.out itself is linked. If such conflict happens, the kernel will either kill the process before it even starts, or it will mmap a.out "on top of" ld.so, and the resulting binary will crash.

You can move ld.so out of the way of usual a.out link address, but someone can always link a.out at un-usual address.

If instead you link ld.so as ET_DYN, with load address of zero, then none of the above problems could happen.

patchelf set interpreter to a path relative to executable

You need to specify the path relative to the current working directory (the one you use to execute the program) and not relative to the directory that contains the binary file.

echo 'int main() { return 0; }' > main.c
gcc -Wl,--dynamic-linker=./lib/ld-linux-x86-64.so.2 -o main main.c

mkdir bin
mkdir lib
cp /lib64/ld-linux-x86-64.so.2 lib/
cp main bin/

bin/main # this should run without problems
cd bin; ./main # this throws a "No such file or directory" error

Can `dlopen` be used to load and mmap a static ELF executable (not library)?

If file anexe is static compiled, no symbols, no exports, ELF, can dlopen("anexe", RTLD_LAZY) be used to map it into memory?

No (but see below).

My goal isn't to be able to reference symbols -- there are no symbols. Rather, my goal is to be able to call its functions given their addresses (which are fixed, not PIC), and to read its data given address.

Note that a non-PIE executable can only be loaded at the address it was linked at. You can find which address that is by examining its program headers (programmatically, or with readelf -Wl).

Once you know which address it should be loaded at (and assuming that address is not already occupied by your own executable), then you can perform a series of mmap calls to "load" that executable into memory, and after that you can call its functions and read its data.

One complication is that the executable's initializers will not have run (you didn't call its _start, nor would you want to), and so functions in it may not run correctly, may crash, etc.

For example, given this binary:

$ echo "int main() { return 0; }" | gcc -xc - -static -no-pie -o a.out
$ readelf -Wl a.out | egrep 'Type|LOAD'

Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x000518 0x000518 R 0x1000
LOAD 0x001000 0x0000000000401000 0x0000000000401000 0x07fd01 0x07fd01 R E 0x1000
LOAD 0x081000 0x0000000000481000 0x0000000000481000 0x026660 0x026660 R 0x1000
LOAD 0x0a7928 0x00000000004a8928 0x00000000004a8928 0x0059c8 0x007298 RW 0x1000

you would need to perform 4 mmap calls (one for each LOAD segment), with MAP_FIXED. The address, file offset, size and protection arguments for mmap are obvious.

The mmap arguments for the last segment may not be: you would need to round address and offset down to Align, and extend the size by 0x928 to account for that rounding.

Using $ORIGIN to specify the interpreter in ELF binaries isn't working

If I specify an absolute path instead of using $ORIGIN then it seems to work fine.

This is working as intended.

It is the dynamic linker that interprets (expands) $ORIGIN and other special tokens.

The Linux kernel doesn't.

And it is the kernel that reads PT_INTERP segment of the main executable and (if present) loads and invokes the interpreter (the dynamic linker). When you set interpreter to non-existant path (such as $ORIGIN/lib/ld-linux-x86-64.so.2), you get ENOENT from the kernel execve system call.

There is no way to make interpreter itself be anything other than valid path.

Depending on what you are actually trying to achieve, rtldi may be the answer.

Where is segment %fs for static elf images setup?

You need to call arch_prctl with an ARCH_SET_FS argument before you can use the %fs segment prefix. You will have to allocate the backing store somewhere (brk, mmap, or an otherwise unused part of the stack).

glibc does this in __libc_setup_tls in csu/libc-tls.c for statically linked binaries, hidden behind the TLS_INIT_TP macro.

Multiple glibc libraries on a single host

It is very possible to have multiple versions of glibc on the same system (we do that every day).

However, you need to know that glibc consists of many pieces (200+ shared libraries) which all must match. One of the pieces is ld-linux.so.2, and it must match libc.so.6, or you'll see the errors you are seeing.

The absolute path to ld-linux.so.2 is hard-coded into the executable at link time, and can not be easily changed after the link is done (Update: can be done with patchelf; see this answer below).

To build an executable that will work with the new glibc, do this:

g++ main.o -o myapp ... \
-Wl,--rpath=/path/to/newglibc \
-Wl,--dynamic-linker=/path/to/newglibc/ld-linux.so.2

The -rpath linker option will make the runtime loader search for libraries in /path/to/newglibc (so you wouldn't have to set LD_LIBRARY_PATH before running it), and the -dynamic-linker option will "bake" path to correct ld-linux.so.2 into the application.

If you can't relink the myapp application (e.g. because it is a third-party binary), not all is lost, but it gets trickier. One solution is to set a proper chroot environment for it. Another possibility is to use rtldi and a binary editor. Update: or you can use patchelf.



Related Topics



Leave a reply



Submit