This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc 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]

[PATCH] ia64: longjmp_chk: support signal stacks (BZ 16372)


The sp check has to be moved up to the start of the func since it now
makes a system call and that'll clobber a lot of registers.

If someone who is an expert in ia64 asm code review this for me, that'd
be great ...

Signed-off-by: Mike Frysinger <vapier@gentoo.org>

2013-12-29   Mike Frysinger  <vapier@gentoo.org>

	* sysdeps/unix/sysv/linux/ia64/Makefile (gen-as-const-headers): Add
	sigaltstack-offsets.sym.
	* sysdeps/unix/sysv/linux/ia64/____longjmp_chk.S: Include new
	sigaltstack-offsets.h header.
	(STACK_SPACE): Define.
	(CHECK_RSP): Rewrite to support sigaltstack.
	* sysdeps/unix/sysv/linux/ia64/__longjmp.S: Move CHECK_RSP to top.
	* sysdeps/unix/sysv/linux/ia64/sigaltstack-offsets.sym: New file.
---
 ports/sysdeps/unix/sysv/linux/ia64/Makefile        |  1 +
 .../sysdeps/unix/sysv/linux/ia64/____longjmp_chk.S | 59 ++++++++++++++++++++--
 ports/sysdeps/unix/sysv/linux/ia64/__longjmp.S     |  6 +--
 .../unix/sysv/linux/ia64/sigaltstack-offsets.sym   | 13 +++++
 4 files changed, 72 insertions(+), 7 deletions(-)
 create mode 100644 ports/sysdeps/unix/sysv/linux/ia64/sigaltstack-offsets.sym

diff --git a/ports/sysdeps/unix/sysv/linux/ia64/Makefile b/ports/sysdeps/unix/sysv/linux/ia64/Makefile
index d9a35a7..bbfd6a2 100644
--- a/ports/sysdeps/unix/sysv/linux/ia64/Makefile
+++ b/ports/sysdeps/unix/sysv/linux/ia64/Makefile
@@ -10,6 +10,7 @@ endif
 ifeq ($(subdir),misc)
 sysdep_headers += sys/io.h
 sysdep_routines += ioperm clone2
+gen-as-const-headers += sigaltstack-offsets.sym
 endif
 
 ifeq ($(subdir),elf)
diff --git a/ports/sysdeps/unix/sysv/linux/ia64/____longjmp_chk.S b/ports/sysdeps/unix/sysv/linux/ia64/____longjmp_chk.S
index f4ce5d3..c7a3dab 100644
--- a/ports/sysdeps/unix/sysv/linux/ia64/____longjmp_chk.S
+++ b/ports/sysdeps/unix/sysv/linux/ia64/____longjmp_chk.S
@@ -15,6 +15,8 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <sigaltstack-offsets.h>
+
 	.section .rodata.str1.8,"aMS",@progbits,1
 	.align 8
 .LC0:
@@ -29,9 +31,60 @@ longjmp_msg:
 
 #define __longjmp ____longjmp_chk
 
