devtools: Add security-check.py #6854

pull laanwj wants to merge 1 commits into bitcoin:master from laanwj:2015_10_security_checks changing 3 files +268 −3
  1. laanwj commented at 1:01 PM on October 19, 2015: member

    Performs the following ELF security checks:

    • PIE: Check for position independent executable (PIE), allowing for address space randomization
    • NX: Check that no sections are writable and executable (including the stack)
    • RELRO: Check for read-only relocations, binding at startup
    • Canary: Check for use of stack canary

    Also add a check to symbol-check.py that checks that only the subset of allowed libraries is imported (to avoid incompatibilities).

    This needs to be integrated into Travis, or at least the gitian build so that we won't do releases that don't pass these checks. We also need similar checks for OSX and Windows at some point.

  2. laanwj added the label Build system on Oct 19, 2015
  3. jonasschnelli commented at 1:55 PM on October 19, 2015: contributor

    Nice. Concept ACK.

    ASLR/PIE check on OSX can be done with otool -hv <file>. Not sure how we would execute otools in gitian. NX checks can be done over a vmmap check. For Travis we should create a native osx build (which could run otools to check the executable).

  4. laanwj force-pushed on Oct 19, 2015
  5. gavinandresen commented at 2:34 PM on October 19, 2015: contributor

    Nice! So testing this would be: Recompile with --disable-hardening (or subsets of those flags) and making sure security-check.py complains?

  6. LongShao007 commented at 2:51 PM on October 19, 2015: contributor

    How to check security for Windows ?

  7. laanwj commented at 3:35 PM on October 19, 2015: member

    @gavinandresen Right, to speed up testing you could use any C file:

    cat >  test1.c << EOF
    #include <stdio.h>
    
    int main()
    {
        printf("the quick brown fox jumps over the lazy god\n");
        return 0;
    }
    EOF
    gcc test1.c -o test1 -Wl,-zexecstack;
    contrib/devtools/security-check.py test1; echo $?
    gcc test1.c -o test1
    contrib/devtools/security-check.py test1; echo $?
    gcc test1.c -o test1 -fstack-protector-all
    contrib/devtools/security-check.py test1; echo $?
    gcc test1.c -o test1 -fstack-protector-all -pie -fPIE
    contrib/devtools/security-check.py test1; echo $?
    gcc test1.c -o test1 -fstack-protector-all -pie -fPIE -Wl,-zrelro  -Wl,-z,now
    contrib/devtools/security-check.py test1; echo $?
    

    Output:

    test1: failed PIE NX RELRO Canary
    1
    test1: failed PIE RELRO Canary
    1
    test1: failed PIE RELRO
    1
    test1: failed RELRO
    1
    0
    

    @LongShao007 yes, how? (readelf doesn't, but objdump -x does in fact work for PE files, but I wouldn't know what flags to look for)

  8. laanwj commented at 3:53 PM on October 19, 2015: member

    On windows:

    NX: DllCharacteristics bit 0x100 signifies nxcompat (DEP):

    -DllCharacteristics     00000100
    +DllCharacteristics     00000000
    

    PIE: DllCharacteristics bit 0x40 signifies dynamicbase (ASLR):

    +DllCharacteristics     00000000
    -DllCharacteristics     00000040
    

    Not sure whether there is a RELRO equivalent, Canary is there but difficult to check from the outside as the mingw library is linked statically.

    Edit: Ok, added the windows checks above for PE executables, and converted the above test to a test script test-security-check.py.

  9. laanwj force-pushed on Oct 19, 2015
  10. laanwj force-pushed on Oct 19, 2015
  11. laanwj commented at 11:17 AM on October 21, 2015: member

    @theuni paths to tools like READELF, OBJDUMP can now be overridden

  12. in contrib/devtools/security-check.py:None in a0dd4e0055 outdated
     156 | +    retval = 0
     157 | +    for filename in sys.argv[1:]:
     158 | +        try:
     159 | +            etype = identify_executable(filename)
     160 | +            if etype is None:
     161 | +                print('%s: unknown format')
    


    MarcoFalke commented at 12:17 PM on October 21, 2015:

    Nit: orphan %s.


    laanwj commented at 12:19 PM on October 21, 2015:

    Good catch. Fixed

  13. laanwj force-pushed on Oct 21, 2015
  14. dcousens commented at 1:03 PM on October 21, 2015: contributor

    concept ACK

  15. in contrib/devtools/security-check.py:None in 5f78ded048 outdated
      77 | +    GNU_RELRO program header must exist, must be "R"
      78 | +    Dynamic section must have BIND_NOW flag
      79 | +    '''
      80 | +    have_gnu_relro = False
      81 | +    for (typ, flags) in get_ELF_program_headers(executable):
      82 | +        if typ == 'GNU_RELRO' and flags == 'R':
    


    theuni commented at 5:39 PM on October 21, 2015:

    Interestingly on my machine, whether or not this shows up as R or RW seems to depend on the linker. I'm afraid I don't know enough to determine if having this section writable is a security implication.

    $ g++ ... -o bitcoin-cli -fuse-ld=bfd
    $ readelf -l -W bitcoin-cli | grep RELRO
      GNU_RELRO      0x243e20 0x0000000000443e20 0x0000000000443e20 0x0201e0 0x0201e0 R   0x1
    
    $ g++ ... -o bitcoin-cli -fuse-ld=gold
    $ readelf -l -W bitcoin-cli | grep RELRO
      GNU_RELRO      0x244e20 0x0000000000245e20 0x0000000000245e20 0x0201e0 0x0201e0 RW  0x20
    

    laanwj commented at 1:15 AM on October 22, 2015:

    One important point of RELRO in combination with BIND_NOW is that the area can be read-only, as that part contains function pointers. Common heap overflow exploits allow overwriting a word, these frequently invoked function pointers make good targets.

      LOAD           0x000000 0x0000000000400000 0x0000000000400000 0x0007d4 0x0007d4 R E 0x200000
       02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame 
    
      LOAD           0x000db8 0x0000000000600db8 0x0000000000600db8 0x000258 0x000260 RW  0x200000
       03     .init_array .fini_array .jcr .dynamic .got .data .bss 
    ...
      GNU_RELRO      0x000db8 0x0000000000600db8 0x0000000000600db8 0x000248 0x000248 R   0x1
       08     .init_array .fini_array .jcr .dynamic .got 
    

    However, all the sections are part of the second LOAD section which are what actually maps memory and determine the permissions, and those are RW, also with my linker. I don't think the flags on GNU_RELRO have any influence.

    It looks like the executable itself takes care of mprotecting this area at start (glibc _dl_protect_relro):

    mprotect(0x600000, 4096, PROT_READ)     = 0
    

    I experimentally verified that the section is unwritable during runtime, both when linked with bfd and with gold. This all makes sense, as the dynamic linker does need to write to it to set the pointers in the first place...


    laanwj commented at 1:20 AM on October 22, 2015:

    See also this thread: http://permalink.gmane.org/gmane.comp.gnu.binutils/71347 Will remove the check - although I agree with Alan that having it as 'R' is clearer, as that is the eventual intention.

  16. theuni commented at 6:08 PM on October 21, 2015: member

    Looks good other than the comment above. Something to note: The libevent brought in a dependency on clock_gettime, which is a glibc compat issue. Once we bump to a newer gcc, we'll have to work that out for releases.

    As discussed on IRC, this should also be hooked up to a make target for easier testing w/ travis and gitian. That can be done as a next step.

  17. devtools: Add security-check.py
    Perform the following ELF security checks:
    
    - PIE: Check for position independent executable (PIE), allowing for address space randomization
    - NX: Check that no sections are writable and executable (including the stack)
    - RELRO: Check for read-only relocations, binding at startup
    - Canary: Check for use of stack canary
    
    Also add a check to symbol-check.py that checks that only the subset of
    allowed libraries is imported (to avoid incompatibilities).
    579b863cd7
  18. laanwj force-pushed on Oct 22, 2015
  19. laanwj merged this on Oct 22, 2015
  20. laanwj closed this on Oct 22, 2015

  21. laanwj referenced this in commit a09297010e on Oct 22, 2015
  22. str4d referenced this in commit 85fe644139 on Oct 15, 2016
  23. zkbot referenced this in commit 4ee9d712b5 on Oct 17, 2016
  24. DrahtBot locked this on Sep 8, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-13 15:15 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me