Project:Hardened uClibc

From Gentoo Wiki
Jump to:navigation Jump to:search
Hardened uClibc
Description This subproject aims to port both tool chain and kernel hardening to uClibc based systems for a variety of architectures. The project treats uClibc as an alternative to glibc, and not necessarily as "embedded". uClibc is no longer supported.
Project email
IRC channel #gentoo-hardened (webchat)
Last elected: 2019/08/27
(and inherited member(s))
Parent Project Hardened
Project listing
The information in this article is representative of former times and has been archived as of 2021-11-14. It can be used for reference, but is most likely not appropriate for current usage. Generally, archived articles should not be edited.
uClibc is not longer supported or packaged by Gentoo. Most users will probably want to use musl instead.

All modern operating systems are comprised of a kernel and userland layer. While the kernel deals directly with hardware resources at the highest privilege level, userland deals with the end user and operates at the lowest level. The two layers communicate with one another via system calls (or "syscalls" for short), which userland issues to the kernel. While any userland application can issue syscalls directly (eg. in x86 ISA, via an INT 0x80), almost all userland syscalls on a typical UNIX system are channeled via one central library referred to as the C standard library. Along with the compiler and other utilities to manipulate executable binaries (eg. binutils), it forms an integral part of the toolchain, and remains a runtime dependency of nearly every dynamically linking object in the system. By far, the most popular is "The GNU C library", or glibc for short; but, for embedded systems uClibc is the standard library of choice, although there are other competitors (see musl ). uClibc (where the "u" is sometimes written as the Greek µ for "micro") is much smaller than glibc, less bloated, much faster, and very configurable.

Continued developments in uClibc have made it increasingly suitable for systems like Lilblue, our security-enhanced, fully featured XFCE4 desktop, amd64 system built on uClibc. The recent addition of the native POSIX thread library (see nptl) meant that we could finally implement our complete complement of tool chain hardening from glibc:

  • Stack Smashing Protection (SSP), which came with nptl;
  • Position Independent Execution (PIE);
  • Bind now and relro, linker hardening to protect the global offset table

These are augmented by the kernel hardening, especially PaX's enhanced Address Space Layout Randomization (ASLR).

So, this sub-project aims to port both tool chain and kernel hardening to uClibc based systems for a variety of architectures, treating uClibc more as a drop in alternative to glibc, and not necessarily as "embedded". Embedded systems aim to produce kernels and user lands with tiny footprints, and so tend to use busybox as their "Swiss Army Knife" of common UNIX utilities. While not excluding this possibility, we aim at making most (all?) of Gentoo's packages both hardened and uClibc compatible.

Migration to uClibc-ng

At the time of this writing, September 2016, uClibc has not pushed out a release since May 2012 and has not committed a change since June 2015. For all intents and purposes, it is a dead project. However, the codebase has been forked and a new project uClibc-ng is being actively maintained. So, on Oct 1, 2016, we will be migrating over all stage3’s to uClibc-ng. For users starting from fresh, you should not notice any changes. But for users who have production systems running uClibc, you will have to migrate over. Unfortunately, there is no simple migration path, but the following mini HOWTO should work. It is recommended that you back up everything before proceeding and be prepared to boot into a rescue environment where you can chroot into your system to do repairs should something go wrong.

Before you begin, make sure your /etc/portage/savedconf/sys-libs/uclibc-ng file is to your liking, or make sure the correct USE flags are enabled. The config file provided in the stage3’s and on the releng overlay for your architecture should work. For example, for hardened amd64, you can use this config. In particular, if UCLIBC_HAS_OBSTACK is off when upgrading, you can expect catastrophic failure!

First build sys-libs/uclibc-ng, and install it in /var/tmp/sys-libs/uclibc-ng/image, but don’t merge it onto the root file system. Both sys-libs/uclibc and uclibc-ng hard block one another, so you can't just emerge uclibc-ng. Even if you could, it would break your system since portage removes sys-libs/uclibc from the system completely before it installs sys-libs/uclibc-ng. This is not an atomic operation, so as soon as uclibc is off, every ELF object linking against breaks. So we will be merging the package onto the root file system manually:

Build sys-libs/uclibc-ng:

root #cd /usr/portage/sys-libs/uclibc-ng
root #ebuild uclibc-ng-1.0.17.ebuild clean install

Make a copy of /lib in case we need to restore the system:

root #cd /
root #cp -a /lib /lib.bak

Next carefully move all the contents of /var/tmp/portage/sys-libs/uclibc-ng/image/lib to /lib. You probably could do a direct copy from /var/tmp/portage/sys-libs/uclibc-ng/image/lib, but it might be a good idea use a copy on the same filesystem as /lib, in case you have NFS running or something. The mv needs to be an atomic operation, or at least near atomic. Be careful with this step because this is where you might break your system!

