[HN Gopher] Hardening ELF binaries using Relocation Read-Only (2...
___________________________________________________________________
Hardening ELF binaries using Relocation Read-Only (2019)
Author : Dentrax
Score : 69 points
Date : 2021-11-11 09:46 UTC (13 hours ago)
(HTM) web link (www.redhat.com)
(TXT) w3m dump (www.redhat.com)
| progbits wrote:
| Here is a video where Andreas implements RELRO protection in
| SerenityOS:
|
| https://youtu.be/7kWSqqZCUcE
|
| This might not be exactly the same as how it is implemented in
| Linux but at least to me seeing all the code involved from start
| to finish is a much better way to understand the concept.
| onedognight wrote:
| Glad to see this security by default progress from RedHat. I was
| surprised to not see a discussion of the costs, though. How much
| slower is program startup for large programs now that all these
| functions are unconditionally looked up at the start instead of
| lazily? Even functions that are never called are now looked up.
| saagarjha wrote:
| 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.
| loeg wrote:
| How often are you starting large applications, and how do you
| define non-negligible here? Milliseconds?
| tpetry wrote:
| > In general, the difference for a large application is non-
| negligible and one should carefully consider the impact
| before enabling this feature by default.
|
| And because of that they enabled it for all binaries on
| Fedora. The fedora users are now testing whether it's
| possible to activate it by default.
| pjmlp wrote:
| From security assessment of view, I consider _the impact_ as
| being the monetary damage that might happen if an exploit is
| taken advantage of.
|
| Naturally one might consider it doesn't matter for the use
| case at hand.
| saagarjha wrote:
| 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.
| nvarsj wrote:
| 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 RELRO/etc.
|
| One of my favorite examples of bypassing relro is the sudo
| exploit that took advantage of a simple format string
| vulnerability. It was downplayed at the time by the sudo
| maintainer as not easy to exploit due to FORTIFY. But you could
| get full root just doing a very simple payload, because sudo
| already calls system(/bin/sh) and FORTIFY itself was easily
| exploitable. [1][2]
|
| 1: https://www.sudo.ws/alerts/sudo_debug.html
|
| 2: https://www.vnsecurity.net/research/2012/02/16/exploiting-
| su...
| DyslexicAtheist wrote:
| 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-security -fstack-protector-strong --param=ssp-
| buffer-size=4 -fcf-protection -Wimplicit-fallthrough
| -D_FORTIFY_SOURCE=2 CFLAGS_DEBUG := -g3 -gdwarf-2
| CFLAGS_RELEASE := -s -fomit-frame-pointer -march=native
| LDFLAGS := -Wl,-z,now -Wl,-z,relro -Wl,-z,defs -Wl,-pie -Wl,--no-
| copy-dt-needed-entries LDFLAGS_HMALLOC := -L/usr/local/lib
| -lhardened_malloc # see
| https://github.com/GrapheneOS/hardened_malloc
|
| don't get security advise from random strangers like me on HN,
| also don't forget to always ship code with an apparmor profile
| and lock down the systemd unit file with seccomp filters and
| other hardening options (even RH is just another IBM company now,
| they have excellent docs on this and some impressive
| appsec/security people on their payroll
| https://www.redhat.com/sysadmin/mastering-systemd). Also after
| learning about systemd hardening this was the time I stopped
| worrying and learned to love systemd. (actually just joking I
| still hate systemd with a passion)
| loeg wrote:
| Isn't -gdwarf-2 an odd choice? Wouldn't you prefer one of the
| newer, more expressive flavors of DWARF? -g by itself gets you
| the default, which is newer than 2 (at least for clang).
| newman314 wrote:
| 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.
| wbl wrote:
| Memory safety obviates these other protections.
| secondcoming wrote:
| 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
| Seirdy wrote:
| 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.
| DyslexicAtheist wrote:
| much appreciated thanks!!
| Seirdy wrote:
| Also you should skip ssp-buffer-size since fstack-
| protector-strong (let alone fstack-protector-all) should
| protect stacks regardless.
| 0xbadcafebee wrote:
| If there's a religion for hating systemd, I want to be one of
| the high priests.
| Seirdy wrote:
| 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.
|
| I listed some more in
| https://news.ycombinator.com/item?id=29191311
| gavinray wrote:
| ... 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.
| yjftsjthsd-h wrote:
| 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.
| DyslexicAtheist wrote:
| 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.
| chasil wrote:
| 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:
| yes Immediate binding: no, not found!
|
| This is the configure directive for new software to pass all
| of the above tests: CFLAGS='-O2
| -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpic -pie' \
| LDFLAGS='-Wl,-z,relro,-z,now -Wl,-z,now' ./configure
|
| The package comes with a manual page with basic explanations
| of each test.
| DyslexicAtheist wrote:
| 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:
| CFLAGS='-O2 -D_FORTIFY_SOURCE=2 -fstack-protector-strong
| -fpic -pie' \ LDFLAGS='-Wl,-z,relro,-z,now
| -Wl,-z,now' ./configure
|
| [1] https://wiki.debian.org/HardeningWalkthrough#My_package
| _alre...
| jcranmer wrote:
| 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-buffer-size=4: adds
| extra code in functions to check that stack buffer overflows
| likely haven't occurred. The second bit does it for every
| variable at least 4 bytes in size.
|
| * -fcf-protection: this enables Intel CET instructions to
| check control flow integrity. This essentially causes the
| hardware to have a shadow stack and other tracking bits to
| prevent ROP attacks from occurring, but it does require very
| new hardware to work correctly.
|
| * -Wimplicit-fallthrough: warns if switch cases don't have
| breaks.
|
| * -D_FORTIFY_SOURCE=2: this causes several basic C functions
| (such as memcpy) in glibc to compile in a somewhat more
| secure manner, namely aborting the program if it can detect
| that it's going to overflow the bounds of an object. The '2'
| level adds extra checks that prohibits some legal C behavior
| (for example, buffer overflows that run into a different
| subobject of the same object).
|
| * -s: Strip the resulting binary after linking.
|
| * -fomit-frame-pointer: This is already the default on
| x86-64, and maybe ARM/AArch64 as well (I don't have those
| ABIs thoroughly memorized).
|
| * -Wl,-z,now: Dynamic symbol resolution has to happen at load
| time rather than lazily. This can cause issues if you're
| relying on a symbol to be provided by a shared library you're
| loading dynamically (not a common case, as most people are
| liable to use dladdr instead).
|
| * -Wl,-z,relro: Make sections that need to be writable only
| for dynamic relocations be read-only post-relocation-fixup
| phase.
|
| * -Wl,-z,defs: Make it a linker error if there's a symbol
| that isn't available in the main executable/library you're
| building or any of the dynamic libraries you've linked. (Like
| -Wl,-z,now, this is again something that is unlikely to cause
| you issues).
|
| * -Wl,-pie: This again enables position-independent
| executables (and should be triggered by -fPIE, so I'm
| somewhat curious why -fPIE isn't being passed here instead of
| -Wl,-pie).
|
| * -Wl,--no-copy-dt-needed-entries: The secondary effect here
| is likely what is intended. If you're linking against
| liba.so, and liba.so depends on libb.so, this prevents the
| application from using libb.so to provide symbols, at least
| for the purposes of deciding whether to cause an error for
| -Wl,-z,defs (it should still load those symbols at runtime
| anyways).
| DyslexicAtheist wrote:
| 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.
| gavinray wrote:
| Thank you so much
___________________________________________________________________
(page generated 2021-11-11 23:02 UTC)