Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Bug#919921: qemu-user Linux ELF loader fails to handle pure BSS segments

59 views
Skip to first unread message

Ben Hutchings

unread,
Jan 20, 2019, 1:00:03 PM1/20/19
to
Package: qemu-user
Version: 1:3.1+dfsg-2
Severity: normal
Tags: patch

I've been building and testing klibc across many architectures using
qemu-user, and I found that qemu-user fails to load a few programs on
a few architectures, reporting an EINVAL error code. Here's the
"readelf -l" output for one such program:

Elf file type is EXEC (Executable file)
Entry point 0x10000100
There are 5 program headers, starting at offset 52

Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x10000034 0x10000034 0x000a0 0x000a0 R 0x4
INTERP 0x0000d4 0x100000d4 0x100000d4 0x0002a 0x0002a R 0x1
[Requesting program interpreter: /lib/klibc-R7FVdnsTBUFpWPgCV6FR07b-mf8.so]
LOAD 0x000000 0x10000000 0x10000000 0x002f8 0x002f8 R E 0x10000
LOAD 0x010000 0x10020000 0x10020000 0x00000 0x08000 RW 0x10000
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x10

Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .text .rodata .eh_frame
03 .bss
04

The unusual feature of this program, and all the others that failed,
is that there is a LOAD segment with a file-size of 0 (i.e. only BSS,
no initialised data). load_elf_image() will try to mmap() initialised
data for this section even though there is none and a length of 0 is
invalid.

The change that seems to fix this is to skip the mmap() in this case:

--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -2316,11 +2316,13 @@ static void load_elf_image(const char *i
vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
vaddr_len = TARGET_ELF_PAGELENGTH(eppnt->p_filesz + vaddr_po);

- error = target_mmap(vaddr_ps, vaddr_len,
- elf_prot, MAP_PRIVATE | MAP_FIXED,
- image_fd, eppnt->p_offset - vaddr_po);
- if (error == -1) {
- goto exit_perror;
+ if (vaddr_len != 0) {
+ error = target_mmap(vaddr_ps, vaddr_len,
+ elf_prot, MAP_PRIVATE | MAP_FIXED,
+ image_fd, eppnt->p_offset - vaddr_po);
+ if (error == -1) {
+ goto exit_perror;
+ }
}

vaddr_ef = vaddr + eppnt->p_filesz;
--- END ---

-- System Information:
Debian Release: buster/sid
APT prefers unstable-debug
APT policy: (500, 'unstable-debug'), (500, 'stable-updates'), (500, 'unstable'), (500, 'testing'), (500, 'stable'), (1, 'experimental')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 4.19.0-1-amd64 (SMP w/4 CPU cores)
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8), LANGUAGE=en_GB.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages qemu-user depends on:
ii libc6 2.28-3
ii libcapstone3 3.0.5-3
ii libgcc1 1:8.2.0-13
ii libglib2.0-0 2.58.1-2
ii libstdc++6 8.2.0-13
ii zlib1g 1:1.2.11.dfsg-1

Versions of packages qemu-user recommends:
ii qemu-user-static [qemu-user-binfmt] 1:3.1+dfsg-2

Versions of packages qemu-user suggests:
ii sudo 1.8.26-2

-- no debconf information

Michael Tokarev

unread,
Jan 22, 2019, 12:50:03 AM1/22/19
to
Forwarding to qemu-devel@
http://bugs.debian.org/919921

Thanks!

Philippe Mathieu-Daudé

unread,
Jan 22, 2019, 4:50:03 AM1/22/19
to
Hi Ben,
This is probably not the good fix, since now your process doesn't have
anything mapped to use his BSS :)

>> +                error = target_mmap(vaddr_ps, vaddr_len,
>> +                                    elf_prot, MAP_PRIVATE | MAP_FIXED,
>> +                                    image_fd, eppnt->p_offset -
>> vaddr_po);
>> +                if (error == -1) {
>> +                    goto exit_perror;
>> +                }
>>               }
>>                 vaddr_ef = vaddr + eppnt->p_filesz;
>> --- END ---

What about this fix instead, using the segment memory size rather than
the file size:

