[PATCH v7 2/4] elf: Do not change stack permission on dlopen/dlmopen

Stafford Horne shorne@gmail.com
Mon Jan 6 11:19:04 GMT 2025


On Mon, Jan 06, 2025 at 09:47:29AM +0000, Stafford Horne wrote:
> On Thu, Dec 26, 2024 at 02:57:43PM -0300, Adhemerval Zanella wrote:
> > If some shared library loaded with dlopen/dlmopen requires an executable
> > stack, either implicitly because of a missing GNU_STACK ELF header
> > (where the ABI default flags implies in the executable bit) or explicitly
> > because of the executable bit from GNU_STACK; the loader will try to set
> > the both the main thread and all thread stacks (from the pthread cache)
> > as executable.
> > 
> > Besides the issue where any __nptl_change_stack_perm failure does not
> > undo the previous executable transition (meaning that if the library
> > fails to load, there can be thread stacks with executable stacks), this
> > behavior was used on recent CVE [1] as a vector for RCE.
> > 
> > This patch changes that if a shared library requires an executable
> > stack, and the current stack is not executable, dlopen fails.  The
> > change is done only for dynamically loaded modules, if the program
> > or any dependency requires an executable stack, the loader will still
> > change the main thread before program execution and any thread created
> > with default stack configuration.
> 
> Note,
> 
> This causes an issue on OpenRISC which I found when running machine testing
> for 2.41.  I bisected the issue to this commit.
> 
> Many tests are failing with (example nptl/tst-robust1):
> 
>     libgcc_s.so.1 must be installed for pthread_cancel to work
> 
>     make[2]: Leaving directory '/home/shorne/work/gnu-toolchain/glibc/nptl'
>     FAIL: nptl/tst-robust1
>     original exit status 1
>     Didn't expect signal from child: got `Aborted'
>     make[1]: Leaving directory '/home/shorne/work/gnu-toolchain/glibc'
> 
> I do have libgcc_s.so.1, but dlopen seems to be failing due to having an
> executable stack header.
> 
>     $ readelf -l /home/shorne/work/gnu-toolchain/build-glibc/nptl/tst-robust1
> 
>     Elf file type is DYN (Position-Independent Executable file)
>     Entry point 0x185c
>     There are 9 program headers, starting at offset 52
> 
>     Program Headers:
>       Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
>       PHDR           0x000034 0x00000034 0x00000034 0x00120 0x00120 R   0x4
>       INTERP         0x0042ac 0x000042ac 0x000042ac 0x00018 0x00018 R   0x1
> 	  [Requesting program interpreter: /lib/ld-linux-or1k.so.1]
>       LOAD           0x000000 0x00000000 0x00000000 0x0464c 0x0464c R E 0x2000
>       LOAD           0x005ecc 0x00007ecc 0x00007ecc 0x0028c 0x002f0 RW  0x2000
>       DYNAMIC        0x005f18 0x00007f18 0x00007f18 0x000e8 0x000e8 RW  0x4
>       NOTE           0x00462c 0x0000462c 0x0000462c 0x00020 0x00020 R   0x4
>       GNU_EH_FRAME   0x0042c4 0x000042c4 0x000042c4 0x00094 0x00094 R   0x4
>       GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10 <-- test RW
>       GNU_RELRO      0x005ecc 0x00007ecc 0x00007ecc 0x00134 0x00134 R   0x1
> 
>     $ readelf -l ~/work/openrisc/buildroot/output/target/lib/libgcc_s.so.1 
> 
>     Elf file type is DYN (Shared object file)
>     Entry point 0x0
>     There are 6 program headers, starting at offset 52
> 
>     Program Headers:
>       Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
>       LOAD           0x000000 0x00000000 0x00000000 0x1c348 0x1c348 R E 0x2000
>       LOAD           0x01df04 0x0001ff04 0x0001ff04 0x00208 0x002e4 RW  0x2000
>       DYNAMIC        0x01df10 0x0001ff10 0x0001ff10 0x000f0 0x000f0 RW  0x4
>       GNU_EH_FRAME   0x01b234 0x0001b234 0x0001b234 0x00294 0x00294 R   0x4
>       GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x10  <-- module RWE
>       GNU_RELRO      0x01df04 0x0001ff04 0x0001ff04 0x000fc 0x000fc R   0x1
> 
> I will look to fixing this by seeing if I can get GCC to not need to have an
> executable stack for libgcc_s.so.1.  But it will mean running new glibc with old
> gcc installs may have some issues.
> 
> If you have any suggestions let me know.

I was able to fix this in GCC by marking a .note.GNU-stack in one of the
libgcc helper files that was missing it.

After this the or1k libgcc_s.so.1 file no longer needs an executable stack.  I
will run a few more tests on this before pushing upstream to gcc.

-Stafford

> > [1] https://www.qualys.com/2023/07/19/cve-2023-38408/rce-openssh-forwarded-ssh-agent.txt
> > 
> > Checked on x86_64-linux-gnu and i686-linux-gnu.
> > ---
> >  NEWS                                   |  6 +++
> >  elf/dl-load.c                          | 13 ++---
> >  elf/dl-support.c                       |  4 --
> >  elf/rtld.c                             |  6 ---
> >  elf/tst-execstack.c                    | 62 +++++++++++++++---------
> >  nptl/allocatestack.c                   | 19 --------
> >  sysdeps/generic/ldsodefs.h             | 22 ++-------
> >  sysdeps/mach/hurd/Makefile             |  2 +
> >  sysdeps/mach/hurd/dl-execstack.c       |  1 -
> >  sysdeps/nptl/pthreadP.h                |  6 ---
> >  sysdeps/unix/sysv/linux/Versions       |  3 --
> >  sysdeps/unix/sysv/linux/dl-execstack.c | 67 +-------------------------
> >  sysdeps/unix/sysv/linux/mips/Makefile  |  7 +++
> >  13 files changed, 66 insertions(+), 152 deletions(-)
> [snip]
> 
> -Stafford


More information about the Libc-alpha mailing list