69

What set of GCC options provide the best protection against memory corruption vulnerabilities such as Buffer Overflows, and Dangling Pointers? Does GCC provide any type of ROP chain mitigation? Are there performance concerns or other issues that would prevent this GCC option from being on a mission critical application?

I am looking at the Debian Hardening Guide as well as GCC Mudflap. Here are the following configurations I am considering:

-D_FORTIFY_SOURCE=2
-fstack-protector --param ssp-buffer-size=4
-fPIE -pie
-Wl,-z,relro,-z,now (ld -z relro and ld -z now)

Are there any improvments that can be made to this set of options?

We are most worried about protecting WebKit.

rook
  • 47,004
  • 10
  • 94
  • 182
  • 4
    `gcc -x ada`. Seriously, if you don't want exploitable programs, start by using a programming language that doesn't go out of its way to let programmers write exploitable code. – Gilles 'SO- stop being evil' Nov 25 '12 at 19:28
  • 16
    @Gilles cool let me know when they write a browser in ada. – rook Nov 25 '12 at 19:38
  • There was a Web browser written in Objective Caml, but the project has stalled more than ten years ago (thus not usable in practice): http://pauillac.inria.fr/mmm/ – Thomas Pornin Nov 29 '12 at 16:43
  • There is also [Lobo](http://lobobrowser.org/java-browser.jsp) which is more recent, and in Java. – Thomas Pornin Nov 29 '12 at 16:46
  • 2
    The mozilla community is working on a Browser Engine written in Rust, that should provide a much better security level than C. (Although, I admit I cannot compare it to ADA, as I don't know anything about ADA.) – MarkusSchaber Jun 04 '16 at 17:38
  • @MarkusSchaber That's the Servo engine, but the cynical part of me wonders if it's vaporware. – forest Dec 28 '18 at 05:13
  • @forest As far as I could google, the CSS engine for the web sites is in Rust since Firefox 57, and also used for the UI since Firefox 60. – MarkusSchaber Jan 15 '19 at 16:00

2 Answers2

64

I don't code for gcc, so hopefully someone else can add to this, or correct me. I'll edit it with responses. Some of these will not work for all circumstances.

  • -Wall -Wextra
    Turn on all warnings to help ensure the underlying code is secure.

  • -Wconversion -Wsign-conversion
    Warn on unsign/sign conversion.

  • -Wformat­-security
    Warn about uses of format functions that represent possible security problems.

  • -Werror
    Turns all warnings into errors.

  • -arch x86_64
    Compile for 64-bit to take max advantage of address space (important for ASLR; more virtual address space to chose from when randomising layout).

  • -mmitigate-rop
    Attempt to compile code without unintended return addresses, making ROP just a little harder.

  • -mindirect-branch=thunk -mfunction-return=thunk
    Enables retpoline (return trampolines) to mitigate some variants of Spectre V2. The second flag is necessary on Skylake+ due to the fact that the branch target buffer is vulnerable.

  • -fstack-protector-all -Wstack-protector --param ssp-buffer-size=4
    Your choice of "-fstack-protector" does not protect all functions (see comments). You need -fstack-protector-all to guarantee guards are applied to all functions, although this will likely incur a performance penalty. Consider -fstack-protector-strong as a middle ground.
    The -Wstack-protector flag here gives warnings for any functions that aren't going to get protected.

  • -fstack-clash-protection
    Defeats a class of attacks called stack clashing.

  • -pie -fPIE
    Required to obtain the full security benefits of ASLR.

  • -ftrapv
    Generates traps for signed overflow (currently bugged in gcc, and may interfere with UBSAN).

  • -­D_FORTIFY_SOURCE=2
    Buffer overflow checks. See also difference between =2 and =1.

  • ­-Wl,-z,relro,-z,now
    RELRO (read-only relocation). The options relro & now specified together are known as "Full RELRO". You can specify "Partial RELRO" by omitting the now flag. RELRO marks various ELF memory sections read­only (E.g. the GOT).

  • -Wl,-z,noexecstack
    Non-executable stack. This option marks the stack non-executable, probably incompatible with a lot of code but provides a lot of security against any possible code execution. (https://www.win.tue.nl/~aeb/linux/hh/protection.html)
  • -fvtable-verify=[std|preinit|none]
    Vtable pointer verification. It enables verification at run time, for every virtual call, that the vtable pointer through which the call is made is valid for the type of the object, and has not been corrupted or overwritten. If an invalid vtable pointer is detected at run time, an error is reported and execution of the program is immediately halted.(https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html)
  • -fcf-protection=[full|branch|return|none]
    Enable code instrumentation of control-flow transfers to increase program security by checking that target addresses of control-flow transfer instructions (such as indirect function call, function return, indirect jump) are valid. Only available on x86(_64) with Intel's CET. (https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html)

If compiling on Windows, please Visual Studio instead of GCC, as some protections for Windows (ex. SEHOP) are not part of GCC, but if you must use GCC:

  • -Wl,dynamicbase
    Tell linker to use ASLR protection.
  • -Wl,nxcompat
    Tell linker to use DEP protection.
forest
  • 65,613
  • 20
  • 208
  • 262
0xdabbad00
  • 1,075
  • 7
  • 5
  • 1
    enabling warnings doesn't help prevent the compromise of a running system. Also, without `-fstack-protector-all` canary's are only added to functions that may incur a stack based overflow that contain an array larger than 4 bytes (as per `ssp-buffer-size=4 `). Not every function needs to be protected by a canary, that is just a waste. Also I am on a 32bit system... So this post hasn't changed my build options. – rook Dec 02 '12 at 19:39
  • @Rook He's using `-Werror`, so the warnings become errors. He can't compile it, unless he's fixing the source. – sfx Dec 03 '12 at 18:38
  • @sfx "he" is me, and "the source" is webkit. – rook Dec 03 '12 at 18:39
  • Well maybe add some information about glibc 2.5 protections and anything else you can think of, and I'll awarded it. – rook Dec 05 '12 at 20:29
  • -ftrapv options doesn't work, there is a BUG in GCC never fixed. – boos Feb 25 '14 at 14:54
  • Nice answer. I tried to add explanation links for the more obscure options (`-z relro` & `-z now`). Can you explain why `arch x86_64` is "important for" ASLR? 32bit apps can have ASLR. – RJFalconer Mar 03 '14 at 12:41
  • 1
    @RJFalconer Compiling as X86_64 gives the application a lot more virtual address space. The ASLR is then more effective, since there is more addresses to choose from when randomizing. – user7610 Apr 25 '14 at 20:33
  • 2
    Apparently, with Windows 8 and [HiASLR](http://security.stackexchange.com/q/23638/971), you might also want to specify `-Wl,highentropyva` in addition to `-Wl,dynamicbase` to ensure you get the full benefits of HiASLR (high-entropy ASLR). I can't tell if/when this flag is actually needed, though. Mentioning this as a public service to others who may stumble across this. – D.W. Jun 04 '14 at 18:34
  • FYI, regarding MS VC++, [dynamic base](https://msdn.microsoft.com/en-us/library/bb384887.aspx) and [nxcompat](https://msdn.microsoft.com/en-us/library/ms235442.aspx) as well as [high entropy for 64bit targets](https://msdn.microsoft.com/en-us/library/jj835761.aspx) are ON by default. – mlt Dec 07 '15 at 02:53
  • What about -Wformat-nonliteral (yes, it's a pain) – Adam Shostack Sep 06 '16 at 17:54
  • 1
    If you're using clang don't forget about [CFI!](https://clang.llvm.org/docs/ControlFlowIntegrity.html) – Aaron Sep 21 '17 at 18:20
  • Be aware that `-ftrapv` (and `-fwrapv`) will interfere with UBSAN integer overflow detection, if you have it enabled. Speaking of which, UBSAN set to kill (with `-fsanitize-undefined-trap-on-error` on GCC) can improve code security a good bit, but a lot of code has so much UB that certain UBSAN features break many programs. I know that `-fsanitize=object-size` tends to work for pretty much everything, at least. – forest Mar 31 '18 at 07:34
  • I wonder if `-fstack-check` works now or if it's still broken as well... Last I checked it really screwed with memory and could add some nasty bugs to the code. – forest Mar 31 '18 at 07:40
  • @Aaron Be aware that CFI requires LTO, which makes some existing undefined behavior exploitable at higher optimization levels. The solution involves passing -O1 to the linker, but -O2 to the compiler. – forest Dec 28 '18 at 05:05
  • In GCC's case CFI requires Intel x86(_64) CPU with CET, I tried it on aarch64 and it refused to compile. – Avamander Mar 08 '19 at 11:10
  • @Avamander That's only for one specific kind of CFI. You can use other CFI techniques that do not require CET (though I think none are easy to get working with GCC. With Clang it's possible though) – forest Mar 09 '19 at 07:20
  • @forest This question is about GCC though – Avamander Mar 10 '19 at 20:11
  • 1
    @Avamander Sure, that's why I only mentioned this in a comment. You can get CFI working for GCC (without CET), but it's not _as easy_ and seamless as with Clang. – forest Mar 11 '19 at 10:43
4

Those are good options, but you need to pay attention to your own source code. Make sure to use secure function when dealing with user inputs, filter them and when you use something like strncpy(), try not to give a lot of space to prevent certain attacks. OS itself provides security i.e. DEP (NX), ASLR and canaries to protect the stack, but you can't rely on them all the time. So, yeah, above is my suggestion. I hope that helps you a bit and you can also use source code auditing tools. Good luck!

3ntr0py
  • 71
  • 2