NetBSD Problem Report #57792

From www@netbsd.org  Sat Dec 23 16:36:30 2023
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits))
	(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id 3E7D91A923C
	for <gnats-bugs@gnats.NetBSD.org>; Sat, 23 Dec 2023 16:36:30 +0000 (UTC)
Message-Id: <20231223163628.4669B1A9241@mollari.NetBSD.org>
Date: Sat, 23 Dec 2023 16:36:28 +0000 (UTC)
From: prlw1@cam.ac.uk
Reply-To: prlw1@cam.ac.uk
To: gnats-bugs@NetBSD.org
Subject: SIGSEGV in ld.elf_so / _rtld_call_ifunc
X-Send-Pr-Version: www-1.0

>Number:         57792
>Category:       lib
>Synopsis:       SIGSEGV in ld.elf_so / _rtld_call_ifunc
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Dec 23 16:40:00 +0000 2023
>Last-Modified:  Mon Jul 15 16:10:01 +0000 2024
>Originator:     Patrick Welche
>Release:        NetBSD-10.99.10/amd64 / pkgsrc-current 2023-12-23
>Organization:
>Environment:
>Description:
Starting program: /tmp/pkgsrc/x11/gtk4/work.x86_64/gtk-4.12.4/output/tmp-introspect31yl1w3c/Gdk-4.0 

Program received signal SIGSEGV, Segmentation fault.
_rtld_call_ifunc (obj=0x7f7ff7ee7400, mask=mask@entry=0x7f7fffffe4f0, 
    cur_objgen=cur_objgen@entry=1) at /usr/src/libexec/ld.elf_so/reloc.c:311
311                             *where = target;
(gdb) bt
#0  _rtld_call_ifunc (obj=0x7f7ff7ee7400, mask=mask@entry=0x7f7fffffe4f0, 
    cur_objgen=cur_objgen@entry=1) at /usr/src/libexec/ld.elf_so/reloc.c:311
#1  0x00007f7ff7ef3284 in _rtld_call_ifunc_functions (cur_objgen=1, 
    obj=<optimized out>, mask=0x7f7fffffe4f0)
    at /usr/src/libexec/ld.elf_so/rtld.c:280
#2  _rtld_call_init_functions (mask=mask@entry=0x7f7fffffe4f0)
    at /usr/src/libexec/ld.elf_so/rtld.c:304
#3  0x00007f7ff7ef3de5 in _rtld (sp=<optimized out>, relocbase=<optimized out>)
    at /usr/src/libexec/ld.elf_so/rtld.c:795
