Is it possible to add missing functions to libc.so.6 via LD_PRELOAD?
The common knowledge is that it’s not possible, because missing functions are usually covered by not present symbol versions. Example: Red Hat 8 with getrandom() function marked as GLIBC_2.25 versus Red Hat 7 with GNU Lib C 2.17. Symbol version GLIBC_2.25 is not present in libc used on Red Hat 7 and as a result Linux loader will fail early before LD_PRELOAD would be able to shadow libc.
Is there any workaround? Yes, full proxy to libc. We can start with missing functions:
user@10.0.5.120[tmp] # cat glibc_compat.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>#define GRND_NONBLOCK 1
#define GRND_RANDOM 2asm(“.symver _getrandom, getrandom@@GLIBC_2.25”);
ssize_t _getrandom(void *buf, size_t buflen, unsigned int flags) {
int fd = open(flags & GRND_RANDOM ? “/dev/random” : “/dev/urandom”,
O_CLOEXEC | (flags & GRND_NONBLOCK ? O_NONBLOCK : 0), O_RDONLY);
if (fd<0) {
return fd;
}
int res = read(fd, buf, buflen);
close(fd);
return res;
}
Later we must add a lot of proxy functions doing dlopen/dlsym on /lib64/libc.so.6.
Our proxy can be compiled with:
gcc glibc_compat.c -o glibc_compat.so -shared -fPIC -Xlinker — version-script=/tmp/glibc_compat.map -Wl,-soname,libc.so.6
We need to have a version map file:
GLIBC_2.25 {
getrandom;
};GLIBC_2.27 {
glob;
};GLIBC_2.0 {};
…
GLIBC_2.3.4 {};
GLIBC_PRIVATE {};
We can proceed step by step with the binary we want to force to run with:
LD_DEBUG=all LD_PRELOAD=/tmp/glibc_compat.so ./linpmem-v3.3-rc3.bin