Bug 25788 - [i386] -fno-omit-frame-pointer in CFLAGS causes test failures, invalid instruction in ld.so
Summary: [i386] -fno-omit-frame-pointer in CFLAGS causes test failures, invalid instru...
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: dynamic-link (show other bugs)
Version: 2.31
: P2 normal
Target Milestone: 2.32
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-04-05 20:39 UTC by Andreas K. Huettel
Modified: 2020-07-31 09:11 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed: 2020-04-06 00:00:00
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andreas K. Huettel 2020-04-05 20:39:04 UTC
-fno-omit-frame-pointer in CFLAGS causes 4 test failures:

FAIL: elf/tst-execstack
FAIL: elf/tst-execstack-needed
FAIL: elf/tst-execstack-prog
FAIL: nptl/tst-execstack

For elf/tst-execstack-prog I*ve dug deeper:

huettel@farino /var/tmp/portage/sys-libs/glibc-2.31-r2/work/build-x86-x86_64-pc-linux-gnu-nptl/elf $ cat tst-execstack-prog.test-result
FAIL: elf/tst-execstack-prog
original exit status 132
huettel@farino /var/tmp/portage/sys-libs/glibc-2.31-r2/work/build-x86-x86_64-pc-linux-gnu-nptl/elf $ cat tst-execstack-prog.out
huettel@farino /var/tmp/portage/sys-libs/glibc-2.31-r2/work/build-x86-x86_64-pc-linux-gnu-nptl/elf $

Looks like an invalid instruction. (Note that this is the -m32 part of our multilib build.)

huettel@farino /var/tmp/portage/sys-libs/glibc-2.31-r2/work/build-x86-x86_64-pc-linux-gnu-nptl/elf $ ../elf/ld.so ./tst-execstack-prog
Ungültiger Maschinenbefehl
huettel@farino /var/tmp/portage/sys-libs/glibc-2.31-r2/work/build-x86-x86_64-pc-linux-gnu-nptl/elf $ ./tst-execstack-prog
DSO called ok (local 0xffed0708, trampoline 0xffed0709)
DSO called ok (local 0xffdbd6d8, trampoline 0xffdbd6d9)

Indeed, it's an invalid instruction, not in the test file but in ld.so !!!

huettel@farino /var/tmp/portage/sys-libs/glibc-2.31-r2/work/build-x86-x86_64-pc-linux-gnu-nptl/elf $ gdb ./ld.so
GNU gdb (Gentoo 9.1 vanilla) 9.1
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://bugs.gentoo.org/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./ld.so...
(gdb) run --inhibit-cache --library-path .. ./tst-execstack-prog
Starting program: /var/tmp/portage/sys-libs/glibc-2.31-r2/work/build-x86-x86_64-pc-linux-gnu-nptl/elf/ld.so --inhibit-cache --library-path .. ./tst-execstack-prog

Program received signal SIGILL, Illegal instruction.
0xf7fe9240 in __GI__dl_make_stack_executable (stack_endp=0xffffc718) at ../sysdeps/unix/sysv/linux/dl-execstack.c:54
54        check_consistency ();
(gdb) bt
#0  0xf7fe9240 in __GI__dl_make_stack_executable (stack_endp=0xffffc718) at ../sysdeps/unix/sysv/linux/dl-execstack.c:54
#1  0xf7fdd4c6 in _dl_map_object_from_fd (name=name@entry=0xffffce94 "./tst-execstack-prog", origname=origname@entry=0x0, fd=<optimized out>, fbp=<optimized out>, realname=<optimized out>, loader=<optimized out>, 
    l_type=<optimized out>, mode=<optimized out>, stack_endp=<optimized out>, nsid=<optimized out>) at dl-load.c:1288
