Member of Information Superhighway

Upgrading GNU libc on older Linux distributions

Have you ever needed to run an application or load a library that requires a newer version of glibc?

If so, you may have seen an error like this:

/lib64/libc.so.6: version `GLIBC_2.14` not found

To check what version of glibc is installed use:

  1. ldd --version
  2. You’ll get a response like ldd (GNU libc) 2.12.

In our case, we were running an older version of Linux (CentOS/RHEL 6.x) and attempting to use a C library that only supported glibc 2.14 or higher.

Normally, the correct choice would be to either:

  1. Rebuild the library from source using the version of glibc on your OS
  2. Upgrade your OS to a newer version that includes the newer glibc

In our case, we could do neither, so we needed another solution.

Building glibc

If you take a look around, you’ll find that you can build a newer version of glibc. Here’s some instructions for doing a side-by-side installation of glibc 2.14 from Stack Overflow:

mkdir ~/glibc_install; cd ~/glibc_install
wget http://ftp.gnu.org/gnu/glibc/glibc-2.14.tar.gz
tar zxvf glibc-2.14.tar.gz
cd glibc-2.14
mkdir build
cd build
../configure --prefix=/opt/glibc-2.14
make -j4
sudo make install

This will install glibc into /opt/glibc-2.14 but if you run ldd --version it will still report the old version. So how do you get your application to use the new version?

Using the new glibc

You might find advice that suggests using LD_LIBRARY_PATH (ex: LD_LIBRARY_PATH=/opt/glibc-2.14/lib), but I’ve found that this can cause problems.

When you specify the LD_LIBRARY_PATH you are giving your system an additional path on your system to look for libraries that it dynamically loads. However, the lib folder contains many other libraries that could be loaded. This can cause things like unexpected segfaults. In our case, the application only needs to load libc.so.6.

So what can you do instead? If you use LD_PRELOAD, you can tell your application to load functions from a given file instead of the locations it would normally load from.

If we had an executable called app, we could run it while prepending LD_PRELOAD as an environment variable:

LD_PRELOAD=/opt/glibc-2.14/lib/libc.so.6 ./app

When the application attempts to make libc function calls the LD_PRELOAD variable will force the application to use the ones stored in the new libc.so.6 file.

In our case, this allowed our application to run using the newer version of glibc.

Syncing the glibc timezone

After running our application with the new glibc, we found the timezone was wrong.

This is because the glibc you install has its own localtime file. You can resolve this by linking the system’s localtime file to the one that the new glibc will use:

ln -sf /etc/localtime /opt/glibc-2.14/etc/localtime

Learn more

If you’d like to learn more about LD_PRELOAD, there’s a great blog post by Rafal Cieslak demonstrating how to use it to overwrite functions in C programs.

In it, they force a binary to use a rand() function that’s injected by LD_PRELOAD.