Live data from Hacker News

Compiler Options Hardening Guide for C and C++

best.openssf.org

1–10 of 72 posts

Re: Compiler Options Hardening Guide for C and C++

#2
> Developers should additionally use -Werror

I've yet to be convinced that this makes sense for every warning. It really depends on the warning IMO.

Edit to elaborate:

I was mostly referring to non-committed/non-release code not deserving -Werror [1]. However, even for release builds, the story kind of depends on whether your builds are hermetic or not. If your commit also includes a snapshot of all your dependencies including your compiler toolchain executables, then off the top of my head, I can't think of any cases where you want warnings without errors (though perhaps there might be some). But if you're ever going to compile the same commit with a different toolchain (like say your system toolchain that you updated), then I don't think you want -Werror, otherwise every time the warning catches a new case, you'll fail to build something that previously compiled fine.

[1] https://news.ycombinator.com/item?id=38481255

Re: Compiler Options Hardening Guide for C and C++

#4
Every compiler flag indicates a place where somebody failed.

Those are either compiler implementators, language or standard designers, or all of them.

>When compiling C or C++ code on compilers such as GCC and clang, turn on these flags for detecting vulnerabilities at compile time and enable run-time protection mechanisms:

>-O2 -Wall -Wformat=2 -Wconversion -Wtrampolines -Wimplicit-fallthrough \ >-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 \ >-D_GLIBCXX_ASSERTIONS \ >-fstrict-flex-arrays=3 \ >-fstack-clash-protection -fstack-protector-strong \ >-Wl,-z,nodlopen -Wl,-z,noexecstack \ >-Wl,-z,relro -Wl,-z,now

Christ.

Re: Compiler Options Hardening Guide for C and C++

#5
Not mentioned in this doc, I like using `-fsanitize=safe-stack` in release builds. Accesses to stack allocated arrays which have non-safe offsets (compiler fails to prove all accesses are in bounds) cause the object to be allocated on the unsafe stack, elsewhere in memory where overruns can only touch other things on the unsafe stack. Provably in-bounds accessed variables, return addresses, compiler generated spill slots, etc., go on the safe stack. This has such a small performance impact, you'll measure improvement and slowdown in equal measure just because of the uncontrolled effects this has on memory layout. The main downside is that presently you can't enable it when building a shared object. Docs: https://clang.llvm.org/docs/SafeStack.html

Also! While the usual sanitizer runtime libraries aren't security hardened for use in production environments, but for UBSan there's -fsanitize-minimal-runtime which switches to a different runtime library that is intended for this purpose (or use -fsanitize-trap=... instead, which executes an illegal instruction on error). Note that if your program terminates with a UBSan error, an attacker who can check whether your program terminated or not could use that as a primitive to leak data, so consider the security impact on your use case carefully. UBSan has a quite small performance impact when building with optimization, so you could deploy to production with it enabled, or parts of it enabled.

Re: Compiler Options Hardening Guide for C and C++

#6
post #2

> Developers should additionally use -Werror I've yet to be convinced that this makes sense for every warning. It really depends on the warning IMO. Edit to elaborate: I was mostly referring to non-committed/non-release code not deserving -Werror [1]. However, even for release builds, the story kind of depends on whether your builds are hermetic or not. If your commit also includes a snapshot of all your dependencies…

Why, what’s the alternative - leave the warnings hanging around? I work on a multi million loc.C++ codebase that used -Werror. If we turned it off, the codebase would be full of warnings in hours.

Re: Compiler Options Hardening Guide for C and C++

#7
post #2

> Developers should additionally use -Werror I've yet to be convinced that this makes sense for every warning. It really depends on the warning IMO. Edit to elaborate: I was mostly referring to non-committed/non-release code not deserving -Werror [1]. However, even for release builds, the story kind of depends on whether your builds are hermetic or not. If your commit also includes a snapshot of all your dependencies…

It definitely does for C/C++. I think there are two reasons:

1. C/C++ build systems tend to be super noisy printing every file that they compile, often long commands and usually in an ugly style, so it is very easy to just miss warnings or to give up even trying to look for them because the output is so verbose.

2. C/C++ tend to produce a lot of warnings that are very annoying to resolve properly and usually not worth the effort. Sign and size conversion warnings are probably the worst. They're low information warnings that usually don't have a clear solution, so people learn to just accept that some warnings should be ignored and they stop trying to fix warnings in general.

3. It's usually difficult to prevent warnings from third party code from being shown and you can't do much about those. There is `-isystem` but it's not well supported and it doesn't solve everything.

I think Go got rid of warnings entirely because of how bad the warning experience in C/C++. But my experience of Rust has shown that warnings can be done sensibly so I wouldn't use `-Werror` in Rust.

In C++ though, you should use `-Werror` in CI and then whitelist specific warnings. Just don't enable it for downstream users.

Re: Compiler Options Hardening Guide for C and C++

#8

Every compiler flag indicates a place where somebody failed. Those are either compiler implementators, language or standard designers, or all of them. >When compiling C or C++ code on compilers such as GCC and clang, turn on these flags for detecting vulnerabilities at compile time and enable run-time protection mechanisms: >-O2 -Wall -Wformat=2 -Wconversion -Wtrampolines -Wimplicit-fallthrough \ >-U_FORTIFY_SOURCE -…

No, it is just respect for backwards compatibility.

Though, what might be nice is a shortcut or set of shortcuts for various recommendations e.g. -fopenssf-recommendation or something (and then you can override the parts you don't want afterwards). You could call it -fsafer but that might be too complicated to get everyone to agree on what it means...

Re: Compiler Options Hardening Guide for C and C++

#9

Every compiler flag indicates a place where somebody failed. Those are either compiler implementators, language or standard designers, or all of them. >When compiling C or C++ code on compilers such as GCC and clang, turn on these flags for detecting vulnerabilities at compile time and enable run-time protection mechanisms: >-O2 -Wall -Wformat=2 -Wconversion -Wtrampolines -Wimplicit-fallthrough \ >-U_FORTIFY_SOURCE -…

This kind of disdain really should be put to rest. All it does is alienate people that were on the fence, or maintain projects with different goals in mind.

And besides, we'll be making similar comments about more your favorite recent languages once they're 38 years old and the field of computing changes. And if you don't believe so, you're in for a very rude awakening.

I can already see the replies that refuse to understand this point.

Re: Compiler Options Hardening Guide for C and C++

#10

Every compiler flag indicates a place where somebody failed. Those are either compiler implementators, language or standard designers, or all of them. >When compiling C or C++ code on compilers such as GCC and clang, turn on these flags for detecting vulnerabilities at compile time and enable run-time protection mechanisms: >-O2 -Wall -Wformat=2 -Wconversion -Wtrampolines -Wimplicit-fallthrough \ >-U_FORTIFY_SOURCE -…

It's a sign that the compiler devs value backward compatibility with earlier incarnations that lacked such programmer aids. These are features that come with an associated cost and you don't pay that price in C without explicitly choosing it.
Post reply on HN