#2  0xf7fdf27b in _dl_map_object (loader=0x0, name=0xffffce94 "./tst-execstack-prog", type=0, trace_mode=0, mode=536870912, nsid=0) at dl-load.c:2218
#3  0xf7fdaa5b in dl_main (phdr=<optimized out>, phnum=8, user_entry=0xffffcb6c, auxv=0xffffcd44) at rtld.c:1277
#4  0xf7feedab in _dl_sysdep_start (start_argptr=0xffffcc10, dl_main=0xf7fd8370 <dl_main>) at ../elf/dl-sysdep.c:252
#5  0xf7fd7e9d in _dl_start_final (arg=0xffffcc10) at rtld.c:449
#6  _dl_start (arg=<optimized out>) at rtld.c:539
#7  0xf7fd70bb in _start ()
(gdb) disassemble
Dump of assembler code for function __GI__dl_make_stack_executable:
   0xf7fe91f0 <+0>:     push   %ebp
   0xf7fe91f1 <+1>:     mov    %esp,%ebp
   0xf7fe91f3 <+3>:     push   %esi
   0xf7fe91f4 <+4>:     call   0xf7ff2ad3 <__x86.get_pc_thunk.si>
   0xf7fe91f9 <+9>:     add    $0x13dcb,%esi
   0xf7fe91ff <+15>:    push   %ebx
   0xf7fe9200 <+16>:    mov    0x8(%ebp),%ebx
   0xf7fe9203 <+19>:    sub    $0x4,%esp
   0xf7fe9206 <+22>:    pushl  -0x560(%esi)
   0xf7fe920c <+28>:    mov    -0x7f4(%esi),%eax
   0xf7fe9212 <+34>:    push   %eax
   0xf7fe9213 <+35>:    neg    %eax
   0xf7fe9215 <+37>:    and    (%ebx),%eax
   0xf7fe9217 <+39>:    push   %eax
   0xf7fe9218 <+40>:    call   0xf7ff1a40 <mprotect>
   0xf7fe921d <+45>:    add    $0x10,%esp
   0xf7fe9220 <+48>:    test   %eax,%eax
   0xf7fe9222 <+50>:    jne    0xf7fe9250 <__GI__dl_make_stack_executable+96>
   0xf7fe9224 <+52>:    movl   $0x0,(%ebx)
   0xf7fe922a <+58>:    orl    $0x1,0x88c(%esi)
   0xf7fe9231 <+65>:    call   0xf7ff2ae0 <__x86.get_pc_thunk.cx>
   0xf7fe9236 <+70>:    add    $0x13d8e,%ecx
   0xf7fe923c <+76>:    sub    %ebx,%ecx
   0xf7fe923e <+78>:    je     0xf7fe9242 <__GI__dl_make_stack_executable+82>
=> 0xf7fe9240 <+80>:    ud2    
   0xf7fe9242 <+82>:    lea    -0x8(%ebp),%esp
   0xf7fe9245 <+85>:    pop    %ebx
   0xf7fe9246 <+86>:    pop    %esi
   0xf7fe9247 <+87>:    pop    %ebp
   0xf7fe9248 <+88>:    ret    
   0xf7fe9249 <+89>:    lea    0x0(%esi,%eiz,1),%esi
   0xf7fe9250 <+96>:    mov    0x968(%esi),%eax
   0xf7fe9256 <+102>:   jmp    0xf7fe9231 <__GI__dl_make_stack_executable+65>
End of assembler dump.


and this is the UD2 in sysdeps/unix/sysv/linux/i386/sysdep.h line 629

Any advice is appreciated.
Comment 1 Andreas K. Huettel 2020-04-05 20:39:51 UTC
PS. Our sys-libs/glibc-2.31-r2 pretty much corresponds to the current tip of the 2.31 release branch.
Comment 2 Sergei Trofimovich 2020-04-06 06:52:07 UTC
Looking at https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/i386/sysdep.h;h=5e3888060b3cb16277971d524f6cf5f0fc4165e7;hb=HEAD#l46 -fno-omit-frame-pointer should just work, but asm statement does not seem to capture all the input and clobber registers:

