This is the mail archive of the libc-ports@sources.redhat.com mailing list for the libc-ports project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

MIPS ____longjmp_chk update


I've applied this patch to update MIPS ____longjmp_chk in line with the 
changes to some libc versions for alternate signal stack support, so that 
debug/tst-longjmp_chk2 now passes for all three ABIs where it previously 
failed.

I hope that the C code here may make it clearer for port maintainers just 
what the logic (taken from x86 and x86_64) is that the various 
target-specific ____longjmp_chk implementations need for signal stacks.  I 
plan to update ARM, but not other ports (e.g. m68k, alpha, hppa, none of 
which have ____longjmp_chk at present so all of which should currently 
fail to build).  If the initial stack pointer check fails - if it appears 
that longjmp would return to a stack frame that has been left - then there 
is a further check to avoid false positives in the case of jumping from a 
frame on the alternate signal stack to one on the normal stack.  If the 
sigaltstack syscall fails, things are treated as OK as we cannot tell 
whether an alternate signal stack is involved or not.  Otherwise, to be OK 
we must be on the alternate stack (ss.ss_flags & SS_ONSTACK) and the stack 
pointer saved in the jmp_buf must be outside it.  The logic for being 
outside it - at least for stacks growing down - seems to be that ss_sp + 
ss_size counts as inside and ss_sp counts as outside, so you are outside 
(OK) if ss_sp + ss_size - (saved sp) >= ss_size as an *unsigned* 
comparison.

diff --git a/ChangeLog.mips b/ChangeLog.mips
index 9afd961..5ba4297 100644
--- a/ChangeLog.mips
+++ b/ChangeLog.mips
@@ -1,3 +1,11 @@
+2009-08-05  Joseph Myers  <joseph@codesourcery.com>
+
+	* sysdeps/mips/____longjmp_chk.c: Remove.  Replaced by....
+	* sysdeps/unix/sysv/linux/mips/____longjmp_chk.c: This.  New file.
+	* sysdeps/mips/__longjmp.c (__longjmp): Use explicit register
+	variable for env.  Use expansion of CHECK_SP macro for check.
+	* sysdeps/mips/mips64/__longjmp.c (__Longjmp): Likewise.
+
 2009-08-03  Joseph Myers  <joseph@codesourcery.com>
 
 	* sysdeps/unix/sysv/linux/mips/mips32/accept4.c,
diff --git a/sysdeps/mips/____longjmp_chk.c b/sysdeps/mips/____longjmp_chk.c
deleted file mode 100644
index a46ed15..0000000
--- a/sysdeps/mips/____longjmp_chk.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/* Copyright (C) 2009 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, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-#include <stdio.h>
-#define __longjmp ____longjmp_chk
-#define CHECK_SP
-#include <__longjmp.c>
diff --git a/sysdeps/mips/__longjmp.c b/sysdeps/mips/__longjmp.c
index 340485d..2a91771 100644
--- a/sysdeps/mips/__longjmp.c
+++ b/sysdeps/mips/__longjmp.c
@@ -25,19 +25,19 @@
 #endif
 
 void
-__longjmp (env, val_arg)
-     __jmp_buf env;
+__longjmp (env_arg, val_arg)
+     __jmp_buf env_arg;
      int val_arg;
 {
   /* gcc 1.39.19 miscompiled the longjmp routine (as it did setjmp before
      the hack around it); force it to use $a1 for the longjmp value.
      Without this it saves $a1 in a register which gets clobbered
      along the way.  */
+  register struct __jmp_buf_internal_tag *env asm ("a0");
   register int val asm ("a1");
 #ifdef CHECK_SP
   register long sp asm ("$29");
-  if ((long) (env[0].__sp) < sp)
-    __fortify_fail ("longjmp causes uninitialized stack frame");
+  CHECK_SP (env[0].__sp, sp, long);
 #endif
 
 #ifdef __mips_hard_float
diff --git a/sysdeps/mips/mips64/__longjmp.c b/sysdeps/mips/mips64/__longjmp.c
index d7e36ff..99aac01 100644
--- a/sysdeps/mips/mips64/__longjmp.c
+++ b/sysdeps/mips/mips64/__longjmp.c
@@ -27,19 +27,19 @@
 #endif
 
 void
-__longjmp (env, val_arg)
-     __jmp_buf env;
+__longjmp (env_arg, val_arg)
+     __jmp_buf env_arg;
      int val_arg;
 {
   /* gcc 1.39.19 miscompiled the longjmp routine (as it did setjmp before
      the hack around it); force it to use $a1 for the longjmp value.
      Without this it saves $a1 in a register which gets clobbered
      along the way.  */
+  register struct __jmp_buf_internal_tag *env asm ("a0");
   register int val asm ("a1");
 #ifdef CHECK_SP
   register long long sp asm ("$29");
-  if ((long long) (env[0].__sp) < sp)
-    __fortify_fail ("longjmp causes uninitialized stack frame");
+  CHECK_SP (env[0].__sp, sp, long long);
 #endif
 
 #ifdef __mips_hard_float
diff --git a/sysdeps/unix/sysv/linux/mips/____longjmp_chk.c b/sysdeps/unix/sysv/linux/mips/____longjmp_chk.c
new file mode 100644
index 0000000..9db339c
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mips/____longjmp_chk.c
@@ -0,0 +1,42 @@
+/* Copyright (C) 2009 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <signal.h>
+#include <stdio.h>
+#define __longjmp ____longjmp_chk
+#define CHECK_SP(saved_sp, cur_sp, sp_type)				\
+  do {									\
+    sp_type sp_saved = (sp_type) (saved_sp);				\
+    if (sp_saved < (cur_sp))						\
+      {									\
+	struct __jmp_buf_internal_tag *env_save = env_arg;		\
+	int val_save = val_arg;						\
+	stack_t ss;							\
+	int ret = __sigaltstack (NULL, &ss);				\
+	if (ret == 0							\
+	    && (!(ss.ss_flags & SS_ONSTACK)				\
+		|| ((unsigned sp_type) ((sp_type) ss.ss_sp		\
+					+ (sp_type) ss.ss_size		\
+					- sp_saved)			\
+		    < ss.ss_size)))					\
+	  __fortify_fail ("longjmp causes uninitialized stack frame");	\
+	asm volatile ("move %0, %1" : "=r" (env) : "r" (env_save));	\
+	asm volatile ("move %0, %1" : "=r" (val) : "r" (val_save));	\
+      }									\
+  } while (0)
+#include <__longjmp.c>

-- 
Joseph S. Myers
joseph@codesourcery.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]