简体   繁体   中英

How to link a program with a “handmade compiled” version of glibc?

First of all, since this is the first question I ask on StackOverflow, I have not enough reputation to include more than 2 links. However, I need to include far more than 2 links in order my question to be complete and understandable. That is why I have written down all the references in question in the folowing Gist . Later, each time you see [XXX], it refers to the corresponding link in the previously mentioned Gist.

Let's tackle the question itself: I am facing a compilation issue involving the glibc.

In a few words, as part of my course, I have the opportunity to study computer security. Notably, I have to study in depth some CVE. I chose to look into [GHOST - CVE-2015-0235]: a buffer overflow in the GetHOSTbyxxx functions which allows remote code execution.

In order to do so, I want to try to reproduce [Qualys exploit]. That is why I set up an a Docker environment, based on the latest LTS Ubuntu distribution (16.04), in which I want to compile a vulnerable version of the [glibc] (2.17) and a vulnerable version of the [Exim mail server] (4.77) - this is the software which is exploited in Qualys exploit.

The first step is to download, compile and install (in /usr/local/lib) the glibc. So far, so good.

In order to verify that I can compile some code with gcc linking to this version of the glibc, I compiled the [GHOST vulnerability check] supplied by Qualys, thanks to the following command (inspired from those two answers from StackOverflow: [1] and [2]):

gcc vulnerability_check.c -o vulnerability_check \
    -Wl,--rpath=/usr/local/lib \
    -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2

No problem at all. Thus, I tried to compile the Exim Mail Server linking to the vulnerable version of the glibc. According to the documentation associated with the Exim mail server, compilation flags can be added by appending the following line to Local/Makefile (which has to be created by the user, from src/EDITME):

CFLAGS="-Wl,--rpath=/usr/local/lib -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2"

However, I am facing some "undefined reference" errors:

/usr/local/lib/libpthread.so.0: undefined reference to `h_errno@GLIBC_PRIVATE'
/usr/local/lib/libpthread.so.0: undefined reference to `__vdso_clock_gettime@GLIBC_PRIVATE'
collect2: error: ld returned 1 exit status
Makefile:517: recipe for target 'eximon.bin' failed

As I understand it, it means that some of the symbols (h_errno and clock_gettime) used in the source code of "eximon", normally defined in shared static libraries, are not found in the version of the glibc I compiled. Just to be sure they really are not defined, I added dummy calls to those two symbols in the [GHOST vulnerability check] code, and compiled it. No problem at all.

I am not sure what to do next to keep tracking the stem of the problem. I have been looking for means to analyse the content of the static libraries compiled along the glibc (nm seems to do the trick). I have tried looking into the depth of the documentation of the compilation toolchain, from gcc to ld. I also found about PatchELF, but I do not think it is what I need (no third-party library to modifu). However, I could not find neither the solution nor a workaround.

Thus, I would appreciate any piece of advice concerning the way to link Exim with the compiled glibc, the proper way of using the compilation toolchain, the proper method to solve such a compilation issue ; or any piece of advice you believe would make me a better programmer.

I thank you very much in advance.

In order to verify that I can compile some code with gcc linking to this version of the glibc,

You didn't compile and link code with this version of glibc.

I compiled the [GHOST vulnerability check] supplied by Qualys, thanks to the following command (inspired from those two answers from StackOverflow: [1] and [2]):

You appear to have lost references [1] and [2].

gcc vulnerability_check.c -o vulnerability_check \\ -Wl,--rpath=/usr/local/lib \\ -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2

Above command makes GCC use standard locations for include (ie /usr/include ) and lib (ie /usr/lib ), but arranges for the alternate version of GLIBC (the one from /usr/local ) to be used at runtime .

That is, there are 3 distinct steps:

  1. Compile sources using some headers
  2. Perform (static) link using some .o and .so files and
  3. Perform runtime linking/loading just before passing control to the application.

You've only arranged for step 3 to use your newly-built GLIBC.

To make use of newly-built GLIBC (assuming it was configured to install into /usr/local ), you should use something like:

gcc -o t -nostdlib -nostartfiles -I/usr/local/include \
  /usr/local/lib/crt1.o \
  /usr/local/lib/crti.o \
  $(gcc --print-file-name=crtbegin.o) \
  t.c \
  /usr/local/lib/libc.so.6 \
  /usr/local/lib/libc_nonshared.a \
  /usr/local/lib/ld-linux-x86-64.so.2 \
  $(gcc  --print-file-name=crtend.o) \
  /usr/local/lib/crtn.o \
  -Wl,--rpath=/usr/local/lib \
  -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2`

CFLAGS="-Wl,--rpath=/usr/local/lib -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2"

Above command is again wrong: it uses mismatched ld-linux.so and libc.so.6 at static link time (at step 2 above), and fails.

TL;DR: linking against non-standard GLIBC is complicated. You'll be much better off using a chroot environment or a virtual machine instead.

Update:

CFLAGS="-I/usr/local/include -Wl,--rpath=/usr/local/lib -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2"

Above setting makes little sense: the -Wl,... are linker flags, they belong in LDFLAGS .

LDFLAGS="-nostdlib -nostartfiles /usr/local/lib/crt1.o /usr/local/lib/crti.o $(gcc --print-file-name=crtbegin.o) /usr/local/lib/libc.so.6 /usr/local/lib/libc_nonshared.a /usr/local/lib/ld-linux-x86-64.so.2 $(gcc --print-file-name=crtend.o) /usr/local/lib/crtn.o"
... Anything wrong ?

Yes. Note that the order of crti.o , your objects/sources, libc.so.6 , and crtn.o matters a great deal, and must be exactly the order I showed.

I don't believe there is any way to achieve such order by specifying it in LDFLAGS . You'll need to either execute the command line by hand, or heavily modify Makefile for the program you are building.

You really are better off doing this in a chroot or a VM.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM