[v4] Mips support for PT_GNU_STACK
diff mbox series

Message ID 1566299534-11595-1-git-send-email-dmladjenovic@wavecomp.com
State New
Headers show
Series
  • [v4] Mips support for PT_GNU_STACK
Related show

Commit Message

Dragan Mladjenovic Aug. 20, 2019, 11:16 a.m. UTC
From: "Dragan Mladjenovic" <dmladjenovic@wavecomp.com>

Hello everyone,

This is fourth attempt to enable glibc to safely handle PT_GNU_STACK on Linux/Mips.
You can check out the previous discussion about this issue at [1], [2] and [3].

A brief summary of the issue this is trying to address:

Up until the Linux kernel version 4.8 [4] MIPS FPU emulator used a small trampoline,
created on user stack, to handle delay slots when emulating FPU branches.
Because of this non-executable stack could not be enabled by default on MIPS.
The compatibility issue is that these old kernels respect PT_GNU_STACK,
making the stack non-executable if requested, and could crash the user process if
there would be need to emulate an instruction in the delay slot of a FPU branch.

In order to allow for the glibc to be safely compiled with potential future gcc that
emits .note.GNU-stack, that is without silently producing RW PT_GNU_STACK libc that
might crash at runtime, this patch forces executable stack for all build objects if
configured to run against minimum kernel version less than 4.8.

The gcc side of the patch can be found at [5]. It allows gcc to emit .note.GNU-stack
by default on hard-float mips targets that are configured against the future release
of glibc.

Best regards,

Dragan

[1] https://sourceware.org/ml/libc-alpha/2019-06/msg00889.html
[2] https://sourceware.org/ml/libc-alpha/2019-07/msg00280.html
[3] https://sourceware.org/ml/libc-alpha/2019-08/msg00065.html
[4] https://github.com/torvalds/linux/commit/432c6bacbd0c16ec210c43da411ccc3855c4c010
[5] https://gcc.gnu.org/ml/gcc-patches/2019-08/msg00254.html

2019-08-20  Dragan Mladjenovic  <dmladjenovic@wavecomp.com>

	* sysdeps/mips/Makefile (CFLAGS-.o*, ASFLAGS-.o*): New rules.
	Apply -Wa,-execstack if mips-force-execstack == yes.
	* sysdeps/mips/configure: Regenerated.
	* sysdeps/mips/configure.ac (mips-force-execstack): New var.
	Set to yes for minimum_kernel < 4.8.0, hard-float, Linux builds.
	(mips-has-gnustack): New var.
	Use value of libc_cv_as_noexecstack if mips-force-execstack != yes,
	otherwise set to no.
	* sysdeps/unix/sysv/linux/mips/Makefile (test-xfail-check-execstack):
	Move under mips-has-gnustack != yes.
---
 sysdeps/mips/Makefile                 | 12 ++++++++++++
 sysdeps/mips/configure.ac             | 28 ++++++++++++++++++++++++++++
 sysdeps/unix/sysv/linux/mips/Makefile |  9 ++++-----
 3 files changed, 44 insertions(+), 5 deletions(-)

Comments

Joseph Myers Aug. 20, 2019, 3:07 p.m. UTC | #1
On Tue, 20 Aug 2019, Dragan Mladjenovic wrote:

> diff --git a/sysdeps/mips/configure.ac b/sysdeps/mips/configure.ac
> index bcbdaff..f0f89ae 100644
> --- a/sysdeps/mips/configure.ac
> +++ b/sysdeps/mips/configure.ac
> @@ -13,3 +13,31 @@ yes
>  if test x$libc_cv_mips_nan2008 = xyes; then
>    AC_DEFINE(HAVE_MIPS_NAN2008)
>  fi
> +
> +# Moved here to allow linux configure fragment to set minimum_kernel
> +# beforehand.

So you have an ordering problem between 
sysdeps/unix/sysv/linux/configure.ac and 
sysdeps/unix/sysv/linux/mips/configure.ac.  But the Linux-specific code

