about summary refs log tree commit diff
path: root/ports/sysdeps/unix
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2013-12-29 21:16:25 +0000
committerMike Frysinger <vapier@gentoo.org>2013-12-30 23:12:16 -0500
commit98b78b4b72131264b1950edbcd94287041ec8311 (patch)
treefebc663314bcf3ea0680513b11d0db1464bb2820 /ports/sysdeps/unix
parente646a161cef3069fe1a6c92b750a87350630c62d (diff)
downloadglibc-98b78b4b72131264b1950edbcd94287041ec8311.tar.gz
glibc-98b78b4b72131264b1950edbcd94287041ec8311.tar.xz
glibc-98b78b4b72131264b1950edbcd94287041ec8311.zip
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.

URL: https://sourceware.org/bugzilla/show_bug.cgi?id=16372
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'ports/sysdeps/unix')
-rw-r--r--ports/sysdeps/unix/sysv/linux/ia64/Makefile1
-rw-r--r--ports/sysdeps/unix/sysv/linux/ia64/____longjmp_chk.S61
-rw-r--r--ports/sysdeps/unix/sysv/linux/ia64/__longjmp.S8
-rw-r--r--ports/sysdeps/unix/sysv/linux/ia64/sigaltstack-offsets.sym13
4 files changed, 71 insertions, 12 deletions
diff --git a/ports/sysdeps/unix/sysv/linux/ia64/Makefile b/ports/sysdeps/unix/sysv/linux/ia64/Makefile
index d9a35a7c67..bbfd6a2392 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 f4ce5d3a3c..ccaf3ccf84 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,13 +31,58 @@ longjmp_msg:
 
 #define __longjmp ____longjmp_chk
 
-#define CHECK_RSP(reg) \
-	cmp.ltu p0, p8 = reg, r12;				\
-(p8)	br.cond.dpnt .Lok;;					\
-	addl r28 = @ltoffx(longjmp_msg#), r1;;			\
-	ld8.mov r28 = [r28], longjmp_msg#;;			\
-	ld8 out0 = [r28];					\
+/* 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 ((sizeSS + 31) & -32)
+
+/* 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 loc0 = [in0];					\
+	;;							\
+	/* First see if target stack is within current one.  */	\
+	cmp.ltu p0, p8 = loc0, r12;				\
+(p8)	br.cond.dptk.many .Lok;					\
+								\
+	/* Check if it's an alternative signal stack.  */	\
+	mov out0 = r0;						\
+	add 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 .Lok;					\
+	/* Move stack_t into regs.  */				\
+	add r14 = oSS_FLAGS, r12;	/* ss_flags */		\
+	add r15 = oSS_SIZE, r12;	/* ss_size */		\
+	ld8 r16 = [r12];		/* ss_sp */		\
+	;;							\
+	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.spnt .Lfail;					\
+	/* Verify target is within alternative stack.  */	\
+	cmp.gtu p7, p0 = loc0, r16;				\
+(p7)	br.cond.spnt .Lfail;					\
+	;;							\
+	cmp.ltu p0, p8 = loc0, r19;				\
+(p8)	br.cond.sptk.many .Lok;					\
+	;;							\
+								\
+	/* Still here?  Abort!  */				\
+.Lfail:								\
+	add r12 = STACK_SPACE, r12;				\
+	addl loc0 = @ltoffx(longjmp_msg#), r1;;			\
+	ld8.mov loc0 = [loc0], longjmp_msg#;;			\
+	ld8 out0 = [loc0];					\
 	br.call.sptk.many b0 = HIDDEN_JUMPTARGET(__fortify_fail)#;; \
-.Lok:
+.Lok:								\
+	add r12 = STACK_SPACE, r12;
 
 #include "__longjmp.S"
diff --git a/ports/sysdeps/unix/sysv/linux/ia64/__longjmp.S b/ports/sysdeps/unix/sysv/linux/ia64/__longjmp.S
index 4860a8caef..4968802ae9 100644
--- a/ports/sysdeps/unix/sysv/linux/ia64/__longjmp.S
+++ b/ports/sysdeps/unix/sysv/linux/ia64/__longjmp.S
@@ -42,9 +42,10 @@
 
 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
+	alloc r8=ar.pfs,2,0,0,0
 #endif
 	mov r27=ar.rsc
 	add r2=0x98,in0		// r2 <- &jmpbuf.orig_jmp_buf_addr
@@ -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],32		// 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 0000000000..f73446941a
--- /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