-#define CHECK_RSP(reg) \
-	cmp.ltu p0, p8 = reg, r12;				\
-(p8)	br.cond.dpnt .Lok;;					\
+/* We use 32 bytes (rather than sizeof(stack_t)) so that we keep the stack
+   properly aligned.  But we still want a sanity check to make sure 32 is
+   actually enough.  */
+#define STACK_SPACE 32
+#if sizeSS > STACK_SPACE
+# error "stack_t size is too big"
+#endif
+
+/* Check the stack pointer held in the jumpbuf.  Make sure it's in either the
+   current stack (r12) or in the signal stack.  */
+#define CHECK_RSP						\
+	ld8 r28 = [in0];					\
+	;;							\
+	/* First see if target stack is within current one.  */	\
+	cmp.ltu p0, p8 = r28, r12;				\
+(p8)	br.cond.dpnt .Lok;					\
+	;;							\
+								\
+	/* Check if it's an alternative signal stack.  */	\
+	mov out0 = r0;						\
+	adds out1 = -STACK_SPACE, r12;				\
+	;;							\
+	mov r12 = out1;						\
+	DO_CALL_VIA_BREAK (SYS_ify (sigaltstack));		\
+	;;							\
+	/* If the syscall failed, then assume it's OK.  */	\
+	cmp.eq p8, p0 = -1, r10;				\
+(p8)	br.cond.spnt.few .Lok;					\
+	;;							\
+	/* Move stack_t into regs and cleanup current stack.  */\
+	adds r14 = 8, r12;		/* ss_flags */		\
+	adds r15 = 16, r12;		/* ss_size */		\
+	ld8 r16 = [r12];		/* ss_sp */		\
+	ld8 r28 = [in0];		/* jmpbuf.sp */		\
+	;;							\
+	adds r12 = STACK_SPACE, r12;				\
+	ld4 r17 = [r14];		/* ss_flags */		\
+	ld8 r18 = [r15];		/* ss_size */		\
+	;;							\
+	sub r19 = r16, r18;		/* sp - size */		\
+	/* See if we're currently on the altstack.  */		\
+	tbit.nz p0, p8 = r17, 0;	/* SS_ONSTACK */	\
+(p8)	br.cond.dpnt .Lfail;					\
+	;;							\
+	/* Verify target is within alternative stack.  */	\
+	cmp.gtu p8, p0 = r28, r16;				\
+(p8)	br.cond.dpnt .Lfail;					\
+	;;							\
+	cmp.ltu p0, p8 = r28, r19;				\
+(p8)	br.cond.dpnt .Lok;					\
+	;;							\
+								\
+	/* Still here?  Abort!  */				\
+.Lfail:								\
 	addl r28 = @ltoffx(longjmp_msg#), r1;;			\
 	ld8.mov r28 = [r28], longjmp_msg#;;			\
 	ld8 out0 = [r28];					\
diff --git a/ports/sysdeps/unix/sysv/linux/ia64/__longjmp.S b/ports/sysdeps/unix/sysv/linux/ia64/__longjmp.S
index 8a70ae2..9b2d07a 100644
--- a/ports/sysdeps/unix/sysv/linux/ia64/__longjmp.S
+++ b/ports/sysdeps/unix/sysv/linux/ia64/__longjmp.S
@@ -42,7 +42,8 @@
 
 LEAF(__longjmp)
 #ifdef CHECK_RSP
-	alloc r8=ar.pfs,2,1,1,0
+	alloc r8=ar.pfs,2,1,3,0
+	CHECK_RSP
 #else
 	alloc r8=ar.pfs,2,1,0,0
 #endif
@@ -79,9 +80,6 @@ LEAF(__longjmp)
 	mov r26=ar.rnat
 	mov ar.unat=r25		// setup ar.unat (NaT bits for r1, r4-r7, and r12)
 	;;
-#ifdef CHECK_RSP
-	CHECK_RSP (r28)
-#endif
 	ld8.fill.nta gp=[r3],16		// r1 (gp)
 	dep r11=-1,r23,3,6	// r11 <- ia64_rse_rnat_addr(jmpbuf.ar_bsp)
 	mov sp=r28		// r12 (sp)
diff --git a/ports/sysdeps/unix/sysv/linux/ia64/sigaltstack-offsets.sym b/ports/sysdeps/unix/sysv/linux/ia64/sigaltstack-offsets.sym
new file mode 100644
index 0000000..f734469
--- /dev/null
+++ b/ports/sysdeps/unix/sysv/linux/ia64/sigaltstack-offsets.sym
@@ -0,0 +1,13 @@
+#include <stddef.h>
+#include <signal.h>
+
+--
+
+#define sigaltstack(member)	offsetof (stack_t, member)
+
+sizeSS				sizeof (stack_t)
+oSS_SP				sigaltstack (ss_sp)
+oSS_FLAGS			sigaltstack (ss_flags)
+oSS_SIZE			sigaltstack (ss_size)
+
+SS_ONSTACK
-- 
1.8.4.3


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