> +AC_CACHE_CHECK([checking whether the compiler must use executable stack],
> +				libc_cv_mips_force_execstack, [dnl
> +libc_cv_mips_force_execstack=no
> +case $os in linux*)
> +  if test x"$libc_mips_float" = xhard -a -n "$minimum_kernel"; then
> +     changequote(,)
> +     min_version=$((`echo "$minimum_kernel.0.0.0" | sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1 \* 65536 + \2 \* 256 + \3/'`))
> +     changequote([,])
> +     if test $min_version -lt 264192; then

doesn't seem appropriate for sysdeps/mips/configure.ac at all; I think the 
ordering issue should be addressed another way.  I think that would be 
simply making sysdeps/unix/sysv/linux/mips/configure.ac handle the case of 
empty minimum_kernel as meaning an old kernel, with a comment saying that 
once the minimum kernel globally is 4.8 or later, all the code relating to 
forcing executable stacks can be removed.  (At that point, the person 
increasing the minimum kernel version will be updating 
sysdeps/unix/sysv/linux/mips/configure.ac anyway to remove the 
arch_minimum_kernel=4.5.0 setting for NaN2008.)

(With all the configure changes in sysdeps/unix/sysv/linux/mips/, I'd 
expect all the Makefile changes to be there as well.)

Patch
diff mbox series

diff --git a/sysdeps/mips/Makefile b/sysdeps/mips/Makefile
index 7ac6fa5..6a9ba90 100644
--- a/sysdeps/mips/Makefile
+++ b/sysdeps/mips/Makefile
@@ -82,3 +82,15 @@  $(objpfx)tst-mode-switch-2: $(shared-thread-library)
 endif
 endif
 endif
+
+ifeq ($(mips-force-execstack),yes)
+CFLAGS-.o += -Wa,-execstack
+CFLAGS-.os += -Wa,-execstack
+CFLAGS-.op += -Wa,-execstack
+CFLAGS-.oS += -Wa,-execstack
+
+ASFLAGS-.o += -Wa,-execstack
+ASFLAGS-.os += -Wa,-execstack
+ASFLAGS-.op += -Wa,-execstack
+ASFLAGS-.oS += -Wa,-execstack
+endif
diff --git a/sysdeps/mips/configure.ac b/sysdeps/mips/configure.ac
index bcbdaff..f0f89ae 100644
--- a/sysdeps/mips/configure.ac
+++ b/sysdeps/mips/configure.ac
@@ -13,3 +13,31 @@  yes
 if test x$libc_cv_mips_nan2008 = xyes; then
   AC_DEFINE(HAVE_MIPS_NAN2008)
 fi
+
+# Moved here to allow linux configure fragment to set minimum_kernel
+# beforehand.
+
+AC_CACHE_CHECK([checking whether the compiler must use executable stack],
+				libc_cv_mips_force_execstack, [dnl
+libc_cv_mips_force_execstack=no
+case $os in linux*)
+  if test x"$libc_mips_float" = xhard -a -n "$minimum_kernel"; then
+     changequote(,)
+     min_version=$((`echo "$minimum_kernel.0.0.0" | sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1 \* 65536 + \2 \* 256 + \3/'`))
+     changequote([,])
+     if test $min_version -lt 264192; then
+       libc_cv_mips_force_execstack=yes
+     fi
+  fi
+  ;;
+esac])
+
+libc_mips_has_gnustack=$libc_cv_as_noexecstack
+
+if test $libc_cv_mips_force_execstack = yes; then
+  libc_mips_has_gnustack=no
+  AC_MSG_WARN([forcing executable stack for pre-4.8.0 Linux kernels])
+fi
+
+LIBC_CONFIG_VAR([mips-force-execstack],[${libc_cv_mips_force_execstack}])
+LIBC_CONFIG_VAR([mips-has-gnustack],[${libc_mips_has_gnustack}])
diff --git a/sysdeps/unix/sysv/linux/mips/Makefile b/sysdeps/unix/sysv/linux/mips/Makefile
index 8217f42..e9206fa 100644
--- a/sysdeps/unix/sysv/linux/mips/Makefile
+++ b/sysdeps/unix/sysv/linux/mips/Makefile
@@ -63,13 +63,12 @@  sysdep-dl-routines += dl-static
 
 sysdep_routines += dl-vdso
 endif
-
-# Supporting non-executable stacks on MIPS requires changes to both
-# the Linux kernel and glibc.  See
-# <https://sourceware.org/ml/libc-alpha/2016-01/msg00567.html> and
-# <https://sourceware.org/ml/libc-alpha/2016-01/msg00719.html>.
+# If the compiler doesn't use GNU.stack note,
+# this test is expected to fail.
+ifneq ($(mips-has-gnustack),yes)
 test-xfail-check-execstack = yes
 endif
+endif
 
 ifeq ($(subdir),stdlib)
 gen-as-const-headers += ucontext_i.sym