Patchwork [RFC,MIPS] Enable non-executable PT_GNU_STACK support

login
register
mail settings
Submitter Faraz Shahbazker
Date Jan. 21, 2016, 10:11 p.m.
Message ID <56A157AF.8080504@imgtec.com>
Download mbox | patch
Permalink /patch/10511/
State New
Headers show

Comments

Faraz Shahbazker - Jan. 21, 2016, 10:11 p.m.
Check AT_FLAGS bits to decide if the kernel supports a non-executable
stack. If not, keep stack executable in spite of permissions requested for
PT_GNU_STACK. Increment ABIVERSION to 5 to mark the new behaviour.

ChangeLog:
	* csu/init-first.c:
	(_init): Invoke EXEC_STACK_OVERRIDE method for static executables.
	* elf/Makefile: Add execstack-ovrd to list of dl-routines.
	Add tst-execstack-ovrd & tst-execstack-ovrd-static test cases.
	* elf/dl-execstack-ovrd.c: New file.
	(_dl_exec_stack_override) New function.
	* elf/dl-load.c
	(_dl_map_object_from_fd): Check if this machine supports
	non-executable stacks using allow_noexec_stack_p_hook and override
	stack executable permissions accordingly.
	* elf/dl-support.c
	(_dl_exec_stack_override_hook): New variable,  initialize to
	_dl_exec_stack_override at startup.
	* elf/rtld.c
	(dl_main): Initialize _dl_exec_stack_override_hook to
	_dl_exec_stack_override at startup.
	* elf/tst-execstack-ovrd-static.c: New test file.
	* elf/tst-execstack-ovrd.c: New test file.
	* sysdeps/generic/ldsodefs.h
	(_dl_exec_stack_override_hook): New function declaration.
	(_dl_exec_stack_override): Likewise.
	* sysdeps/unix/sysv/linux/mips/dl-execstack-ovrd.c: New file.
	(_dl_exec_stack_override) New function.
	* sysdeps/unix/sysv/linux/mips/init-first.c: New file.
	* sysdeps/mips/unix/sysv/linux/mips/ldsodefs.h
	(VALID_ELF_ABIVERSION): Up valid ABI version check to < 6.
	* sysdeps/unix/sysv/linux/mips/libc-abis:
	(MIPS_GNU_STACK): New libc ABI version.
---
 csu/init-first.c                                 |    4 ++
 elf/Makefile                                     |   11 +++--
 elf/dl-execstack-ovrd.c                          |   25 +++++++++++
 elf/dl-load.c                                    |    8 ++++
 elf/dl-support.c                                 |    4 ++
 elf/rtld.c                                       |    1 +
 elf/tst-execstack-ovrd-static.c                  |    1 +
 elf/tst-execstack-ovrd.c                         |    1 +
 sysdeps/generic/ldsodefs.h                       |    8 ++++
 sysdeps/unix/sysv/linux/mips/dl-execstack-ovrd.c |   50 ++++++++++++++++++++++
 sysdeps/unix/sysv/linux/mips/init-first.c        |   26 +++++++++++
 sysdeps/unix/sysv/linux/mips/ldsodefs.h          |    2 +-
 sysdeps/unix/sysv/linux/mips/libc-abis           |    6 +++
 13 files changed, 143 insertions(+), 4 deletions(-)
 create mode 100644 elf/dl-execstack-ovrd.c
 create mode 100644 elf/tst-execstack-ovrd-static.c
 create mode 100644 elf/tst-execstack-ovrd.c
 create mode 100644 sysdeps/unix/sysv/linux/mips/dl-execstack-ovrd.c
 create mode 100644 sysdeps/unix/sysv/linux/mips/init-first.c

\ No newline at end of file
Joseph Myers - Jan. 21, 2016, 10:17 p.m.
On Thu, 21 Jan 2016, Faraz Shahbazker wrote:

> +#ifdef EXEC_STACK_OVERRIDE
> +  EXEC_STACK_OVERRIDE (&GL(dl_stack_flags));
> +#endif

