Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request]: Add built-in option(s) to simplify hardening binaries #13024

Open
arun5309 opened this issue Mar 30, 2024 · 5 comments
Open

Comments

@arun5309
Copy link

Currently meson lacks built-in options for hardening binaries in a portable manner (across programming languages, across compilers, across OSes, across binary types, etc.). Adding such options would simplify creation of hardened binaries, which would complying with security practices (like https://best.openssf.org/Compiler-Hardening-Guides/Compiler-Options-Hardening-Guide-for-C-and-C++) easier.

Example project (template) with hardening options (based on a manual cmake configuration): https://github.com/cpp-best-practices/cmake_template.

Other potentially useful information: https://developers.redhat.com/articles/2022/09/17/gccs-new-fortification-level, https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html (hardening options here, run time checking options like stack-protector, etc.), https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#minimal-runtime, https://learn.microsoft.com/en-us/cpp/build/reference/guard-enable-control-flow-guard?view=msvc-170.

@dcbaker
Copy link
Member

dcbaker commented Apr 1, 2024

We have some options already available for this:

  • b_sanitize provides a way to turn on sanitizers, though there is some work to be done here, see this for example.
  • C++ stdlib assertions are turned on (in recent versions of Meson) whenever assertions themselves are turned on.
  • PIC and PIE are turned on by default (except where not supported), and must be opted out of

These can be combined into configuration file snippets for easier distribution:
echo hardened.ini

[constants]
c_cpp_args =  ['-D_FORTIFY_SOURCES=3', '-Wimplicit-fallthrough']

[built-in options]
werror = true
b_ndebug = false
b_sanitizer = 'address,undefined'
b_pic = true
b_pie = true
c_args = c_cpp_args
cpp_args = c_cpp_args

You can place these in well known places, and then reference them by meson setup builddir --native-file hardened.ini.

Does that meet your needs, or is there something more specific you'd like?

@arun5309
Copy link
Author

arun5309 commented Apr 2, 2024

Thank you for responding! I am aware that I could manually add options for hardening. But the issue with this approach is that it is not convenient, in particular as new hardening (or related) options get added to compiler I have to manually add it to the hardened.ini file. This also becomes tedious when testing with different compiler versions (as older compilers might not support newer options. Similar case can be made for different compilers (say gcc, msvc, clang), different languages, etc.). Even worse, what if I am not aware of certain new options or just forget to add a few hardening options.

One of the things I like about using meson is that it has nice defaults (uses ninja over make if present, uses sccache if present, support for reproducible builds out of the box, etc.). So, in the same spirit it would be nice to have a single option (or something similar) such when it is set all the (supported) hardening options get enabled (of course, with the capability to manually override when needed. Could also have different hardening levels for common use cases.). I think, this would make hardening easier to use even for users who are not necessarily familiar with the best practices for hardening, reduce duplicated efforts (say in maintaining hardened.ini file) across projects and make for a better developer experience overall.

I also won't mind if meson or some related tool generates the hardened.ini file automatically and provides the user to manually override it when needed.

@eli-schwartz
Copy link
Member

eli-schwartz commented Apr 2, 2024

Some of the suggestions in the OpenSSF article are pretty good. Some of them are terrible.

You should not be using e.g. -fno-strict-aliasing, because it tells the compiler to assume you have terrible code with vulnerabilities, and to try to avoid compiling it into an exploit. Instead, you should be using -Werror=strict-aliasing which tells the compiler to fatally error when it detects such code. Then you fix the code so it behaves correctly.

The guidance quotes the Linux kernel a lot, which has a known problem: they don't want to rewrite tons of terrible code from decades ago, and can't even agree whether it is terrible code. They're okay with violating the language definition if the compiler pinky promises to not choke on their misuse.

Gentoo's tinderboxing projects (continuously building all packages available in Gentoo using different feature options, new compiler and dependency updates, etc.) also perform test runs for stuff like this. In particular, the LTO tinderbox runs with the following flags:

-flto --Werror=odr -Werror=lto-type-mismatch -Werror=strict-aliasing

LTO is great for this, by the way. It's a massively global optimization pass that causes the compiler to have tremendously better insight into the structure of your entire program, and catch warnings it would otherwise be unable to detect. Strict-aliasing can generally be detected even without LTO, however.

There's another tinderbox that is testing the Modern C flags (c99 forbidden constructs). The guide erroneously singles out Fedora as unique in testing this. Anyways, those are definitely great flags to add. In fact, @thesamesam suggested #12682 to do this via meson, which sounds like a component of what you want.

Meson's sanitizer options are already pretty good. I'm not sure what more we could do here especially since we really don't want to enable sanitizers in production builds (it's great for running testsuites and fuzzers but wow do you pay for the test coverage in terms of performance impact). We already do set some sanitizer options to make sure it errors out as appropriate (again thanks to @thesamesam).

@thesamesam
Copy link
Collaborator

I've been wondering about whether Meson should do this. There's already, as observed, separate options for PIE and PIC.

When I came across #1140 a while back, I wasn't sure if the right answer was to add yet another option for relro or whether we should have a consolidated hardening option.

We also have #12341 we need to handle.

As Eli observed, the OpenSSF guidelines conflate two things:

  1. hardening binaries against attacks
  2. removing UB to make things more predictable

If any, it's Meson's job to do 1), not 2).

I don't know yet if we should do a megaoption or just keep adding individual ones, but I'm not against the idea. I like the concept of making it easy for developers to say "please give me all sensible hardening options". GCC has -fhardened now in (unreleased) GCC 14, but other compilers don't, and it'd be nice to be able to top it up too if appropriate.

@arun5309
Copy link
Author

arun5309 commented Apr 3, 2024

Just to clarify in case it was not clear already, I am not saying meson should have an option to implement the OpenSSF guidelines (or any other guideline for that matter) blindly. Instead, I am saying it would be nice if meson had an option that gives all sensible hardening options.

Also, I am not sure if the megaoption should enable this or not but looking into clang's undefined behavior sanitizer minimal-runtime (this is suitable for use in production environments) might be of interest.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants