Default setting for CLANG_DEFAULT_PIE_ON_LINUX

Hi everyone,

Recently @MaskRay committed a patch (⚙ D120305 [Driver] Default CLANG_DEFAULT_PIE_ON_LINUX to ON) to change the default value for CLANG_DEFAULT_PIE_ON_LINUX to “ON”. This caused some test failures in a couple of downstream projects I work on. While it’s easy enough for these projects to explicitly keep the old default value (for now, at least), it seems like a change of this nature requires more discussion than just what happens in a typical code review.

This was previous brought up here (PIE/PIC Clang Defaults on Linux x86-64), but it doesn’t seem like a consensus was reached.

The change caused a number of buildbot failures, and while I believe these have all since been sorted out, I suspect they are indicative of the kinds of problems that users are going to encounter when this change reaches them. For anyone who was building clang without explicitly setting CLANG_DEFAULT_PIE_ON_LINUX, this change introduces potential compatibility issues with previously compiled object files and static libraries.

The motivation for the change seems to hinge on two points:

  1. Compatibility with GCC default behavior
  2. Consistency with major distribution of Linux

With regard to the first point, this is a bit ambiguous. GCC, like clang, controls its default through a configuration option used when building the compiler. If the option is not explicitly specified, it does not enable PIE by default. A change was proposed, but it seems not to have been accepted (103398 – configure: Enable --enable-default-pie by default for Linux).

However, the second point is strongly connected to the first. The claim (I haven’t investigated this extensively) is that many, perhaps most, major distributions do explicitly use the option to make PIE the default in the build of GCC that is part of the distribution. I’d like to see more data. I know there are distributions that are not using this default. I’d also like input from someone affiliated with any of the distributions that don’t use the new default.

I’m sympathetic to Fangrui’s argument that the mere existence of this option in GCC and clang leads to unnecessary confusion and inconsistency, but I’m not sure that the recent change does much to help eliminate that problem and may, in fact, make it worse.

Finally, I’m concerned by this statement in the description of the change: “Note: CLANG_DEFAULT_PIE_ON_LINUX will be removed in the future.” That would make it more difficult for my downstream projects to maintain their current behavior.

Hi Andy, so you can see that linux-musl and linux-android triples use default PIE even with -DCLANG_DEFAULT_PIE_ON_LINUX=off.
(Android and all musl distributions I know do use default PIE.)
For linux-gnu systems, Arch Linux, Debian, Fedora, Gentoo, OpenSuse, Ubuntu, etc have been using default PIE for many years now.
Note that there had been several atempts before me adding a patch to enable default PIE for their Clang distributions.
I currently think of at least Arch Linux and Gentoo, and vaguely remember folks referencing the patches in various places.
There had also been numerous reports about why Clang did not use PIE as GCC does.

I’d also like input from someone affiliated with any of the distributions that don’t use the new default.

I cannot name a distribution that doesn’t use default PIE. I’d like to know if this even exists:)
The current ubuiquitous PIE in the Linux world is largely credited to security hardening practices accepted by most groups.
Traditionally the GNU toolchain behaviors largely define what a Linux system works.
Not making some changes here can harm the adoption of Clang on such systems.
I can imagine that many packages just assumed default PIE on Linux systems and therefore Clang’s default-to-no-pie would make Clang not a drop-in replacement.
So I went ahead and contributed the change. I feel sympathy to the groups that need time for migration, therefore CLANG_DEFAULT_PIE_ON_LINUX was added as a first step to make the transition easy.

  • Compatibility with GCC default behavior

103398 – configure: Enable --enable-default-pie by default for Linux (“configure: Enable --enable-default-pie by default for Linux”) rejection by one GCC developer was unfortunate. This is really one configuration that the upstream GCC repository default has deviated from the ubiquitous state.
I’d hope the developer or others would revisit the issue considering the practice in the Linux world.

