From 1b519c0ae436480881ab10d5b66a184afa4d4373 Mon Sep 17 00:00:00 2001 From: Nikola Veljkovic Date: Tue, 6 Oct 2015 18:39:49 +0200 Subject: [PATCH] Implement setjmp cookies on MIPS and MIPS64 Bug: http://b/23942752 Change-Id: Ie58892a97b5075d30d7607667251007cda99d38c --- libc/arch-mips/bionic/setjmp.S | 137 ++++++++++++++++++++------------- tests/setjmp_test.cpp | 12 ++- 2 files changed, 94 insertions(+), 55 deletions(-) diff --git a/libc/arch-mips/bionic/setjmp.S b/libc/arch-mips/bionic/setjmp.S index 3ef0f1129..73002e8a8 100644 --- a/libc/arch-mips/bionic/setjmp.S +++ b/libc/arch-mips/bionic/setjmp.S @@ -132,10 +132,9 @@ /* field: byte offset: size: */ /* dynam filler (0*4) 0-4 bytes of rounddown filler, DON'T TOUCH!! often overlays user storage!! */ -#define SC_MAGIC_OFFSET (1*4) /* 4 bytes, identify jmpbuf, first actual field */ -#define SC_FLAG_OFFSET (2*4) /* 4 bytes, savesigs flag */ -#define SC_FPSR_OFFSET (3*4) /* 4 bytes, floating point control/status reg */ +#define SC_FPSR_OFFSET (1*4) /* 4 bytes, floating point control/status reg */ /* following fields are 8-byte aligned */ +#define SC_FLAG_OFFSET (2*4) /* 8 bytes, cookie and savesigs flag, first actual field */ #define SC_MASK_OFFSET (4*4) /* 16 bytes, mips32/mips64 version of sigset_t */ #define SC_SPARE_OFFSET (8*4) /* 8 bytes, reserved for future uses */ @@ -166,6 +165,16 @@ #error _JBLEN is too small #endif +.macro m_mangle_reg_and_store reg, cookie, temp, offset + xor \temp, \reg, \cookie + REG_S \temp, \offset +.endm + +.macro m_unmangle_reg_and_load reg, cookie, temp, offset + REG_L \temp, \offset + xor \reg, \temp, \cookie +.endm + /* * * GPOFF and FRAMESIZE must be the same for all setjmp/longjmp routines @@ -190,36 +199,46 @@ setjmp_common: li t0, ~7 and a0, t0 # round jmpbuf addr DOWN to 8-byte boundary #endif - sw a1, SC_FLAG_OFFSET(a0) # save savesigs flag - beqz a1, 1f # do saving of signal mask? - REG_S ra, RAOFF(sp) # spill state REG_S a0, A0OFF(sp) + + # get the cookie and store it along with the signal flag. + move a0, a1 + jal __bionic_setjmp_cookie_get + REG_L a0, A0OFF(sp) + + REG_S v0, SC_FLAG_OFFSET(a0) # save cookie and savesigs flag + andi t0, v0, 1 # extract savesigs flag + + beqz t0, 1f # do saving of signal mask? + # call sigprocmask(int how ignored, sigset_t* null, sigset_t* SC_MASK(a0)): LA a2, SC_MASK_OFFSET(a0) # gets current signal mask li a0, 0 # how; ignored when new mask is null li a1, 0 # null new mask jal sigprocmask # get current signal mask REG_L a0, A0OFF(sp) - REG_L ra, RAOFF(sp) 1: - li v0, 0xACEDBADE # sigcontext magic number - sw v0, SC_MAGIC_OFFSET(a0) + REG_L gp, GPOFF(sp) # restore spills + REG_L ra, RAOFF(sp) + REG_L t0, SC_FLAG_OFFSET(a0) # move cookie to temp reg + # callee-saved long-sized regs: - REG_S ra, SC_REGS+0*REGSZ(a0) - REG_S s0, SC_REGS+1*REGSZ(a0) - REG_S s1, SC_REGS+2*REGSZ(a0) - REG_S s2, SC_REGS+3*REGSZ(a0) - REG_S s3, SC_REGS+4*REGSZ(a0) - REG_S s4, SC_REGS+5*REGSZ(a0) - REG_S s5, SC_REGS+6*REGSZ(a0) - REG_S s6, SC_REGS+7*REGSZ(a0) - REG_S s7, SC_REGS+8*REGSZ(a0) - REG_S s8, SC_REGS+9*REGSZ(a0) - REG_L v0, GPOFF(sp) - REG_S v0, SC_REGS+10*REGSZ(a0) # save gp - PTR_ADDU v0, sp, FRAMESZ - REG_S v0, SC_REGS+11*REGSZ(a0) # save orig sp + PTR_ADDU v1, sp, FRAMESZ # save orig sp + + # m_mangle_reg_and_store reg, cookie, temp, offset + m_mangle_reg_and_store ra, t0, t1, SC_REGS+0*REGSZ(a0) + m_mangle_reg_and_store s0, t0, t2, SC_REGS+1*REGSZ(a0) + m_mangle_reg_and_store s1, t0, t3, SC_REGS+2*REGSZ(a0) + m_mangle_reg_and_store s2, t0, t1, SC_REGS+3*REGSZ(a0) + m_mangle_reg_and_store s3, t0, t2, SC_REGS+4*REGSZ(a0) + m_mangle_reg_and_store s4, t0, t3, SC_REGS+5*REGSZ(a0) + m_mangle_reg_and_store s5, t0, t1, SC_REGS+6*REGSZ(a0) + m_mangle_reg_and_store s6, t0, t2, SC_REGS+7*REGSZ(a0) + m_mangle_reg_and_store s7, t0, t3, SC_REGS+8*REGSZ(a0) + m_mangle_reg_and_store s8, t0, t1, SC_REGS+9*REGSZ(a0) + m_mangle_reg_and_store gp, t0, t2, SC_REGS+10*REGSZ(a0) + m_mangle_reg_and_store v1, t0, t3, SC_REGS+11*REGSZ(a0) cfc1 v0, $31 @@ -288,36 +307,41 @@ NON_LEAF(siglongjmp, FRAMESZ, ra) li t0, ~7 and a0, t0 # round jmpbuf addr DOWN to 8-byte boundary #endif - lw v0, SC_MAGIC_OFFSET(a0) - li t0, 0xACEDBADE - bne v0, t0, longjmp_botch # jump if error - lw t0, SC_FLAG_OFFSET(a0) # get savesigs flag + move s1, a1 # temp spill + move s0, a0 + + # extract savesigs flag + REG_L s2, SC_FLAG_OFFSET(s0) + andi t0, s2, 1 beqz t0, 1f # restore signal mask? - REG_S a1, A1OFF(sp) # temp spill - REG_S a0, A0OFF(sp) - # call sigprocmask(int how SIG_SETMASK, sigset_t* SC_MASK(a0), sigset_t* null): - LA a1, SC_MASK_OFFSET(a0) # signals being restored + # call sigprocmask(int how SIG_SETMASK, sigset_t* SC_MASK(a0), sigset_t* null): + LA a1, SC_MASK_OFFSET(s0) # signals being restored li a0, 3 # mips SIG_SETMASK li a2, 0 # null jal sigprocmask # restore signal mask - REG_L a0, A0OFF(sp) - REG_L a1, A1OFF(sp) 1: + move t0, s2 # get cookie to temp reg + move a1, s1 + move a0, s0 + # callee-saved long-sized regs: - REG_L ra, SC_REGS+0*REGSZ(a0) - REG_L s0, SC_REGS+1*REGSZ(a0) - REG_L s1, SC_REGS+2*REGSZ(a0) - REG_L s2, SC_REGS+3*REGSZ(a0) - REG_L s3, SC_REGS+4*REGSZ(a0) - REG_L s4, SC_REGS+5*REGSZ(a0) - REG_L s5, SC_REGS+6*REGSZ(a0) - REG_L s6, SC_REGS+7*REGSZ(a0) - REG_L s7, SC_REGS+8*REGSZ(a0) - REG_L s8, SC_REGS+9*REGSZ(a0) - REG_L gp, SC_REGS+10*REGSZ(a0) - REG_L sp, SC_REGS+11*REGSZ(a0) + + # m_unmangle_reg_and_load reg, cookie, temp, offset + # don't restore gp yet, old value is needed for cookie_check call + m_unmangle_reg_and_load ra, t0, t1, SC_REGS+0*REGSZ(a0) + m_unmangle_reg_and_load s0, t0, t2, SC_REGS+1*REGSZ(a0) + m_unmangle_reg_and_load s1, t0, t3, SC_REGS+2*REGSZ(a0) + m_unmangle_reg_and_load s2, t0, t1, SC_REGS+3*REGSZ(a0) + m_unmangle_reg_and_load s3, t0, t2, SC_REGS+4*REGSZ(a0) + m_unmangle_reg_and_load s4, t0, t3, SC_REGS+5*REGSZ(a0) + m_unmangle_reg_and_load s5, t0, t1, SC_REGS+6*REGSZ(a0) + m_unmangle_reg_and_load s6, t0, t2, SC_REGS+7*REGSZ(a0) + m_unmangle_reg_and_load s7, t0, t3, SC_REGS+8*REGSZ(a0) + m_unmangle_reg_and_load s8, t0, t1, SC_REGS+9*REGSZ(a0) + m_unmangle_reg_and_load v1, t0, t2, SC_REGS+10*REGSZ(a0) + m_unmangle_reg_and_load sp, t0, t3, SC_REGS+11*REGSZ(a0) lw v0, SC_FPSR_OFFSET(a0) ctc1 v0, $31 # restore old fr mode before fp values @@ -341,15 +365,22 @@ NON_LEAF(siglongjmp, FRAMESZ, ra) l.d $f28, SC_FPREGS+4*REGSZ_FP(a0) l.d $f30, SC_FPREGS+5*REGSZ_FP(a0) #endif - bne a1, zero, 1f - li a1, 1 # never return 0! -1: - move v0, a1 - j ra # return to setjmp call site -longjmp_botch: - jal longjmperror - jal abort + # check cookie + PTR_SUBU sp, FRAMESZ + REG_S v1, GPOFF(sp) + REG_S ra, RAOFF(sp) + REG_S a1, A1OFF(sp) + move a0, t0 + jal __bionic_setjmp_cookie_check + REG_L gp, GPOFF(sp) + REG_L ra, RAOFF(sp) + REG_L a1, A1OFF(sp) + PTR_ADDU sp, FRAMESZ + + sltiu t0, a1, 1 # never return 0! + xor v0, a1, t0 + j ra # return to setjmp call site END(siglongjmp) ALIAS_SYMBOL(longjmp, siglongjmp) diff --git a/tests/setjmp_test.cpp b/tests/setjmp_test.cpp index 944dac8fb..c75ab512c 100644 --- a/tests/setjmp_test.cpp +++ b/tests/setjmp_test.cpp @@ -221,15 +221,24 @@ TEST(setjmp, setjmp_fp_registers) { #define __JB_SIGFLAG 7 #elif defined(__x86_64) #define __JB_SIGFLAG 8 +#elif defined(__mips__) && defined(__LP64__) +#define __JB_SIGFLAG 1 +#elif defined(__mips__) +#define __JB_SIGFLAG 2 #endif TEST(setjmp, setjmp_cookie) { -#if !defined(__mips__) jmp_buf jb; int value = setjmp(jb); ASSERT_EQ(0, value); +#if defined(__mips__) && !defined(__LP64__) + // round address to 8-byte boundry + uintptr_t jb_aligned = reinterpret_cast(jb) & ~7L; + long* sigflag = reinterpret_cast(jb_aligned) + __JB_SIGFLAG; +#else long* sigflag = reinterpret_cast(jb) + __JB_SIGFLAG; +#endif // Make sure there's actually a cookie. EXPECT_NE(0, *sigflag & ~1); @@ -237,5 +246,4 @@ TEST(setjmp, setjmp_cookie) { // Wipe it out *sigflag &= 1; EXPECT_DEATH(longjmp(jb, 0), ""); -#endif }