Initially noticed as a SIGSEGV in dlopen() when error is encountered: https://bugs.gentoo.org/640130 Minimal reproducer: #include <setjmp.h> #include <stdio.h> int main() { jmp_buf jb; volatile register long s0 asm ("$s0"); s0 = 1234; if (setjmp(jb) == 0) longjmp(jb, 1); printf ("$s0 = %lu\n", s0); } Without the fix: $ qemu-mipsn32 -L . ./mips-longjmp-bug $s0 = 1082346228 With the fix: $ qemu-mipsn32 -L . ./mips-longjmp-bug $s0 = 1234 The problem happens in function __sigsetjmp_aux() when --enable-stack-protector=all is enabled. Implementation of __sigsetjmp_aux() assumes it clobber no registers as it's called right from assembly __sigsetjmp. Unfortunately -fstack-protector-all clobbers s0 right at the beginning of the function: Dump of assembler code for function __sigsetjmp_aux: addiu sp,sp,-48 sd gp,32(sp) lui gp,0x18 addu gp,gp,t9 addiu gp,gp,-23968 sd s0,24(sp) ; here we backup s0 lw s0,-27824(gp) ; and load into s0 stack canary address ... sd s0,16(a0) ... The workaround to disable stack protection fixes the failure: --- a/sysdeps/mips/mips64/setjmp_aux.c +++ b/sysdeps/mips/mips64/setjmp_aux.c @@ -25,6 +25,7 @@ access them in C. */ int +inhibit_stack_protector __sigsetjmp_aux (jmp_buf env, int savemask, long long sp, long long fp, long long gp) {
glibc was configured as: ../glibc/configure \ --enable-stack-protector=all \ --enable-stackguard-randomization \ --enable-kernel=3.2.0 \ --enable-add-ons=libidn \ --without-selinux \ --without-cvs \ --disable-werror --enable-bind-now \ --build=x86_64-pc-linux-gnu \ --host=mips64-unknown-linux-gnu \ --disable-profile \ --without-gd \ --with-headers=/usr/mips64-unknown-linux-gnu/usr/include \ --prefix=/usr \ --sysconfdir=/etc \ --localstatedir=/var \ --libdir=$(prefix)/lib32 \ --mandir=$(prefix)/share/man \ --infodir=$(prefix)/share/info \ --libexecdir=$(libdir)/misc/glibc \ --disable-multi-arch \ --disable-systemtap \ --disable-nscd \ --disable-timezone-tools
More details if the above description is not very clear: http://trofi.github.io/posts/205-stack-protection-on-mips64.html
Sent https://sourceware.org/ml/libc-alpha/2017-12/msg00527.html for review.
Created attachment 10694 [details] v2-0001-mips64-fix-clobbering-s0-in-setjmp-BZ-22624.patch mips32 uses almost the same asm->C jump to handle setjmp. Added the same marking to mips32 in v2 patch. Attached.
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GNU C Library master sources". The branch, master has been updated via 368b6c8da9f8ae453f5d70f8a62dbf3f1b6d5995 (commit) from c8e939f12a4fce3bb09a8c4818629ccf76c8658c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=368b6c8da9f8ae453f5d70f8a62dbf3f1b6d5995 commit 368b6c8da9f8ae453f5d70f8a62dbf3f1b6d5995 Author: Sergei Trofimovich <slyfox@gentoo.org> Date: Mon Dec 18 17:23:02 2017 +0000 mips64: fix clobbering s0 in setjmp() [BZ #22624] When configured as --enable-stack-protector=all glibc inserts stack checking canary into every function including __sigsetjmp_aux(). Stack checking code ends up using s0 register to temporary hold address of global canary value. Unfortunately __sigsetjmp_aux assumes no caller' caller-save registers should be clobbered as it stores them as-is. The fix is to disable stack protection of __sigsetjmp_aux. Tested on the following test: #include <setjmp.h> #include <stdio.h> int main() { jmp_buf jb; volatile register long s0 asm ("$s0"); s0 = 1234; if (setjmp(jb) == 0) longjmp(jb, 1); printf ("$s0 = %lu\n", s0); } Without the fix: $ qemu-mipsn32 -L . ./mips-longjmp-bug $s0 = 1082346228 With the fix: $ qemu-mipsn32 -L . ./mips-longjmp-bug $s0 = 1234 [BZ #22624] * sysdeps/mips/mips64/setjmp_aux.c (__sigsetjmp_aux): Use inhibit_stack_protector. ----------------------------------------------------------------------- Summary of changes: ChangeLog | 6 ++++++ sysdeps/mips/mips64/setjmp_aux.c | 5 +++++ 2 files changed, 11 insertions(+), 0 deletions(-)
mips64 patch as submitted to libc-alpha committed. I presume you'll submit the mips32 patch to libc-alpha when ready.
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GNU C Library master sources". The branch, master has been updated via c85c564d1442f0bc09a6c80fca025f004e12d044 (commit) from 368b6c8da9f8ae453f5d70f8a62dbf3f1b6d5995 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=c85c564d1442f0bc09a6c80fca025f004e12d044 commit c85c564d1442f0bc09a6c80fca025f004e12d044 Author: Sergei Trofimovich <slyfox@gentoo.org> Date: Mon Dec 18 18:26:49 2017 +0000 mips32: fix clobbering s0 in setjmp() [BZ #22624] Similar to commit 1ab47db00dfbc0128119e3503d3ed640ffc4830b ("mips64: fix clobbering s0 in setjmp() [BZ #22624]") as sysdeps/mips/setjmp_aux.c is almost an identical copy of sysdeps/mips/mips64/setjmp_aux.c. [BZ #22624] * sysdeps/mips/setjmp_aux.c (__sigsetjmp_aux): Use inhibit_stack_protector. ----------------------------------------------------------------------- Summary of changes: ChangeLog | 4 ++++ sysdeps/mips/setjmp_aux.c | 5 +++++ 2 files changed, 9 insertions(+), 0 deletions(-)
Fixed for 2.27.