Bug 28990 - ld.so --verify segfaults on cc1 binary on arm 32bit
Summary: ld.so --verify segfaults on cc1 binary on arm 32bit
Status: UNCONFIRMED
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.35
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-03-22 15:27 UTC by Jan Palus
Modified: 2022-03-30 12:50 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
ld.so/cc1 (6.13 MB, application/x-xz)
2022-03-22 15:27 UTC, Jan Palus
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jan Palus 2022-03-22 15:27:34 UTC
Created attachment 14032 [details]
ld.so/cc1

ld.so --verify cc1 segfaults with attached files on arm 32bit (these are arm6hf, but verified behavior is the same also on armv7hf).

For plenty other binaries it works fine, it appears to have issues with those coming from gcc though.
Comment 1 Jan Palus 2022-03-22 15:53:07 UTC
Looks like it might be related to linux kernel 5.17. It appears to work fine with 5.15 and 5.16.

likely not very useful but strace between versions:
5.15:
execve("/lib/ld-linux-armhf.so.3", ["/lib/ld-linux-armhf.so.3", "--verify", "/usr/lib/gcc/armv6hl-pld-linux-g"...], 0x7e8365ac /* 52 vars */) = 0
brk(NULL)                               = 0xd93000
openat(AT_FDCWD, "/usr/lib/gcc/armv6hl-pld-linux-gnueabi/11.2.0/cc1", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\2\0(\0\1\0\0\0P(\32\0004\0\0\0"..., 512) = 512
mmap2(0x10000, 20832256, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0x10000
mmap2(0x13fe000, 98304, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x13de000) = 0x13fe000
mmap2(0x1416000, 945808, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x1416000
close(3)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

5.17:
execve("/lib/ld-linux-armhf.so.3", ["/lib/ld-linux-armhf.so.3", "--verify", "/usr/lib/gcc/armv6hl-pld-linux-g"...], 0x7ec004ec /* 57 vars */) = 0
brk(NULL)                               = 0xc89000
openat(AT_FDCWD, "/usr/lib/gcc/armv6hl-pld-linux-gnueabi/11.2.0/cc1", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\2\0(\0\1\0\0\0P(\32\0004\0\0\0"..., 512) = 512
mmap2(0x10000, 20832256, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0x10000
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x10} ---
Comment 2 Jan Palus 2022-03-23 19:10:25 UTC
It seems to be caused by fixed address 0x10000 used for mmap as seen in strace. With kernel 5.16 plenty of space is available:

/proc/<pid>/maps just before mmap (5.16):
76fc4000-76fed000 r-xp 00000000 b3:02 393320     /lib/ld-linux-armhf.so.3
76ffa000-76ffb000 r-xp 00000000 00:00 0          [sigpage]
76ffb000-76ffc000 r--p 00000000 00:00 0          [vvar]
76ffc000-76ffd000 r-xp 00000000 00:00 0          [vdso]
76ffd000-77000000 rw-p 00029000 b3:02 393320     /lib/ld-linux-armhf.so.3
7efdf000-7f000000 rw-p 00000000 00:00 0          [stack]
ffff0000-ffff1000 r-xp 00000000 00:00 0          [vectors]

/proc/<pid>/maps just before mmap (5.17):
00400000-00429000 r-xp 00000000 b3:02 393320     /lib/ld-linux-armhf.so.3
00439000-0043c000 rw-p 00029000 b3:02 393320     /lib/ld-linux-armhf.so.3
76ffd000-76ffe000 r-xp 00000000 00:00 0          [sigpage]
76ffe000-76fff000 r--p 00000000 00:00 0          [vvar]
76fff000-77000000 r-xp 00000000 00:00 0          [vdso]
7efdf000-7f000000 rw-p 00000000 00:00 0          [stack]
ffff0000-ffff1000 r-xp 00000000 00:00 0          [vectors]

so larger binaries (>4MB) start to overlap with first region under 5.17 and result in SIGSEGV. Not sure who's to blame for this situation though.
Comment 3 Jan Palus 2022-03-23 23:46:50 UTC
Address for mmap is defined as "l->l_addr + c->mapstart" where l->l_addr==0 and c->mapstart==0x10000. As far as I can tell the latter comes from ELF so either 5.17 loads binary in wrong place or l->l_addr should be adjusted accordingly. In this code path nothing seems to set l->l_addr to anything but 0 though admittedly this is all way over my head.
Comment 4 Andreas Schwab 2022-03-24 09:04:55 UTC
cc1 is an ET_EXEC, so it can only be loaded at a fixed address.  This looks like a kernel bug if it loads a shared object at such a low address.
Comment 5 Jan Palus 2022-03-30 12:50:19 UTC
For reference kernel issue reported at:

https://bugzilla.kernel.org/show_bug.cgi?id=215734