last time I checked the Debian and Gentoo hardening guides relro/pie were standard practice. I can't remember the time we didn't use it and I've been around for a minute. this is my template for most Linux projects (except when "something else" is needed :)) ... please don't copy paste without certainty of what it does: CFLAGS_BASE := -c -O2 -Wall -Werror -Wpedantic -pipe $(CFLAGS) CFLAGS_HARD := -fPIE -Wformat-secur…
You should probably add noexecstack to your ldflags.
I also only use -fstack-protector-strong and -fcf-protection as a fallback in case -fstack-protector-all and -fcf-protection=full cause crashes.
... please don't copy paste without certainty of what it does Would you be willing to explain why this specific set of flags (I realize I could google them all, but I also realize that some flags have interactions with other flags and trying to find those is not straightforward)? Genuinely interested, not holding you accountable for my computer exploding.
EPEL has this package: $ rpm -q hardening-check hardening-check-2.6-1.el7.noarch $ rpm -qi hardening-check | grep URL URL : http://packages.debian.org/hardening-wrapper It will tell you basic protections in ELF binaries. $ hardening-check /bin/ls /bin/ls: Position Independent Executable: no, normal executable! Stack protected: yes Fortify Source functions: yes (some protected functions found) Read-only relocations: y…
I checked the debian package for hardening-wrapper and it seems deprecated [1], but fwiw still useful imo.
your configure directives are more up2date from what I posted by moving -pie -fpic to cflags:
... please don't copy paste without certainty of what it does Would you be willing to explain why this specific set of flags (I realize I could google them all, but I also realize that some flags have interactions with other flags and trying to find those is not straightforward)? Genuinely interested, not holding you accountable for my computer exploding.
If nothing else, I'd like to call out -Werror as a footgun when shipping for other people to use. By all means use it for dev work when you control the environment, but as an end-user (well, downstream, at least) it's a problem when packages outright break because I'm building with a newer compiler version that added more warnings.
absolutely. you don't want to have -Werror in a fast moving FOSS project. It depends on what you're doing. I compile against latest compiler versions in a CI pipeline that I want to fail. It's probably not how you want to ship in FOSS projects.
... please don't copy paste without certainty of what it does Would you be willing to explain why this specific set of flags (I realize I could google them all, but I also realize that some flags have interactions with other flags and trying to find those is not straightforward)? Genuinely interested, not holding you accountable for my computer exploding.
Not OP, but here goes: * -fPIE : Compile as a 'position-independent executable'. This allows code and data sections of the executable to be installed at random locations in the address space, and comes with a mild cost due to needing extra indirections to handle position-independent code. * -Wformat-security: adds some extra warnings around possible misuse of printf and scanf. * -fstack-protector-strong --param=ssp-b…
much appreciated. Especially the hint that -fomit-frame.pointer being default now was new to me . I recall many discussions (email threads spanning months) to convince our teams to add it in release builds. I'm glad seeing this as the default now.
I think the killer feature which nobody picked up on is hardened_malloc. though it requires LD_PRELOAD and it comes with a very big disclaimer that might be too conservative for most projects.
Wouldn't some of this be mitigated by specifying function visiblity? AIUI, when building a shared lib, all functions are visible in case a user wants to hook any functions via, e.g. LD_PRELOAD
Yes, fvisibility=hidden is a great addition; combined with LTO and a Clang toolchain, you can also add fsanitize=cfi. The CFI sanitizer adds a 1% perf penalty for a significant exploit mitigation. It complements -fcf-protection=full nicely. You can also add fsanitize=shadow-stack (ARM) or fsanitize=safe-stack (x86_64) for stronger protection than -fstack-protector-all. This will cause many programs to crash.
Yes, fvisibility=hidden is a great addition; combined with LTO and a Clang toolchain, you can also add fsanitize=cfi. The CFI sanitizer adds a 1% perf penalty for a significant exploit mitigation. It complements -fcf-protection=full nicely. You can also add fsanitize=shadow-stack (ARM) or fsanitize=safe-stack (x86_64) for stronger protection than -fstack-protector-all. This will cause many programs to crash.
much appreciated thanks!!
Also you should skip ssp-buffer-size since fstack-protector-strong (let alone fstack-protector-all) should protect stacks regardless.
last time I checked the Debian and Gentoo hardening guides relro/pie were standard practice. I can't remember the time we didn't use it and I've been around for a minute. this is my template for most Linux projects (except when "something else" is needed :)) ... please don't copy paste without certainty of what it does: CFLAGS_BASE := -c -O2 -Wall -Werror -Wpedantic -pipe $(CFLAGS) CFLAGS_HARD := -fPIE -Wformat-secur…
Also, one can use checksec to confirm that the protections are actually in place. https://github.com/slimm609/checksec.sh I happened to be looking at this for Go binaries last night and it seems that -buildmode=pie gets you part of the way there. Was trying to see if full relro was possible with CGO_ENABLED=0 but it seems only partial was achievable in the few hours I spent.
... please don't copy paste without certainty of what it does Would you be willing to explain why this specific set of flags (I realize I could google them all, but I also realize that some flags have interactions with other flags and trying to find those is not straightforward)? Genuinely interested, not holding you accountable for my computer exploding.
EPEL has this package: $ rpm -q hardening-check hardening-check-2.6-1.el7.noarch $ rpm -qi hardening-check | grep URL URL : http://packages.debian.org/hardening-wrapper It will tell you basic protections in ELF binaries. $ hardening-check /bin/ls /bin/ls: Position Independent Executable: no, normal executable! Stack protected: yes Fortify Source functions: yes (some protected functions found) Read-only relocations: y…
In Debian, the perl script, "hardening-check" is included in the package "devscripts".
There’s a one sentence nod to this at the bottom: > Using full RELRO has a slight performance impact during application startup (as the linker has to populate the GOT entries before entering the main function). In general, the difference for a large application is non-negligible and one should carefully consider the impact before enabling this feature by default.
How often are you starting large applications, and how do you define non-negligible here? Milliseconds?
This might be important if you're doing something like repeatedly spawning a large shell interpreter, for example.
One might wonder how high this raises the bar; that is, what how an attacker would generally respond to full RELRO. The answer is usually that one would go after other data pointers not secured by RELRO. If there’s any in the binary, that’s the best, but otherwise usually you leak information about libc and target something like the malloc or free hooks which are likely to be called.
It definitely makes generic exploits harder. Without RELRO it's easy to leak libc once you find an overflow. You can also easily take control via overwriting the GOT pointers. Unsure what you mean by any in the binary - with PIE you can't do much even if you know a fixed offset, unless you can leak the binary location. Although if you can read/write into the stack you can usually find something useful regardless of R…
If you can write to the GOT, you can also likely write to function pointers in the binary's data segment. (Which is generally harder to set up, which is why RELRO is useful.)