We want to avoid #ifdef where possible.  It's better to have a default 
definition of this macro to expand to do nothing, in a header overridden 
for MIPS.

> @@ -14,3 +14,9 @@ UNIQUE
>  #
>  # MIPS O32 FP64
>  MIPS_O32_FP64   mips*-*-linux*
> +#
> +# MIPS IFUNC
> +IFUNC		mips*-*-linux*
> +#
> +# Non-executable stack support
> +MIPS_GNU_STACK mips*-*-linux*
> \ No newline at end of file

Always end text files with a newline (exactly one newline, otherwise the 
git hooks will complain).

Patch

diff --git a/csu/init-first.c b/csu/init-first.c
index 77c6e1c..3e84690 100644
--- a/csu/init-first.c
+++ b/csu/init-first.c
@@ -77,6 +77,10 @@  _init (int argc, char **argv, char **envp)
   /* First the initialization which normally would be done by the
      dynamic linker.  */
   _dl_non_dynamic_init ();
+
+#ifdef EXEC_STACK_OVERRIDE
+  EXEC_STACK_OVERRIDE (&GL(dl_stack_flags));
+#endif
 #endif
 
 #ifdef VDSO_SETUP
diff --git a/elf/Makefile b/elf/Makefile
index 63a5355..e9f6458 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -31,7 +31,8 @@  routines	= $(all-dl-routines) dl-support dl-iteratephdr \
 dl-routines	= $(addprefix dl-,load lookup object reloc deps hwcaps \
 				  runtime error init fini debug misc \
 				  version profile conflict tls origin scope \
-				  execstack caller open close trampoline)
+				  execstack caller open close trampoline \
+				  execstack-ovrd)
 ifeq (yes,$(use-ldconfig))
 dl-routines += dl-cache
 endif
@@ -122,7 +123,8 @@  tests = tst-tls1 tst-tls2 tst-tls9 tst-leaks1 \
 tests-static = tst-tls1-static tst-tls2-static tst-stackguard1-static \
 	       tst-leaks1-static tst-array1-static tst-array5-static \
 	       tst-ptrguard1-static tst-dl-iter-static \
-	       tst-tlsalign-static tst-tlsalign-extern-static
+	       tst-tlsalign-static tst-tlsalign-extern-static \
+	       tst-execstack-ovrd-static
 ifeq (yes,$(build-shared))
 tests-static += tst-tls9-static
 tst-tls9-static-ENV = \
@@ -158,7 +160,8 @@  endif
 test-srcs = tst-pathopt
 selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null)
 ifneq ($(selinux-enabled),1)
-tests-execstack-yes = tst-execstack tst-execstack-needed tst-execstack-prog
+tests-execstack-yes = tst-execstack tst-execstack-needed tst-execstack-prog \
+	tst-execstack-ovrd
 endif
 endif
 ifeq ($(run-built-tests),yes)
@@ -901,6 +904,8 @@  LDFLAGS-tst-execstack-needed = -Wl,-z,noexecstack
 LDFLAGS-tst-execstack-prog = -Wl,-z,execstack
 CFLAGS-tst-execstack-prog.c += -Wno-trampolines
 CFLAGS-tst-execstack-mod.c += -Wno-trampolines
+LDFLAGS-tst-execstack-ovrd = -Wl,-z,noexecstack
+LDFLAGS-tst-execstack-ovrd-static = -Wl,-z,noexecstack
 endif
 
 LDFLAGS-tst-array2 = $(no-as-needed)
