[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)