Override the GNU C library — painlessly



Summary:  A great way to debug glibc functions is to override the function of interest with your own version. This can be done without having root permissions and without recompiling the libc source. Imagine the pure thrill of writing your own version of open()!

What do you do if you don’t have the source for your application and it’s failing because a GNU Library for C (glibc) function is returning something bad to the application? Because glibc is open-source, you can of course get the source code, make your changes, rebuild, and install. This is not for the faint of heart, however, because although the API is well documented, the internal organization of the GNU C library is not. Finding the correct function prototypes is only the first of many challenges. It’s a big package as well, so the first time you compile, it will take some time (glibc 2.2.2 has 8,552 files and 1,775,440 lines of code, including comments).

A better way

Better than rebuilding glibc is selectively overriding a function. Many of the modern Unixes support the concept of preloading user defined libraries. These libraries can be either complete replacements (that is, a private version of glibc) or subsets — even a single function. You can use a private version of glibc by setting the LD_LIBRARY_PATH to include your private version of the library first. You can use a subset of library routines that you write by using the LD_PRELOAD environmental value. Both LD_LIBRARY_PATH and LD_PRELOAD are controlled by the dynamic ELF linker/loader. It uses a first match to satisfy any symbol name. By preloading your version of a library or function you short circuit the normal path, allowing you to override it.

Here’s an example makefile that overrides the glibc function setresgid():

Makefile to override setresgid()

# Makefile

all: libs setresgid-tester

# Make a shared Library
libs: libfuncs.c
gcc -shared -Wl,-soname,libfuncs.so.1 -o libfuncs.so.1.0 libfuncs.c
ln -s libfuncs.so.1.0 libfuncs.so.1
ln -s libfuncs.so.1 libfuncs.so

# Here is a program that calls setresgid() for testing
setresgid-tester: setresgid-tester.c
gcc -o setresgid-tester setresgid-tester.c


The file libfuncs.c contains my private version of setresgid(). Be careful to implement it to support the same number of arguments and in other ways act the same as the original setresgid(), although my version lies to the application and always returns 0.

The second file of interest is setresgid-tester.c. It tries out the new function by calling setresgid().

This is the source code for the dynamic library:

Replacement library

Put all the functions you want to override here
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>

int errno;

setresgid(rgid, egid, sgid)
gid_t rgid,egid,sgid;
printf("It me the shim, Hi there!n");



You’ll also need a simple way to test your private version of setresgid(). You can use strace or ltrace to watch the process run. This is the source for a trivial test example:

Trivial test example

setresgid() system/library call tester


Now compile the library, set the LD_PRELOAD shell variable and run the test application. You may also need to set your LD_LIBRARY_PATH.

Running test application

export LD_PRELOAD=libfuncs.so
It's me the shim, Hi there!


You can also confirm that your private library is being used by using ldd to list the dynamically linked libraries:

Confirming use of private library

[jay@prion ld_preload]$ ldd setresgid-tester
libfuncs.so => libfuncs.so (0x40018000)
libc.so.6 => /lib/libc.so.6 (0x40022000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)



Writing private versions of GNU C library functions is a great way to debug systems problems or make quick fixes. Using the LD_PRELOAD shell variable, you can selectively override system C library functions with your own private versions. This technique works for both Linux and Solaris environments.


About the author


Change vlan device name

        Function:  register_vlan_device()
        Location:  net/8021q/vlan.c
static int register_vlan_device(struct net_device *real_dev, u16 vlan_id)
                   switch (vn->name_type) {
                   case VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD:
snprintf(name, IFNAMSIZ, "%s.%i", real_dev->name, vlan_id);
snprintf(name, IFNAMSIZ, "%s%i", "eth", vlan_id);
                   case VLAN_NAME_TYPE_PLUS_VID:
                                      /* Put our vlan.VID in the name.
                                       * Name will look like:    vlan0005
                                      snprintf(name, IFNAMSIZ, "vlan%.4i", vlan_id);

VirtualBox access physical disk partition

List DISK partitions:

VBoxManage.exe internalcommands listpartitions -rawdisk \.PhysicalDrive0
VBoxManage.exe internalcommands listpartitions -rawdisk \.PhysicalDrive1
VBoxManage.exe internalcommands listpartitions -rawdisk \.PhysicalDrive2


Create raw VMDK:

VBoxManage internalcommands createrawvmdk -filename K:vdiskwhole.vmdk -rawdisk \.PhysicalDrive1 -partitions 1,2,3,4
VBoxManage internalcommands createrawvmdk -filename K:vdiskpart1.vmdk -rawdisk \.PhysicalDrive1 -partitions 1
VBoxManage internalcommands createrawvmdk -filename K:vdiskpart2.vmdk -rawdisk \.PhysicalDrive1 -partitions 2
VBoxManage internalcommands createrawvmdk -filename K:vdiskpart3.vmdk -rawdisk \.PhysicalDrive1 -partitions 3
VBoxManage internalcommands createrawvmdk -filename K:vdiskpart4.vmdk -rawdisk \.PhysicalDrive1 -partitions 4


Manage ram VMDK in Graphics VirtualBox Manager as usual.


Reserve eth0 slot in Linux Kernel

   Function:      __dev_alloc_name
   Location:      net/core/dev.c
static int __dev_alloc_name(...)
for_each_netdev(net, d) {
/* Add two lines */ 
if (!strncmp(name,"eth",3))                    
  set_bit(0, inuse);

Ubuntu 10.04/Lucid Kernel Rebuild



Install tool:

sudo apt-get install fakeroot build-essential crash kexec-tools 
makedumpfile kernel-wedge
sudo apt-get build-dep linux
sudo apt-get install git-core libncurses5 libncurses5-dev 
libelf-dev asciidoc binutils-dev


Download the source archive

sudo apt-get build-dep --no-install-recommends linux-image-$(uname -r)
apt-get source linux-image-$(uname -r)


Change to source directory & Make scripts executable 

cd linux-2.6.32/

sudo chmod -R u+x debian/scripts/*


Modify code



Update config

debian/rules updateconfigs


Build kernel

sudo fakeroot debian/rules clean
fakeroot debian/rules binary-generic

Trigger Rebuild

sudo rm debian/stamps/stamp-build-generic
fakeroot debian/rules binary-generic

Build Result

Located in parent directory:

Install new kernel

sudo dpkg -i linux-headers-2.6.32-30-generic_2.6.32-30.59_amd64.deb
sudo dpkg -i linux-image-2.6.32-30-generic_2.6.32-30.59_amd64.deb

Check new kernel

        ls /usr/src
        ls /boot