diff --git a/elf/dl-execstack-ovrd.c b/elf/dl-execstack-ovrd.c
new file mode 100644
index 0000000..e0b6cd1
--- /dev/null
+++ b/elf/dl-execstack-ovrd.c
@@ -0,0 +1,25 @@ 
+/* Non-executable stack override for GNU dynamic linker.  Stub version.
+   Copyright (C) 2016 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
+   <http://www.gnu.org/licenses/>.  */
+
+int
+internal_function
+_dl_exec_stack_override (void* flags)
+{
+  return 0;
+}
+rtld_hidden_def (_dl_exec_stack_override)
diff --git a/elf/dl-load.c b/elf/dl-load.c
index c0d6249..bec0d1b 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1278,6 +1278,14 @@  cannot allocate TLS data structures for initial thread");
     /* Adjust the PT_PHDR value by the runtime load address.  */
     l->l_phdr = (ElfW(Phdr) *) ((ElfW(Addr)) l->l_phdr + l->l_addr);
 
+  /* Program requests a non-executable stack, but architecture does
+     not support it.  */
+  if (__glibc_unlikely ((*GL(dl_exec_stack_override_hook)) (&stack_flags) != 0))
+    {
+      errstring = N_("cannot override stack memory protections");
+      goto call_lose_errno;
+    }
+
   if (__glibc_unlikely ((stack_flags &~ GL(dl_stack_flags)) & PF_X))
     {
       if (__glibc_unlikely (__check_caller (RETURN_ADDRESS (0), allow_ldso) != 0))
diff --git a/elf/dl-support.c b/elf/dl-support.c
index c30194c..b25a6b3 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -182,6 +182,10 @@  ElfW(Word) _dl_stack_flags = DEFAULT_STACK_PERMS;
 int (*_dl_make_stack_executable_hook) (void **) internal_function
   = _dl_make_stack_executable;
 
+/* Check if architecture allows non-executable stack.  */
+int (*_dl_exec_stack_override_hook) (void *) internal_function
+  = _dl_exec_stack_override;
+
 
 /* Function in libpthread to wait for termination of lookups.  */
 void (*_dl_wait_lookup_done) (void);
diff --git a/elf/rtld.c b/elf/rtld.c
index 647661c..80a4871 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -768,6 +768,7 @@  dl_main (const ElfW(Phdr) *phdr,
   /* The explicit initialization here is cheaper than processing the reloc
      in the _rtld_local definition's initializer.  */
   GL(dl_make_stack_executable_hook) = &_dl_make_stack_executable;
+  GL(dl_exec_stack_override_hook) = &_dl_exec_stack_override;
 
   /* Process the environment variable which control the behaviour.  */
   process_envvars (&mode);
diff --git a/elf/tst-execstack-ovrd-static.c b/elf/tst-execstack-ovrd-static.c
new file mode 100644
index 0000000..0e5e61b
--- /dev/null
+++ b/elf/tst-execstack-ovrd-static.c
@@ -0,0 +1 @@ 
+#include "tst-execstack-ovrd.c"
diff --git a/elf/tst-execstack-ovrd.c b/elf/tst-execstack-ovrd.c
new file mode 100644
index 0000000..180657e
--- /dev/null
+++ b/elf/tst-execstack-ovrd.c
@@ -0,0 +1 @@ 
+#include "tst-execstack-prog.c"
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 2733ac8..d0d0e9b 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -366,6 +366,9 @@  struct rtld_global
      It returns an errno code or zero on success.  */
   EXTERN int (*_dl_make_stack_executable_hook) (void **) internal_function;
 
+  /* Check if this architecture support non-executable stack segments.  */
+  EXTERN int (*_dl_exec_stack_override_hook) (void *) internal_function;
+
   /* Prevailing state of the stack, PF_X indicating it's executable.  */
   EXTERN ElfW(Word) _dl_stack_flags;
 
@@ -629,6 +632,11 @@  extern void **_dl_initial_error_catch_tsd (void) __attribute__ ((const))
 extern int _dl_make_stack_executable (void **stack_endp) internal_function;
 rtld_hidden_proto (_dl_make_stack_executable)
 
+/* This is the initial value of GL(dl_exec_stack_override_hook).
+   A threads library can change it.  */
+extern int _dl_exec_stack_override (void *) internal_function;
+rtld_hidden_proto (_dl_exec_stack_override)
+
 /* Variable pointing to the end of the stack (or close to it).  This value
    must be constant over the runtime of the application.  Some programs
    might use the variable which results in copy relocations on some
diff --git a/sysdeps/unix/sysv/linux/mips/dl-execstack-ovrd.c b/sysdeps/unix/sysv/linux/mips/dl-execstack-ovrd.c
new file mode 100644
index 0000000..f4ba5b1
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mips/dl-execstack-ovrd.c
@@ -0,0 +1,50 @@ 
+/* Non-executable stack override for GNU dynamic linker.  MIPS specific
+   version.
+   Copyright (C) 2016 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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <elf.h>
+#include <ldsodefs.h>
+#include <misc/sys/auxv.h>
+
+ /* Flag to indicate that non-executable stack supported by kernel.
+    Ref: arch/mips/include/asm/elf.h in kernel sources. */
+#define AV_FLAGS_MIPS_GNU_STACK	(1 << 24)
+
+extern int __stack_prot attribute_relro attribute_hidden;
+
+int
+internal_function
+_dl_exec_stack_override (void* flags)
+{
+  if ((*(ElfW(Word) *)flags & PF_X) == 0
+      && (getauxval (AT_FLAGS) & AV_FLAGS_MIPS_GNU_STACK) == 0)
+    {
+#ifndef SHARED
+      /* For static executable, we need to set stack permission here. */
+      uintptr_t page = ((uintptr_t) __libc_stack_end
+		    & -(intptr_t) GLRO(dl_pagesize));
+      if (__mprotect ((void *) page, GLRO(dl_pagesize),
+		      PROT_READ | PROT_WRITE | PROT_EXEC | __stack_prot) < 0)
+	return errno;
+#endif /* !SHARED */
+      *(ElfW(Word) *)flags |= PF_X;
+    }
+
+  return 0;
+}
+rtld_hidden_def (_dl_exec_stack_override)
diff --git a/sysdeps/unix/sysv/linux/mips/init-first.c b/sysdeps/unix/sysv/linux/mips/init-first.c
new file mode 100644
index 0000000..28a3033
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mips/init-first.c
@@ -0,0 +1,26 @@ 
+/* Initialization code run first thing by the ELF startup code.  Linux/ARM.
+   Copyright (C) 2016 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
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef SHARED
+#include <ldsodefs.h>
+
+# define EXEC_STACK_OVERRIDE GL(dl_exec_stack_override)
+#endif /* !SHARED */
+
+#include <csu/init-first.c>
diff --git a/sysdeps/unix/sysv/linux/mips/ldsodefs.h b/sysdeps/unix/sysv/linux/mips/ldsodefs.h
index 3d2289c..3eb17d4 100644
--- a/sysdeps/unix/sysv/linux/mips/ldsodefs.h
+++ b/sysdeps/unix/sysv/linux/mips/ldsodefs.h
@@ -34,7 +34,7 @@  extern void _dl_static_init (struct link_map *map);
 #undef VALID_ELF_ABIVERSION
 #define VALID_ELF_ABIVERSION(osabi,ver)			\
   (ver == 0						\
-   || (osabi == ELFOSABI_SYSV && ver < 4)		\
+   || (osabi == ELFOSABI_SYSV && ver < 6)		\
    || (osabi == ELFOSABI_GNU && ver < LIBC_ABI_MAX))
 
 #endif /* ldsodefs.h */
diff --git a/sysdeps/unix/sysv/linux/mips/libc-abis b/sysdeps/unix/sysv/linux/mips/libc-abis
index 14ff603..8728f68 100644
--- a/sysdeps/unix/sysv/linux/mips/libc-abis
+++ b/sysdeps/unix/sysv/linux/mips/libc-abis
@@ -14,3 +14,9 @@  UNIQUE
 #
 # MIPS O32 FP64
 MIPS_O32_FP64   mips*-*-linux*
+#
+# MIPS IFUNC
+IFUNC		mips*-*-linux*
+#
+# Non-executable stack support
+MIPS_GNU_STACK mips*-*-linux*