mirror of
https://sourceware.org/git/glibc.git
synced 2025-06-09 10:01:22 +03:00
elf: Add elf/check-wx-segment, a test for the presence of WX segments
Writable, executable segments defeat security hardening. The existing check for DT_TEXTREL does not catch this. hppa and SPARC currently keep the PLT in an RWX load segment.
This commit is contained in:
parent
b5b7fb76e1
commit
0499a353a6
@ -402,6 +402,7 @@ tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out \
|
|||||||
$(objpfx)tst-rtld-preload.out
|
$(objpfx)tst-rtld-preload.out
|
||||||
endif
|
endif
|
||||||
tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \
|
tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \
|
||||||
|
$(objpfx)check-wx-segment.out \
|
||||||
$(objpfx)check-localplt.out $(objpfx)check-initfini.out
|
$(objpfx)check-localplt.out $(objpfx)check-initfini.out
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -1180,6 +1181,12 @@ $(objpfx)check-execstack.out: $(..)scripts/check-execstack.awk \
|
|||||||
$(evaluate-test)
|
$(evaluate-test)
|
||||||
generated += check-execstack.out
|
generated += check-execstack.out
|
||||||
|
|
||||||
|
$(objpfx)check-wx-segment.out: $(..)scripts/check-wx-segment.py \
|
||||||
|
$(all-built-dso:=.phdr)
|
||||||
|
$(PYTHON) $^ --xfail="$(check-wx-segment-xfail)" > $@; \
|
||||||
|
$(evaluate-test)
|
||||||
|
generated += check-wx-segment.out
|
||||||
|
|
||||||
$(objpfx)tst-dlmodcount: $(libdl)
|
$(objpfx)tst-dlmodcount: $(libdl)
|
||||||
$(objpfx)tst-dlmodcount.out: $(test-modules)
|
$(objpfx)tst-dlmodcount.out: $(test-modules)
|
||||||
|
|
||||||
|
85
scripts/check-wx-segment.py
Normal file
85
scripts/check-wx-segment.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# Check ELF program headers for WX segments.
|
||||||
|
# Copyright (C) 2020 Free Software Foundation, Inc.
|
||||||
|
# This file is part of the GNU C Library.
|
||||||
|
#
|
||||||
|
# The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2.1 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with the GNU C Library; if not, see
|
||||||
|
# <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
"""Check that the program headers do not contain write-exec segments."""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os.path
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Regular expression to extract the RWE flags field. The
|
||||||
|
# address/offset columns have varying width.
|
||||||
|
RE_LOAD = re.compile(
|
||||||
|
r'^ LOAD +(?:0x[0-9a-fA-F]+ +){5}([R ][W ][ E]) +0x[0-9a-fA-F]+\n\Z')
|
||||||
|
|
||||||
|
def process_file(path, inp, xfail):
|
||||||
|
"""Analyze one input file."""
|
||||||
|
|
||||||
|
errors = 0
|
||||||
|
for line in inp:
|
||||||
|
error = None
|
||||||
|
if line.startswith(' LOAD '):
|
||||||
|
match = RE_LOAD.match(line)
|
||||||
|
if match is None:
|
||||||
|
error = 'Invalid LOAD line'
|
||||||
|
else:
|
||||||
|
flags, = match.groups()
|
||||||
|
if 'W' in flags and 'E' in flags:
|
||||||
|
if xfail:
|
||||||
|
print('{}: warning: WX segment (as expected)'.format(
|
||||||
|
path))
|
||||||
|
else:
|
||||||
|
error = 'WX segment'
|
||||||
|
|
||||||
|
if error is not None:
|
||||||
|
print('{}: error: {}: {!r}'.format(path, error, line.strip()))
|
||||||
|
errors += 1
|
||||||
|
|
||||||
|
if xfail and errors == 0:
|
||||||
|
print('{}: warning: missing expected WX segment'.format(path))
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""The main entry point."""
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument('--xfail',
|
||||||
|
help='Mark input files as XFAILed ("*" for all)',
|
||||||
|
type=str, default='')
|
||||||
|
parser.add_argument('phdrs',
|
||||||
|
help='Files containing readelf -Wl output',
|
||||||
|
nargs='*')
|
||||||
|
opts = parser.parse_args(sys.argv)
|
||||||
|
|
||||||
|
xfails = set(opts.xfail.split(' '))
|
||||||
|
xfails_all = opts.xfail.strip() == '*'
|
||||||
|
|
||||||
|
errors = 0
|
||||||
|
for path in opts.phdrs:
|
||||||
|
xfail = ((os.path.basename(path) + '.phdrs') in xfails
|
||||||
|
or xfails_all)
|
||||||
|
with open(path) as inp:
|
||||||
|
errors += process_file(path, inp, xfail)
|
||||||
|
if errors > 0:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -16,6 +16,15 @@ CPPFLAGS-crti.S += -fPIC
|
|||||||
CPPFLAGS-crtn.S += -fPIC
|
CPPFLAGS-crtn.S += -fPIC
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(subdir),elf)
|
||||||
|
|
||||||
|
# Lazy binding on SPARC rewrites the PLT sequence. See the Solaris
|
||||||
|
# Linker and Libraries Guide, section SPARC: Procedure Linkage Table.
|
||||||
|
# <https://docs.oracle.com/cd/E19455-01/816-0559/chapter6-1236/index.html>
|
||||||
|
test-xfail-check-wx-segment = *
|
||||||
|
|
||||||
|
endif # $(subdir) == elf
|
||||||
|
|
||||||
# nscd uses atomic_spin_nop which in turn requires cpu_relax
|
# nscd uses atomic_spin_nop which in turn requires cpu_relax
|
||||||
ifeq ($(subdir),nscd)
|
ifeq ($(subdir),nscd)
|
||||||
routines += cpu_relax
|
routines += cpu_relax
|
||||||
|
@ -3,9 +3,14 @@ ifeq ($(subdir),stdlib)
|
|||||||
gen-as-const-headers += ucontext_i.sym
|
gen-as-const-headers += ucontext_i.sym
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(subdir),elf)
|
||||||
# Supporting non-executable stacks on HPPA requires changes to both
|
# Supporting non-executable stacks on HPPA requires changes to both
|
||||||
# the Linux kernel and glibc. The kernel currently needs an executable
|
# the Linux kernel and glibc. The kernel currently needs an executable
|
||||||
# stack for syscall restarts and signal returns.
|
# stack for syscall restarts and signal returns.
|
||||||
ifeq ($(subdir),elf)
|
|
||||||
test-xfail-check-execstack = yes
|
test-xfail-check-execstack = yes
|
||||||
endif
|
|
||||||
|
# On hppa, the PLT is executable because it contains an executable
|
||||||
|
# trampoline used during lazy binding.
|
||||||
|
test-xfail-check-wx-segment = *
|
||||||
|
|
||||||
|
endif # $(subdir) == elf
|
||||||
|
Loading…
x
Reference in New Issue
Block a user