Bug 22624 - MIPS setjmp() saves incorrect 'o0' register in --enable-stack-protector=all
Summary: MIPS setjmp() saves incorrect 'o0' register in --enable-stack-protector=all
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.27
: P2 normal
Target Milestone: 2.27
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-12-17 09:46 UTC by Sergei Trofimovich
Modified: 2018-03-31 12:39 UTC (History)
3 users (show)

See Also:
Host: mips*-unknown-linux-gnu
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments
v2-0001-mips64-fix-clobbering-s0-in-setjmp-BZ-22624.patch (1.04 KB, patch)
2017-12-18 14:34 UTC, Sergei Trofimovich
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Sergei Trofimovich 2017-12-17 09:46:24 UTC
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)
 {
Comment 1 Sergei Trofimovich 2017-12-17 09:47:44 UTC
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
Comment 2 Sergei Trofimovich 2017-12-17 09:48:22 UTC
More details if the above description is not very clear: http://trofi.github.io/posts/205-stack-protection-on-mips64.html
Comment 3 Sergei Trofimovich 2017-12-17 10:03:24 UTC
Sent https://sourceware.org/ml/libc-alpha/2017-12/msg00527.html for review.
Comment 4 Sergei Trofimovich 2017-12-18 14:34:41 UTC
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.
Comment 5 Sourceware Commits 2017-12-18 17:24:27 UTC
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(-)
Comment 6 jsm-csl@polyomino.org.uk 2017-12-18 18:16:54 UTC
mips64 patch as submitted to libc-alpha committed.  I presume you'll 
submit the mips32 patch to libc-alpha when ready.
Comment 7 Sourceware Commits 2017-12-18 18:27:51 UTC
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(-)
Comment 8 Joseph Myers 2017-12-18 18:28:52 UTC
Fixed for 2.27.