Finally, I’m concerned by this statement in the description of the change: “Note: CLANG_DEFAULT_PIE_ON_LINUX will be removed in the future.” That would make it more difficult for my downstream projects to maintain their current behavior.

The relanded version changed the word from the descritpion (not reflected on the differential summary yet)
“Note: CLANG_DEFAULT_PIE_ON_LINUX /may/ be removed in the future”.

I also have a user which needs to use CLANG_DEFAULT_PIE_ON_LINUX for a period of time,
but I think every configurable option partitions the user community a bit and the vendor differences likely cause more problems to both users and developers.
If indeed folks can all migrate to CLANG_DEFAULT_PIE_ON_LINUX=on, I don’t see a need to retain the CLANG_DEFAULT_PIE_ON_LINUX toggle forever.

However, the second point is strongly connected to the first. The claim (I haven’t investigated this extensively) is that many, perhaps most, major distributions do explicitly use the option to make PIE the default in the build of GCC that is part of the distribution. I’d like to see more data. I know there are distributions that are not using this default. I’d also like input from someone affiliated with any of the distributions that don’t use the new default.

I did some research to provide some data for you.

Speaking as a distribution person (Gentoo), the lack of a default-PIE option for Clang has been a pain when trying to experiment with an LLVM-based toolchain, as forcing via compiler-flags (as Fedora, and I think Fedora only) does is more fragile.

I’m not extremely attached to the default being on, given the same distributions which turn it on downstream for GCC could do the same for LLVM, but I also don’t have a strong reason against it. I feel like GCC should have (and still should!) do the same for reasonable targets.

There’s already sufficient variation in distributions’ toolchains that if one needs to disable PIE, the appropriate options must be passed anyway. So, in that sense, the default being on isn’t really problematic.

I would generally not be surprised if a compiler enabled PIE by default when I install an arbitrary distribution. I wouldn’t be shocked if it was off, but I generally expect it to be on. The point being, people already need to explicitly state what they need anyway to work cross-distribution.

FWIW, users were often confused in Gentoo when they were told that using Clang didn’t come with the same hardening defaults we provided with GCC.

Note that distributions typically enable GCC’s SSP by default option too (and patch in default -D_FORTIFY_SOURCE=2). But that’s a topic for another day.

This is a step forward for better hardened binaries and at pretty low cost. IMO, it’s worth it.

Finally, I’m concerned by this statement in the description of the change: “Note: CLANG_DEFAULT_PIE_ON_LINUX will be removed in the future.” That would make it more difficult for my downstream projects to maintain their current behavior.

I agree the toggle’s description is a bit confusing. When I read it, I was worried it might go away, rather than become always-on.

I don’t generally get my fingers into the details of distributions, so I may be totally uninformed here. What I can tell you is that the system I use for daily development doesn’t seem to have been configured that way. Here’s what it tells me:

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/8/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-redhat-linux
Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,fortran,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl --disable-libmpx --enable-offload-targets=nvptx-none --without-cuda-driver --enable-gnu-indirect-function --enable-cet --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
Thread model: posix
gcc version 8.3.1 20191121 (Red Hat 8.3.1-5) (GCC)

This is maintained by some support group in my company, so I don’t know what may have happened to it to get in this state. I can tell you this is /usr/bin/gcc. Maybe one of our Red Hat contributors can comment on whether I’ve just got an odd setup.

Your point about security hardening is compelling, and it may be worth suffering through some temporary user problems to get that. I just want to make sure we’ve properly considered the impact of the change.

There is an important distinction to make here between flags that distributions use to build their packages and flags that are enabled in the toolchain package shipped to users. As @thesamesam noted, Fedora uses -pie when compiling packages for the distribution, but if a user installs the gcc package it will not be part of the default flags.

@tstellar Do you have a preference as to what the clang default should be?

I don’t have a strong preference on what the default should be, but whatever it is, I don’t think it should be configurable with a CMake option. We should just pick a default and go with it.

1 Like