tl;dr version: If you have a security-sensitive package, and wish to enable some gcc-level hardening features with a modest performance impact, you will soon be able to enable them (nearly) automagically by rebuilding with this line in your spec file: %define _hardened_build 1 Now for the details. * 1: what are we trying to do? There are three somewhat-overlapping build features in play here. The first one is called "relro", which instructs the linker to emit some relocations in a special segment that can be marked read-only after relocation processing is finished but before you call into main(). Or in English: more things that you've asked to be const, will actually be const. This on its own is quite cheap, and so it has been enabled globally as of redhat-rpm-config-9.1.0-13.fc16. By default, not all symbols are resolved that early in program execution. In particular, functions are resolved lazily the first time they're called. This makes startup faster, and since not all functions are actually called in typical program execution, usually makes total execution time faster. However, if all symbols were resolved early, the relro feature could do a better job, and virtually all relocations could be made read-only. The '-z now' flag to the linker makes this happen, and an app so linked is said to be "Full RELRO" instead of "Partial RELRO". Finally, applications may be built as position-independent executables, by passing -fPIC or -fPIE at build time and -pie at link time. This allows the runtime linker to randomize the placement of the executable at runtime, which makes it more difficult for an attacker to guess the address of writeable memory. * 2: how do we go about doing it? The non-PIE parts of this are trivial, just pass the appropriate flags to the linker and you're done. PIE is more difficult, both at build time and at link time. Although both -fPIC and -fPIE produce position-independent code at the assembly level, -fPIE will (at least on amd64) produce relocation types that are only valid in an executable. This means you can't just say -fPIE in CFLAGS: your libraries will fail to link. (PIC objects in a PIE executable are fine; PIE objects in a PIC library are not. When in doubt, -fPIC.) Likewise, at link time, the -pie and -shared options are mutually exclusive. ld.gold will simply refuse to execute if you specify both. ld.bfd will (afaict) let whichever one comes last win, and if that happens to be -pie when you're building a shared library it will fail to link because it won't be able to find a _start symbol. All of this is only an issue because most build systems don't let you say different CFLAGS or LDFLAGS for shared libraries and executables. Sigh. So instead, we'll teach gcc to figure it out. To do this we'll use the -specs flag to pass some rewrite rules to the compiler driver. At compile time, if we don't see -fPIC or -fPIE on the command line, we'll add -fPIC. At link time, if we don't see -shared, we'll add -pie. This way we build relocatable objects that are always suitable for either type of final link object, and we'll only attempt to build a PIE if we know we're not building a shared library. Victory! * 3: what does this mean for you? The link-time bit of the last paragraph required a bit of gcc magic to get right (previously specs rules could only add strings to the command line of the program to invoke; they could not rewrite gcc's notion of which flags had been passed in the first place). Thanks to a patch from Jakub Jelinek, this is now fixed in gcc-4.6.1-7.fc16, and will be in gcc 4.7 and later. As a result, %defined _hardened_build 1 will not work until that gcc update has gone through. Once that's done (and redhat-rpm-config-9.1.0-15.fc16 has been gone through updates), if you're using a %configure-style spec file, defining the magic macro is all you have to do. The rpm macros will notice the macro, and put the right magic into CFLAGS and LDFLAGS, and everything is great and wonderful. If you're _not_ using %configure, then you have to do whatever is conventional for your build system to get CFLAGS and LDFLAGS inherited properly. For CFLAGS, this will be $RPM_OPT_FLAGS or %{optflags} as before. As of rpm-4.9.1-3.fc16, you will be able to say $RPM_LD_FLAGS for the corresponding LDFLAGS values. Until then, there is no such shell variable, but you can get the same effect from %{?__global_ldflags}. Yes, that's ugly, sorry. If you are the owner of one of the packages listed here: https://fedoraproject.org/wiki/User:Kevin/DRAFT_When_to_use_PIE_compiler_flags Then I have locally built (though not extensively tested) your package with the appropriate specfile modifications, and the results do indeed appear to be fully hardened. If you would like to handle the rebuilds yourself, please let me know. Otherwise I will submit them myself once the relevant updates have gone through. If you've made it to the end, congratulations. Please let me know if there are any issues, or any questions I can answer. In particular if the performance impact of these flags is excessive for you, there are some ways it can be mitigated that are out of scope for this particular email. - ajax -- devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxxx https://admin.fedoraproject.org/mailman/listinfo/devel