From 774f5a3082b9b55a7668e3a92dc847de577c4946 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Fri, 15 May 2009 08:01:09 -0700 Subject: Test DSOs for executable stack. Add a text program, built to run on the host, to check all newly built DSOs for executable stacks and fail if the stack information is missing or indicates executable stacks. --- ChangeLog | 5 ++ elf/Makefile | 14 ++++- elf/check-execstack.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 elf/check-execstack.c diff --git a/ChangeLog b/ChangeLog index e3afa8543c..cb52b49da4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-05-15 Ulrich Drepper + + * elf/check-execstack.c: New file. + * elf/Makefile: Add rules to build and run check-execstack. + 2009-05-10 Ulrich Drepper * version.h (VERSION): Bump to 2.10.1. diff --git a/elf/Makefile b/elf/Makefile index e44ff1d382..94b9d069bf 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -93,7 +93,7 @@ distribute := rtld-Rules \ order2mod1.c order2mod2.c order2mod3.c order2mod4.c \ tst-stackguard1.c tst-stackguard1-static.c \ tst-array5.c tst-array5-static.c tst-array5dep.c \ - tst-array5.exp tst-leaks1.c + tst-array5.exp tst-leaks1.c check-execstack.c CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables @@ -842,12 +842,16 @@ check-textrel-CFLAGS = -O -Wall -D_XOPEN_SOURCE=600 -D_BSD_SOURCE $(objpfx)check-textrel: check-textrel.c $(native-compile) +check-execstack-CFLAGS = -O -Wall -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -std=gnu99 +$(objpfx)check-execstack: check-execstack.c + $(native-compile) + check-localplt-CFLAGS = -O -Wall -D_GNU_SOURCE -std=gnu99 $(objpfx)check-localplt: check-localplt.c $(native-compile) ifeq (yes,$(build-shared)) -tests: $(objpfx)check-textrel.out +tests: $(objpfx)check-textrel.out $(objpfx)check-execstack.out $(objpfx)check-textrel.out: $(objpfx)check-textrel $(dir $<)$(notdir $<) $(common-objpfx)libc.so \ @@ -855,6 +859,12 @@ $(objpfx)check-textrel.out: $(objpfx)check-textrel $(common-objpfx)iconvdata/*.so)) > $@ generated += check-textrel check-textrel.out +$(objpfx)check-execstack.out: $(objpfx)check-execstack + $(dir $<)$(notdir $<) $(common-objpfx)libc.so \ + $(sort $(wildcard $(common-objpfx)*/lib*.so \ + $(common-objpfx)iconvdata/*.so)) > $@ +generated += check-execstack check-execstack.out + $(objpfx)tst-dlmodcount: $(libdl) $(objpfx)tst-dlmodcount.out: $(test-modules) diff --git a/elf/check-execstack.c b/elf/check-execstack.c new file mode 100644 index 0000000000..55cf48721a --- /dev/null +++ b/elf/check-execstack.c @@ -0,0 +1,158 @@ +/* Check for executable stacks in DSOs. + Copyright (C) 2009 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contribute by Ulrich Drepper . 2009. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef BITS + +# define AB(name) _AB (name, BITS) +# define _AB(name, bits) __AB (name, bits) +# define __AB(name, bits) name##bits +# define E(name) _E (name, BITS) +# define _E(name, bits) __E (name, bits) +# define __E(name, bits) Elf##bits##_##name +# define SWAP(val) \ + ({ __typeof (val) __res; \ + if (((ehdr.e_ident[EI_DATA] == ELFDATA2MSB \ + && BYTE_ORDER == LITTLE_ENDIAN) \ + || (ehdr.e_ident[EI_DATA] == ELFDATA2LSB \ + && BYTE_ORDER == BIG_ENDIAN)) \ + && sizeof (val) != 1) \ + { \ + if (sizeof (val) == 2) \ + __res = bswap_16 (val); \ + else if (sizeof (val) == 4) \ + __res = bswap_32 (val); \ + else \ + __res = bswap_64 (val); \ + } \ + else \ + __res = (val); \ + __res; }) + + +static int +AB(handle_file) (const char *fname, int fd) +{ + E(Ehdr) ehdr; + + if (pread (fd, &ehdr, sizeof (ehdr), 0) != sizeof (ehdr)) + { + read_error: + printf ("%s: read error: %m\n", fname); + return 1; + } + + const size_t phnum = SWAP (ehdr.e_phnum); + const size_t phentsize = SWAP (ehdr.e_phentsize); + + /* Read the program header. */ + E(Phdr) *phdr = alloca (phentsize * phnum); + if (pread (fd, phdr, phentsize * phnum, SWAP (ehdr.e_phoff)) + != phentsize * phnum) + goto read_error; + + /* Search for the PT_GNU_STACK entry. */ + for (size_t cnt = 0; cnt < phnum; ++cnt) + if (SWAP (phdr[cnt].p_type) == PT_GNU_STACK) + { + unsigned int flags = SWAP(phdr[cnt].p_flags); + if (flags & PF_X) + { + printf ("%s: executable stack signaled\n", fname); + return 1; + } + + return 0; + } + + printf ("%s: no PT_GNU_STACK entry\n", fname); + return 1; +} + +# undef BITS +#else + +# define BITS 32 +# include "check-execstack.c" + +# define BITS 64 +# include "check-execstack.c" + + +static int +handle_file (const char *fname) +{ + int fd = open (fname, O_RDONLY); + if (fd == -1) + { + printf ("cannot open %s: %m\n", fname); + return 1; + } + + /* Read was is supposed to be the ELF header. Read the initial + bytes to determine whether this is a 32 or 64 bit file. */ + char ident[EI_NIDENT]; + if (read (fd, ident, EI_NIDENT) != EI_NIDENT) + { + printf ("%s: read error: %m\n", fname); + close (fd); + return 1; + } + + if (memcmp (&ident[EI_MAG0], ELFMAG, SELFMAG) != 0) + { + printf ("%s: not an ELF file\n", fname); + close (fd); + return 1; + } + + int result; + if (ident[EI_CLASS] == ELFCLASS64) + result = handle_file64 (fname, fd); + else + result = handle_file32 (fname, fd); + + close (fd); + + return result; +} + + +int +main (int argc, char *argv[]) +{ + int cnt; + int result = 0; + + for (cnt = 1; cnt < argc; ++cnt) + result |= handle_file (argv[cnt]); + + return result; +} +#endif -- cgit 1.4.1