root #cp -a /var/tmp/portage/sys-libs/uclibc-ng/image/lib /
root #mv /* /lib

Now let’s make sure that when we copied the files over from / we clobbered the old sym links and that they are pointing to the correct files.

Check sym links:

root #ls -al /lib/

You should find that /lib/ ->, or whatever version of sys-libs/uclibc-ng you’re working with. If it still ponits to a version like, then you're still using the old uclibc .so's.

At this point, we can clean out /lib of the old uclibc files. We’ll move them out of the way rather than delete them, just in case we might need them again.

root #mkdir /root/oldlibc
root #mv /lib/** /root/oldlibc

Congratulations, your system has been converted to sys-libs/uclibc-ng, but portage still thinks you have sys-libs/uclibc installed. We have to manually delete portage’s records of uclibc and emerge sys-libs/uclibc-ng at least once, although twice is better.

Update portage to record sys-libs/uclibc-ng in /var/db:

root #rm -rf /var/db/pkg/sys-libs/uclibc-
root #emerge uclibc-ng

The first time you emerge, you’ll get a bunch of file collisions reported by portage. These are the files you put on the file system when you copied over your libraries from / above. They are harmless and portage will overwrite those files with the same files again. The second emerge should go smoothly. Again, you could skip that step, but it doesn’t hurt as a check that emerging uclibc-ng now works smoothly.

You're done, and you should be able to continue working with uclibc-ng as your libc provider. Although it shouldn't happen, you might find that something wants to pull in uclibc instead of uclibc-ng. If so, just hard mask uclibc in /etc/portage/package.mask.

Upgrade to =sys-libs/uclibc-ng-1.0.22

There have been two major changes in uclibc-ng which need special attention in upgrading. Version 1.0.19 restructured the breakout libraries,,, and friends. The functions in those libraries are now included in Version 1.0.21 and above removed libc support for obstack, expecting packages to use their bundled GNU lib code. Both changes require special upgrade procedures which we outline below:

0. Because of changes in the library structure in previous versions, make sure you are working with 1.0.19 and rebuild world using:

root #emerge -evq @world

This will make sure all executables link directly against (as reported by readelf -d) rather than via symlinks like -> Then upgrade from 1.0.19 to 1.0.20 without symlink-combat:

root #USE="-symlink-compat" emerge =sys-libs/uclibc-ng-1.0.20

1. Get rid of the obstack.h header since its used by configure scripts to look for function prototypes and macros:

root #mv /usr/include/obstack.h ~

2. We also need to force the use of any bundled gnu lib code. We can do this by removing the definition of _GNU_OBSTACK_INTERFACE_VERSION from gnu-version.h

root #cp /usr/include/gnu-versions.h ~
root #sed -i -e '/#define _GNU_OBSTACK/d' /usr/include/gnu-versions.h

3. We need to tell stdio.h that __UCLIBC_HAS_OBSTACK__ is false. We do this via the uClibc_config.h file.

root #cp /usr/include/bits/uClibc_config.h ~
root #sed -i -e '/__UCLIBC_HAS_OBSTACK__/ s/1/0/' /usr/include/bits/uClibc_config.h

4. To be safe, you may want to back up your entire /lib directory so you can fall back should something go wrong:

root #cp -a /lib /lib.bak

5. Now when we rebuild @world, all packages will use their bundled obstack code rather than depending on libc to provide it.

root #ac_cv_func_obstack_vprintf=no emerge --keep-going --exclude sys-libs/uclibc-ng -evq @world

6. Finally updated uclibc-ng to the latest:

root #emerge =sys-libs/uclibc-ng-1.0.22

7. For good measure, rebuild the entire system:

root #emerge —evq @world


The project goals can be best summarized by the following chart:

Arch Subarchs Tool Chain Hardening Kernel Hardening Status Downloads
amd64 Generic Yes Yes Stable Desktop stage3-amd64-uclibc-{hardened,vanilla}
arm armv7a-softfp Yes No Development stage3-armv7a-uclibc-{hardened,vanilla}
arm armv7a-hardfp Yes No Development stage3-armv7a_hardfp-uclibc-{hardened,vanilla}
mips mips32r2 Yes No Development stage3-mips32r2-uclibc-{hardened,vanilla}
mips mipsel3 Yes No Development stage3-mipsel3-uclibc-{hardened,vanilla}
ppc classic No No Development stage3-ppc-uclibc-vanilla
x86 i686 Yes Yes Stable stage3-i686-uclibc-{hardened,vanilla}


To participate in the Hardened uClibc project join the mailing list at and visit our online IRC channel at #gentoo-hardened (webchat) on Libera.Chat.

See also

  • Lilblue - A hardened uClibc XFCE desktop.