Skip to content

sloader is an ELF loader which aims to replace ld-linux.so of glibc.

License

Notifications You must be signed in to change notification settings

akawashiro/sloader

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

sloader

sloader is an ELF loader that aims to replace ld-linux.so.2 of glibc.

Notice

sloader haven't implmented almost all security related features. Please be careful.

Table of Contents

Current status

sloader can load many practical programs such as cmake, g++, ld, htop, etc. Furthermore, sloader can launche some GUI applications. GUI applications launched by sloader

However, sloader depends on ld-linux.so because I cannot statically link sloader now.

How to build and use

$ git clone https://github.com/akawashiro/sloader.git
$ cd sloader
$ mkdir build
$ cmake -S . -B build -G Ninja
$ cmake --build build
$ ./build/sloader ls

Why I am making alternative loader

What is a loader

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.

Problem of ld-linux.so

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.

Motivation of making sloader

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.).

Developement principles of sloader

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.

For developpers

How to build and run tests

$ 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

Test using custom build glibc

$ 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