aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@myware66.akkadia.org>2009-05-15 08:01:09 -0700
committerUlrich Drepper <drepper@redhat.com>2009-05-15 08:48:00 -0700
commit774f5a3082b9b55a7668e3a92dc847de577c4946 (patch)
tree1d3ee2c0284923bd69b4db4f9eab2c433efa2af0
parentdeb84c43b1bb0958d942e6739f136d4c11189b3b (diff)
downloadglibc-774f5a3082b9b55a7668e3a92dc847de577c4946.zip
glibc-774f5a3082b9b55a7668e3a92dc847de577c4946.tar.gz
glibc-774f5a3082b9b55a7668e3a92dc847de577c4946.tar.bz2
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.
-rw-r--r--ChangeLog5
-rw-r--r--elf/Makefile14
-rw-r--r--elf/check-execstack.c158
3 files changed, 175 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index e3afa85..cb52b49 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2009-05-15 Ulrich Drepper <drepper@redhat.com>
+
+ * elf/check-execstack.c: New file.
+ * elf/Makefile: Add rules to build and run check-execstack.
+
2009-05-10 Ulrich Drepper <drepper@redhat.com>
* version.h (VERSION): Bump to 2.10.1.
diff --git a/elf/Makefile b/elf/Makefile
index e44ff1d..94b9d06 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 0000000..55cf487
--- /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 <drepper@redhat.com>. 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 <byteswap.h>
+#include <elf.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+#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