"""
  46 /* Since GCC 5 and above can properly spill %ebx with PIC when needed,
  47    we can inline syscalls with 6 arguments if GCC 5 or above is used
  48    to compile glibc.  Disable GCC 5 optimization when compiling for
  49    profiling or when -fno-omit-frame-pointer is used since asm ("ebp")
  50    can't be used to put the 6th argument in %ebp for syscall.  */
  51 #if __GNUC_PREREQ (5,0) && !defined PROF && CAN_USE_REGISTER_ASM_EBP
  52 # define OPTIMIZE_FOR_GCC_5
  53 #endif
...
 583 /* Consistency check for position-independent code.  */
 584 #if defined __PIC__ && !defined OPTIMIZE_FOR_GCC_5
 585 # define check_consistency()                         \
 586   ({ int __res;                                      \
 587      __asm__ __volatile__                            \
 588        (LOAD_PIC_REG_STR (cx) ";"                    \
 589         "subl %%ebx, %%ecx;"                         \
 590         "je 1f;"                                     \
 591         "ud2;"                                       \
 592         "1:\n"                                       \
 593         : "=c" (__res));                             \
 594      __res; })
 595 #endif
"""

I'd expect at least "cc" in clobber registers. And maybe some form of "%ebx" as an input register.
Comment 3 Sergei Trofimovich 2020-04-06 07:18:10 UTC
The host compiler is a --enable-default-pie --enable-default-ssp:

$ LANG=C gcc -v
Using built-in specs.
COLLECT_GCC=/usr/bin/gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-pc-linux-gnu/10.0.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /tmp/portage-tmpdir/portage/sys-devel/gcc-10.0.1_pre9999/work/gcc-10.0.1_pre9999/configure --host=x86_64-pc-linux-gnu --build=x86_64-pc-linux-gnu --prefix=/usr --bindir=/usr/x86_64-pc-linux-gnu/gcc-bin/10.0.1 --includedir=/usr/lib/gcc/x86_64-pc-linux-gnu/10.0.1/include --datadir=/usr/share/gcc-data/x86_64-pc-linux-gnu/10.0.1 --mandir=/usr/share/gcc-data/x86_64-pc-linux-gnu/10.0.1/man --infodir=/usr/share/gcc-data/x86_64-pc-linux-gnu/10.0.1/info --with-gxx-include-dir=/usr/lib/gcc/x86_64-pc-linux-gnu/10.0.1/include/g++-v10 --with-python-dir=/share/gcc-data/x86_64-pc-linux-gnu/10.0.1/python --enable-languages=c,c++,go,fortran --enable-obsolete --enable-secureplt --disable-werror --with-system-zlib --enable-nls --without-included-gettext --enable-checking=release --with-bugurl=https://bugs.gentoo.org/ --with-pkgversion='Gentoo 10.0.1_pre9999 p2, commit 705510a708d3642c9c962beb663c476167e4e8a4' --disable-esp --enable-libstdcxx-time --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-multilib --with-multilib-list=m32,m64 --disable-altivec --disable-fixed-point --enable-targets=all --enable-libgomp --disable-libmudflap --disable-libssp --disable-libada --disable-systemtap --enable-vtable-verify --without-zstd --enable-lto --with-isl --disable-isl-version-check --enable-default-pie --enable-default-ssp --disable-bootstrap
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.0.1 20200405 (experimental) (Gentoo 10.0.1_pre9999 p2, commit 705510a708d3642c9c962beb663c476167e4e8a4)
Comment 4 Andreas K. Huettel 2020-04-06 10:52:42 UTC
And this is the compiler that I used (so it's not a gcc-10 issue)

huettel@farino ~ $ LANG=C gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-pc-linux-gnu/9.2.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /var/tmp/portage/sys-devel/gcc-9.2.0-r2/work/gcc-9.2.0/configure --host=x86_64-pc-linux-gnu --build=x86_64-pc-linux-gnu --prefix=/usr --bindir=/usr/x86_64-pc-linux-gnu/gcc-bin/9.2.0 --includedir=/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/include --datadir=/usr/share/gcc-data/x86_64-pc-linux-gnu/9.2.0 --mandir=/usr/share/gcc-data/x86_64-pc-linux-gnu/9.2.0/man --infodir=/usr/share/gcc-data/x86_64-pc-linux-gnu/9.2.0/info --with-gxx-include-dir=/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/include/g++-v9 --with-python-dir=/share/gcc-data/x86_64-pc-linux-gnu/9.2.0/python --enable-languages=c,c++,fortran --enable-obsolete --enable-secureplt --disable-werror --with-system-zlib --enable-nls --without-included-gettext --enable-checking=release --with-bugurl=https://bugs.gentoo.org/ --with-pkgversion='Gentoo 9.2.0-r2 p3' --disable-esp --enable-libstdcxx-time --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-multilib --with-multilib-list=m32,m64 --disable-altivec --disable-fixed-point --enable-targets=all --enable-libgomp --disable-libmudflap --disable-libssp --disable-libada --disable-systemtap --enable-vtable-verify --enable-lto --without-isl --enable-default-pie --enable-default-ssp
Thread model: posix
gcc version 9.2.0 (Gentoo 9.2.0-r2 p3)
Comment 5 H.J. Lu 2020-04-06 12:59:45 UTC
(In reply to Sergei Trofimovich from comment #2)
> Looking at
> https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/
> i386/sysdep.h;h=5e3888060b3cb16277971d524f6cf5f0fc4165e7;hb=HEAD#l46
> -fno-omit-frame-pointer should just work, but asm statement does not seem to
> capture all the input and clobber registers:
> 
> """
>   46 /* Since GCC 5 and above can properly spill %ebx with PIC when needed,
>   47    we can inline syscalls with 6 arguments if GCC 5 or above is used
>   48    to compile glibc.  Disable GCC 5 optimization when compiling for
>   49    profiling or when -fno-omit-frame-pointer is used since asm ("ebp")
>   50    can't be used to put the 6th argument in %ebp for syscall.  */
>   51 #if __GNUC_PREREQ (5,0) && !defined PROF && CAN_USE_REGISTER_ASM_EBP
>   52 # define OPTIMIZE_FOR_GCC_5
>   53 #endif
> ...
>  583 /* Consistency check for position-independent code.  */
>  584 #if defined __PIC__ && !defined OPTIMIZE_FOR_GCC_5
>  585 # define check_consistency()                         \
>  586   ({ int __res;                                      \
>  587      __asm__ __volatile__                            \
>  588        (LOAD_PIC_REG_STR (cx) ";"                    \
>  589         "subl %%ebx, %%ecx;"                         \
>  590         "je 1f;"                                     \
>  591         "ud2;"                                       \
>  592         "1:\n"                                       \
>  593         : "=c" (__res));                             \
>  594      __res; })
>  595 #endif
> """
> 
> I'd expect at least "cc" in clobber registers. And maybe some form of "%ebx"
> as an input register.

This code came from

commit dbfc1e02671b7ed137272af79751b534613a9326
Author: Ulrich Drepper <drepper@redhat.com>
Date:   Tue Feb 8 06:48:30 2005 +0000

    (check_consistency): Define.

At the time, GCC always used EBX as PIC register:

        call    __x86.get_pc_thunk.bx
        addl    $_GLOBAL_OFFSET_TABLE_, %ebx

Since GCC 5 commit:

commit d290bb1d72b5ef24be30d43abcaa17caa387c3c6
Author: Ilya Enkovich <ilya.enkovich@intel.com>
Date:   Thu Jan 29 12:24:06 2015 +0000

    i386-protos.h (ix86_use_pseudo_pic_reg): New.
    
            * config/i386/i386-protos.h (ix86_use_pseudo_pic_reg): New.
            * config/i386/i386.h (PIC_OFFSET_TABLE_REGNUM): Simplify by
            using x86_use_pseudo_pic_reg.
            * config/i386/i386.c (ix86_conditional_register_usage): Remove
            support for fixed PIC register.
            (ix86_use_pseudo_pic_reg): Not static any more.

other registers can be used as PIC register:

        call    __x86.get_pc_thunk.di
        addl    $_GLOBAL_OFFSET_TABLE_, %edi

This check should be disabled for GCC 5.  OPTIMIZE_FOR_GCC_5 should be
replaced with __GNUC_PREREQ (5,0).
Comment 6 H.J. Lu 2020-04-06 13:26:08 UTC
A patch is posted at

https://sourceware.org/pipermail/libc-alpha/2020-April/112552.html