-- >8 --
@@ -2314,7 +2314,7 @@ static void load_elf_image(const char *image_name,
int image_fd,
vaddr = load_bias + eppnt->p_vaddr;
vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
- vaddr_len = TARGET_ELF_PAGELENGTH(eppnt->p_filesz + vaddr_po);
+ vaddr_len = TARGET_ELF_PAGELENGTH(eppnt->p_memsz + vaddr_po);

error = target_mmap(vaddr_ps, vaddr_len,
elf_prot, MAP_PRIVATE | MAP_FIXED,

Richard Henderson

unread,
Jan 23, 2019, 12:40:02 AM1/23/19
to
Not true. The mapping happens in zero_bss.

> What about this fix instead, using the segment memory size rather than
> the file size:
>
> -- >8 --
> @@ -2314,7 +2314,7 @@ static void load_elf_image(const char *image_name,
> int image_fd,
> vaddr = load_bias + eppnt->p_vaddr;
> vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
> vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
> - vaddr_len = TARGET_ELF_PAGELENGTH(eppnt->p_filesz + vaddr_po);
> + vaddr_len = TARGET_ELF_PAGELENGTH(eppnt->p_memsz + vaddr_po);
>
> error = target_mmap(vaddr_ps, vaddr_len,
> elf_prot, MAP_PRIVATE | MAP_FIXED,

No, there's only filesz bytes in the file. I'd expect zero_bss to map over the
extra that you just mapped, but it doesn't help.


r~

Ben Hutchings

unread,
Oct 7, 2019, 1:40:03 PM10/7/19
to
Is there a reason why my fix can't be applied? Do I need to open a bug
report in Launchpad for this?

Ben.
--
Ben Hutchings - Debian developer, member of kernel, installer and LTS teams
signature.asc

Philippe Mathieu-Daudé

unread,
Oct 7, 2019, 1:50:03 PM10/7/19
to
Hi Ben,
Simply send your patch formally to qemu-...@nongnu.org.

Michael Tokarev

unread,
Jul 22, 2020, 3:40:03 PM7/22/20
to
I see that qemu 4.1 have this commit:
https://salsa.debian.org/qemu-team/qemu/-/commit/d87146bce08d3d2ea6c00025d7ee0bfa77991692

- error = target_mmap(vaddr_ps, vaddr_len,
- elf_prot, MAP_PRIVATE | MAP_FIXED,
- image_fd, eppnt->p_offset - vaddr_po);
- if (error == -1) {
- goto exit_perror;
+ /*
+ * Some segments may be completely empty without any backing file
+ * segment, in that case just let zero_bss allocate an empty buffer
+ * for it.
+ */
+ if (eppnt->p_filesz != 0) {
+ error = target_mmap(vaddr_ps, vaddr_len, elf_prot,
+ MAP_PRIVATE | MAP_FIXED,
+ image_fd, eppnt->p_offset - vaddr_po);
+
+ if (error == -1) {
+ goto exit_perror;
+ }
}


I'm not sure I understand what's going on here. This looks like
a different case to me, maybe we still need to add the suggested
condition (vaddr_len != 0) to the mix?

Thanks,

/mjt

Michael Tokarev

unread,
Apr 24, 2022, 4:50:03 AM4/24/22
to
Control: tag -1 - patch

On Sun, 20 Jan 2019 17:55:00 +0000 Ben Hutchings <b...@decadent.org.uk> wrote:
> Package: qemu-user
> Version: 1:3.1+dfsg-2
> Severity: normal
> Tags: patch
>
> I've been building and testing klibc across many architectures using
> qemu-user, and I found that qemu-user fails to load a few programs on
> a few architectures, reporting an EINVAL error code. Here's the
> "readelf -l" output for one such program:
>
> Elf file type is EXEC (Executable file)
> Entry point 0x10000100
> There are 5 program headers, starting at offset 52

Hi Ben!

I just come across an old qemu-user bugreport. Can you tell whenever this
is still relevant for current qemu (6.x or 7.0)? There were some changes
in that area, and I don't know which program you used for testing.

We had quite some discussion in that bug report, and the last question is
still unanswered.

Removing the tag "patch" for now, because the patch provided does not apply
to qemu anymore.

Thank you!

/mjt
0 new messages