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.
(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.