#4  0x00007f7ff7eed033 in rtld_start () from /usr/libexec/ld.elf_so
#5  0x0000000000000000 in ?? ()
(gdb) list
306                     _rtld_exclusive_enter(mask);
307     #ifdef __sparc__
308                     sparc_write_branch(where2 + 1, (void *)target);
309     #else
310                     if (*where != target)
311                             *where = target;
312     #endif
313             }
314
315             while (obj->ifunc_remaining_nonplt > 0 && _rtld_objgen == cur_objgen) {
(gdb) print target
$1 = 140187593839377 = 0x7F7FF7BB9311
(gdb) print where
$2 = (Elf64_Addr *) 0x7f7ff7ed64c8 <*ABS*@got.plt>
(gdb) print *where
$3 = 140187589897974 = 0x7F7FF77F6EF6
(gdb) x 0x7F7FF7BB9311
0x7f7ff7bb9311 <float_to_half_f16c>:    0x8e0fd285
(gdb) x 0x7f7ff7ed64c8
0x7f7ff7ed64c8 <*ABS*@got.plt>: 0xf77f6ef6
(gdb) x 0x7F7FF77F6EF6
0x7f7ff77f6ef6 <*ABS*+0x46f2a0@plt+6>:  0x00088268
(gdb) frame 2
#2  _rtld_call_init_functions (mask=mask@entry=0x7f7fffffe4f0) at /usr/src/libexec/ld.elf_so/rtld.c:304
304                     if (_rtld_call_ifunc_functions(mask, elm->obj, cur_objgen)) {
(gdb) list
299             SIMPLEQ_INIT(&initlist);
300             _rtld_initlist_tsort(&initlist, 0);
301
302             /* First pass: objects with IRELATIVE relocations. */
303             SIMPLEQ_FOREACH(elm, &initlist, link) {
304                     if (_rtld_call_ifunc_functions(mask, elm->obj, cur_objgen)) {
305                             dbg(("restarting init iteration"));
306                             _rtld_objlist_clear(&initlist);
307                             goto restart;
308                     }
(gdb) print *elm->obj
$11 = {next = 0x7f7ff7ee7800, 
  path = 0x7f7ff7ee8080 "/tmp/pkgsrc/x11/gtk4/work.x86_64/gtk-4.12.4/output/gtk/libgtk-4.so.1", refcount = 1, 
  dl_refcount = 0, mapbase = 0x7f7ff774a000 "\177ELF\002\001\001\003", mapsize = 7966720, textsize = 675840, 
  vaddrbase = 0, relocbase = 0x7f7ff774a000 "\177ELF\002\001\001\003", dynamic = 0x7f7ff7ed2168, entry = 0x0, 
  phdr = 0x7f7ff774a040, phsize = 504, pltgot = 0x7f7ff7ed2548, rel = 0x0, rellim = 0x0, rela = 0x7f7ff77b4b38, 
  relalim = 0x7f7ff77e1ec8, pltrel = 0x0, pltrellim = 0x0, pltrela = 0x7f7ff77e1ec8, pltrelalim = 0x7f7ff77eeb40, 
  symtab = 0x7f7ff7755568, strtab = 0x7f7ff77807f8 "", strsize = 198980, buckets = 0x7f7ff774a240, unused1 = 0, 
  chains = 0x7f7ff774e24c, nchains = 7366, rpaths = 0x7f7ff7ee59c0, needed = 0x7f7ff7ee55c0, 
  init = 0x7f7ff77ef000 <_init>, fini = 0x7f7ff7bba460 <_fini>, mainprog = 0, rtld = 0, textrel = 0, 
  symbolic = 1, printed = 0, isdynamic = 1, mainref = 1, globalref = 0, init_done = 1, init_called = 0, 
  fini_called = 0, z_now = 1, z_nodelete = 0, z_initfirst = 0, z_noopen = 0, phdr_loaded = 1, tls_static = 1, 
  tls_dynamic = 0, ref_nodel = 0, sysv_hash = 1, gnu_hash = 0, linkmap = {
    l_addr = 0x7f7ff774a000 "\177ELF\002\001\001\003", 
    l_name = 0x7f7ff7ee8080 "/tmp/pkgsrc/x11/gtk4/work.x86_64/gtk-4.12.4/output/gtk/libgtk-4.so.1", 
    l_ld = 0x7f7ff7ed2168, l_next = 0x7f7ff7ee7908, l_prev = 0x7f7ff7ee7108}, interp = 0x0, dldags = {
    sqh_first = 0x0, sqh_last = 0x7f7ff7ee7538}, dagmembers = {sqh_first = 0x0, sqh_last = 0x7f7ff7ee7548}, 
  dev = 43778, ino = 82350959332080029, ehdr = 0x7f7ff7ee3000, nbuckets = 4099, nbuckets_m = 4288680445, 
  nbuckets_s1 = 1 '\001', nbuckets_s2 = 12 '\f', buckets_gnu = 0x0, nbuckets_gnu = 0, nbuckets_m_gnu = 0, 
  nbuckets_s1_gnu = 0 '\000', nbuckets_s2_gnu = 0 '\000', chains_gnu = 0x0, bloom_gnu = 0x0, symndx_gnu = 0, 
  mask_bm_gnu = 0, shift2_gnu = 0, pathlen = 68, names = {sqh_first = 0x7f7ff7ee6040, sqh_last = 0x7f7ff7ee6040}, 
  tlsindex = 0, tlsinit = 0x0, tlsinitsize = 0, tlssize = 0, tlsoffset = 0, tlsalign = 0, 
  relro_page = 0x7f7ff7eb8840, relro_size = 124864, verneed = 0x7f7ff77b4ac8, verneednum = 3, verdef = 0x0, 
  verdefnum = 0, versyms = 0x7f7ff77b113c, vertab = 0x7f7ff63f3000, vertabnum = 6, init_array = 0x7f7ff7eb8840, 
  init_arraysz = 3, fini_array = 0x0, fini_arraysz = 0, ifunc_remaining = 2, ifunc_remaining_nonplt = 0, 
  cxa_refcount = 0}

>How-To-Repeat:
On NetBSD-current/amd64, HAVE_GCC=12 (probably not necessary), with pkgsrc-current, set 'export GI_SCANNER_DEBUG="save-temps"' and try to build x11/gtk4. The environment variable will stop unlinking the evidence.

It will fail with
Command '['/tmp/pkgsrc/x11/gtk4/work.x86_64/gtk-4.12.4/output/tmp-introspect31yl1w3c/Gdk-4.0', '--introspect-dump=/tmp/pkgsrc/
x11/gtk4/work.x86_64/gtk-4.12.4/output/tmp-introspect31yl1w3c/functions.txt,/tmp/pkgsrc/x11/gtk4/work.x86_64/gtk-4.12.4/output
/tmp-introspect31yl1w3c/dump.xml']' died with <Signals.SIGSEGV: 11>.

# file Gdk-4.0
Gdk-4.0: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /usr/libexec/ld.elf_so, for
NetBSD 10.99.10, with debug_info, not stripped
# file ../gtk/libgtk-4.so.1.1200.4
libgtk-4.so.1.1200.4: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, for NetBSD 10.99.10, with debug_info, not stripped

# env LD_LIBRARY_PATH=/tmp/pkgsrc/x11/gtk4/work.x86_64/gtk-4.12.4/output/gtk ./Gdk-4.0
[1]   Segmentation fault (core dumped) env LD_LIBRARY_PATH=/tmp/pkgsrc/x11/gtk4/work.x86_64/gtk-4.12.4/output/gtk ./Gdk-4.0

Gdk-4.0 is built by the gnome module of mesonbuild. Apparently simply running kills ld.so_elf as it tries to load the freshly built libgtk?!
>Fix:

>Audit-Trail:
From: Patrick Welche <prlw1@talktalk.net>
To: gnats-bugs@netbsd.org
Cc: 
Subject: Re: lib/57792: SIGSEGV in ld.elf_so / _rtld_call_ifunc
Date: Sun, 24 Dec 2023 17:17:59 -0600

 Just repeated the experiment with LD_DEBUG:
 sp = 0x7f7fffffe6c0, argc = 1, argv = 0x7f7fffffe6d8 <./Gdk-4.0> relocbase 0x7f7ff7ee8000
 ...
 headers: digesting PT_DYNAMIC at 0x7f7ff7efdba0
   d_tag 16 at 0x7f7ff7efdba0
   d_tag 4 at 0x7f7ff7efdbb0
   d_tag 5 at 0x7f7ff7efdbc0
   d_tag 6 at 0x7f7ff7efdbd0
   d_tag 10 at 0x7f7ff7efdbe0
   d_tag 11 at 0x7f7ff7efdbf0
   d_tag 7 at 0x7f7ff7efdc00
   d_tag 8 at 0x7f7ff7efdc10
   d_tag 9 at 0x7f7ff7efdc20
   d_tag 1879048185 at 0x7f7ff7efdc30
  added path "/usr/lib"

 Does that last d_tag look strangely large?

From: RVP <rvp@SDF.ORG>
To: gnats-bugs@netbsd.org
Cc: 
Subject: Re: lib/57792: SIGSEGV in ld.elf_so / _rtld_call_ifunc
Date: Tue, 26 Dec 2023 23:51:11 +0000 (UTC)

 On Mon, 25 Dec 2023, Patrick Welche wrote:

 > Just repeated the experiment with LD_DEBUG:
 > sp = 0x7f7fffffe6c0, argc = 1, argv = 0x7f7fffffe6d8 <./Gdk-4.0> relocbase 0x7f7ff7ee8000
 > ...
 > headers: digesting PT_DYNAMIC at 0x7f7ff7efdba0
 >   d_tag 16 at 0x7f7ff7efdba0
 >   d_tag 4 at 0x7f7ff7efdbb0
 >   d_tag 5 at 0x7f7ff7efdbc0
 >   d_tag 6 at 0x7f7ff7efdbd0
 >   d_tag 10 at 0x7f7ff7efdbe0
 >   d_tag 11 at 0x7f7ff7efdbf0
 >   d_tag 7 at 0x7f7ff7efdc00
 >   d_tag 8 at 0x7f7ff7efdc10
 >   d_tag 9 at 0x7f7ff7efdc20
 >   d_tag 1879048185 at 0x7f7ff7efdc30
 >  added path "/usr/lib"
 >
 > Does that last d_tag look strangely large?
 >

 That's `DT_RELACOUNT':

 ```
 $ fgrep DT_RELACOUNT /usr/src/external/bsd/elftoolchain/
 /usr/src/external/bsd/elftoolchain/dist/common/sys/elfconstants.m4:_(`DT_RELACOUNT',        0x6FFFFFF9UL,
 $
 ```

 I think what's happening here is the dynamic linker _not_ doing a
 mprotect(PROT_WRITE) before it goes to patch the ifunc addresses
 in an _executable_ (shared libs seem fine) built with RELRO+NOW:

 ```
 $ cat i.c
 #include <stdio.h>

 #define MAGIC 0xdeadbeefLL

 static long long ifunc_helper(void) {
          return MAGIC;
 }

 static void* resolve_ifunc(void) {
          return ifunc_helper;
 }

 static long long ifunc(void) __attribute__((ifunc ("resolve_ifunc")));

 int main(void) {
          printf("calling ifunc\n");
          fflush(stdout);
          return ifunc() != MAGIC;
 }

 $ gcc -Wall -Wextra -Wconversion -o i i.c -Wl,-z,now
 $ ./i || echo FAIL
 calling ifunc		# only -z now works

 $ gcc -Wall -Wextra -Wconversion -o i i.c -Wl,-z,relro
 $ ./i || echo FAIL
 calling ifunc		# only -z relro also works

 $ gcc -Wall -Wextra -Wconversion -o i i.c -Wl,-z,now,-z,relro
 $ ./i || echo FAIL
 Segmentation fault (core dumped)
 FAIL			# -z relro + -z now fails!

 $
 ```

 Unfortunately, src/tests/libexec/ld.elf_so/t_ifunc.c doesn't test
 with RELRO + NOW, otherwise this would've been caught long ago.

 Try compiling the package without `-z now'.

 -RVP

From: "Patrick Welche" <prlw1@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/57792 CVS commit: pkgsrc/x11/gtk4
Date: Tue, 16 Jan 2024 10:00:16 +0000

 Module Name:	pkgsrc
 Committed By:	prlw1
 Date:		Tue Jan 16 10:00:16 UTC 2024

 Modified Files:
 	pkgsrc/x11/gtk4: Makefile distinfo
 Added Files:
 	pkgsrc/x11/gtk4/patches: patch-meson.build

 Log Message:
 gtk4: build workaround for NetBSD with gcc 12

 NetBSD ld.elf_so dumps core with a shlib built with gcc 12 and
 both -z,relro and -z,now. c.f., PR lib/57792

 gtk4 adds both of these flags by default, and fails on either a
 system with a base HAVE_GCC=12, or with GCC_REQD=12.

 With the patch, it can be caused to fail again by setting
 PKGSRC_USE_RELRO=full

 Thank you to RVP for the analysis


 To generate a diff of this commit:
 cvs rdiff -u -r1.39 -r1.40 pkgsrc/x11/gtk4/Makefile
 cvs rdiff -u -r1.17 -r1.18 pkgsrc/x11/gtk4/distinfo
 cvs rdiff -u -r0 -r1.5 pkgsrc/x11/gtk4/patches/patch-meson.build

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/57792 CVS commit: src
Date: Sun, 7 Jul 2024 17:37:33 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Sun Jul  7 17:37:33 UTC 2024

 Modified Files:
 	src/distrib/sets/lists/debug: mi
 	src/distrib/sets/lists/tests: mi
 	src/tests/libexec/ld.elf_so: Makefile

 Log Message:
 t_ifunc: Test with all combinations of {relro, bindnow}.

 PR lib/57792


 To generate a diff of this commit:
 cvs rdiff -u -r1.436 -r1.437 src/distrib/sets/lists/debug/mi
 cvs rdiff -u -r1.1325 -r1.1326 src/distrib/sets/lists/tests/mi
 cvs rdiff -u -r1.21 -r1.22 src/tests/libexec/ld.elf_so/Makefile

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: Taylor R Campbell <riastradh@NetBSD.org>
To: Patrick Welche <prlw1@cam.ac.uk>, RVP <rvp@SDF.ORG>
Cc: gnats-bugs@NetBSD.org, netbsd-bugs@NetBSD.org, joerg@NetBSD.org,
	skrll@NetBSD.org, mrg@NetBSD.org
Subject: Re: lib/57792: SIGSEGV in ld.elf_so / _rtld_call_ifunc
Date: Mon, 15 Jul 2024 16:08:56 +0000

 The following test cases now exhibit the difference:

 /usr/tests/libexec/ld.elf_so/t_ifunc (relro, bind lazily)
 /usr/tests/libexec/ld.elf_so/t_ifunc_now (relro, bind now)

 t_ifunc works; t_ifunc_now crashes.

 Setting a breakpoint on

 https://nxr.netbsd.org/xref/src/libexec/ld.elf_so/reloc.c?r=3D1.118#311

 where t_ifunc_now crashes reveals:

 [t_ifunc]     where =3D  0x55c03018 <*ABS*@got.plt>
 [t_ifunc_now] where =3D 0x1b5e02f10 <*ABS*@got.plt>

 The high-order parts of the addresses -- 0x55c0...., 0x1b5e0.... --
 are ASLR red herrings; it's the low-order parts that are relevant.

 Examining /proc/<pid>/maps reveals:

 0000000055c02000-0000000055c03000 r--p 0000000000002000 2bd:13ede 679572   =
                           /home/riastradh/netbsd/10/obj.amd64/destdir.amd64=
 /usr/tests/libexec/ld.elf_so/t_ifunc
 0000000055c03000-0000000055c04000 rw-p 0000000000000000 00:00 0

 00000001b5e02000-00000001b5e03000 r--p 0000000000002000 2bd:13ede 679575   =
                           /home/riastradh/netbsd/10/obj.amd64/destdir.amd64=
 /usr/tests/libexec/ld.elf_so/t_ifunc_now
 00000001b5e03000-00000001b5e04000 rw-p 0000000000000000 00:00 0

 In both cases, relative to the base address (0x55c00000, 0x1b5e00000),
 page 0x2000 is mapped read-only and page 0x3000 is mapped read/write.

 - In the working case (t_ifunc), the ifunc relocation is in the
   read/write page at 0x3018.

 - In the broken case (t_ifunc_now), the ifunc relocation is in the
   read-only page at 0x2f10.

 readelf shows the following headers and segments:

 $ readelf -a t_ifunc
 ...
  0x0000000000000003 (PLTGOT)             0x3fe8
 ...
 Program Headers:
   Type           Offset             VirtAddr           PhysAddr
                  FileSiz            MemSiz              Flags  Align
   PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                  0x0000000000000230 0x0000000000000230  R      0x8
   INTERP         0x0000000000000270 0x0000000000000270 0x0000000000000270
                  0x0000000000000017 0x0000000000000017  R      0x1
       [Requesting program interpreter: /usr/libexec/ld.elf_so]
   LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                  0x0000000000000c90 0x0000000000000c90  R      0x1000
   LOAD           0x0000000000001000 0x0000000000001000 0x0000000000001000
                  0x0000000000000c6e 0x0000000000000c6e  R E    0x1000
   LOAD           0x0000000000002000 0x0000000000002000 0x0000000000002000
                  0x000000000000052c 0x000000000000052c  R      0x1000
   LOAD           0x0000000000002d38 0x0000000000003d38 0x0000000000003d38
                  0x00000000000003e2 0x0000000000000450  RW     0x1000
 ...
    04     .rodata .eh_frame_hdr .eh_frame=20
    05     .ctors .dtors .jcr .data.rel.ro .dynamic .got .got.plt .data .bss=
 =20
 ...

 $ readelf -a t_ifunc_now
 ...
  0x0000000000000003 (PLTGOT)             0x3ef8
 ...
 Program Headers:
   Type           Offset             VirtAddr           PhysAddr
                  FileSiz            MemSiz              Flags  Align
   PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                  0x0000000000000230 0x0000000000000230  R      0x8
   INTERP         0x0000000000000270 0x0000000000000270 0x0000000000000270
                  0x0000000000000017 0x0000000000000017  R      0x1
       [Requesting program interpreter: /usr/libexec/ld.elf_so]
   LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                  0x0000000000000c90 0x0000000000000c90  R      0x1000
   LOAD           0x0000000000001000 0x0000000000001000 0x0000000000001000
                  0x0000000000000c6e 0x0000000000000c6e  R E    0x1000
   LOAD           0x0000000000002000 0x0000000000002000 0x0000000000002000
                  0x000000000000052c 0x000000000000052c  R      0x1000
   LOAD           0x0000000000002c78 0x0000000000003c78 0x0000000000003c78
                  0x00000000000003da 0x0000000000000450  RW     0x1000
 ...
    04     .rodata .eh_frame_hdr .eh_frame=20
    05     .ctors .dtors .jcr .data.rel.ro .dynamic .got .data .bss=20
 ...

 Someone who has more details of linkers and gots and plts may be able
 to pursue this thread more efficiently than I can at this point.

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.47 2022/09/11 19:34:41 kim Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2024 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.