sloader
is an ELF loader that aims to replace ld-linux.so.2
of glibc.
sloader
haven't implmented almost all security related features. Please be careful.
sloader
can load many practical programs such as cmake
, g++
, ld
, htop
, etc. Furthermore, sloader
can launche some GUI applications.
However, sloader
depends on ld-linux.so
because I cannot statically link sloader
now.
$ git clone https://github.com/akawashiro/sloader.git
$ cd sloader
$ mkdir build
$ cmake -S . -B build -G Ninja
$ cmake --build build
$ ./build/sloader ls
When you run an executable binary file on Linux using execve(2), there are two execution paths.
- Linux kernel loads the file to the memory space.
- The loader specified by the file loads the file to the memory space.
You can check the specified loader path using readelf -l
. In most cases, you will find Requesting program interpreter: /lib64/ld-linux-x86-64.so.2
which means the loader loads the binary. Although the path includes -x86-64
because my machine is x86-64, I call it ld-linux.so
from now for generality.
$ readelf -l $(which nvim) | grep INTERP -A 2
INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
ld-linux.so
does three things when loading binary files.
- Seaches shared libraries that the file needs.
- Loads all shared libraries and the file to the memory.
- Resolves symbols of shared libraries and the file.
It is important to understand precisely how ld-linux.so
works. For example, valuable hacks with environment variables such as LD_PRELOAD and LD_AUDIT are implemented by changing their behavior. Understanding the behavior of ld-linux.so
will allow you to infer what these environment variables can and cannot do. Also, understanding it is essential for creating software like https://github.com/akawashiro/sold that forcibly links shared libraries.
ld-linux.so
is installed on Linux as part of GNU libc, and its complete source code is publicly available. However, two problems exist in understanding the behavior of ld-linux.so
from the published source code.
The first problem is that the GNU libc source code is hard to read. GNU libc is a software with a long history written in C language. It also requires portability to multiple architectures such as x86-84, Alpha, ARM, and PowerPC. As a result, macros are used extensively throughout the source code, making it difficult to follow the flow of the program.
The second problem is that libc.so
is simultaneously initialized when ld-linux.so
loads an executable file. And it is hard to understand the initialization and the loading process separately. libc.so is the so-called standard C library, which is almost certainly loaded when the binary file is loaded by ld-linux.so
. libc.so
and ld-linux.so
are in the same package, and glibc doesn't explicitly document the relationship between the two components.
To solve the above problems and understand ld-linux.so
behavior, I decided to develop a new loader that can replace ld-linux.so
. In other words, I am trying to load all the programs that start on Linux (systemd
, cat
, find
, firefox
, etc.).
I decided the following two principles when I started the development.
The first principle is to use modern C++ instead of C. I try to use modern C++ features up to C++20 to improve readability. I considered using Rust, but I decided that a language compatible with the C language would be better because I would be developing while referring to the GNU libc source code.
The second principle is not to initialize libc.so
. The purpose is to understand only the load part, so I will not do the complicated libc.so
.
$ git clone https://github.com/akawashiro/sloader.git
$ cd sloader
$ mkdir build
$ cmake -S . -B build -G Ninja
$ cmake --build build
$ cd build
$ ctest -V
$ git clone https://github.com/akawashiro/sloader.git
$ cd sloader
$ mkdir build
$ cmake -S . -B build -G Ninja
$ cmake --build build
$ ./misc/clone_glibc.sh
$ ./misc/build_glibc.sh
$ SLOADER_LIBRARY_PATH=/home/akira/sloader/glibc-install/lib ./build/sloader ./build/tests/hello_glibc/hello_glibc