[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Bug 1886097] [NEW] Error in user-mode calculation of ELF program's brk
From: |
Langston |
Subject: |
[Bug 1886097] [NEW] Error in user-mode calculation of ELF program's brk |
Date: |
Thu, 02 Jul 2020 20:50:41 -0000 |
Public bug reported:
There's a discrepancy between the way QEMU user-mode and Linux calculate
the initial program break for statically-linked binaries. I have a
binary with the following segments:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
EXIDX 0x065a14 0x00075a14 0x00075a14 0x00588 0x00588 R 0x4
PHDR 0x0a3000 0x000a3000 0x000a3000 0x00160 0x00160 R 0x1000
LOAD 0x0a3000 0x000a3000 0x000a3000 0x00160 0x00160 R 0x1000
LOAD 0x000000 0x00010000 0x00010000 0x65fa0 0x65fa0 R E 0x10000
LOAD 0x066b7c 0x00086b7c 0x00086b7c 0x02384 0x02384 RW 0x10000
NOTE 0x000114 0x00010114 0x00010114 0x00044 0x00044 R 0x4
TLS 0x066b7c 0x00086b7c 0x00086b7c 0x00010 0x00030 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x8
GNU_RELRO 0x066b7c 0x00086b7c 0x00086b7c 0x00484 0x00484 R 0x1
LOAD 0x07e000 0x00089000 0x00089000 0x03ff4 0x03ff4 R E 0x1000
LOAD 0x098000 0x00030000 0x00030000 0x01000 0x01000 RW 0x1000
The call to set_brk in Linux's binfmt_elf.c receives these arguments:
set_brk(0xa3160, 0xa3160, 1)
Whereas in QEMU, info->brk gets set to 0x88f00. When the binary is run in QEMU,
it crashes on the second call to brk, whereas it runs fine on real ARM
hardware. I think the trouble is that the program break is set to an address
lower than the virtual address of a LOAD segment (the program headers, in this
case).
I believe that this discrepancy arises because in QEMU, info->brk is
only incremented when the LOAD segment in question has PROT_WRITE. For
this binary, the LOAD segment with write permissions and the highest
virtual address is
LOAD 0x066b7c 0x00086b7c 0x00086b7c 0x02384 0x02384 RW 0x10000
which overlaps with the TLS segment:
TLS 0x066b7c 0x00086b7c 0x00086b7c 0x00010 0x00030 R 0x4
However, the Linux kernel puts the program break after the loadable segment
with the highest virtual address, regardless of flags. So I think the fix is
for QEMU to do the same.
** Affects: qemu
Importance: Undecided
Status: New
--
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1886097
Title:
Error in user-mode calculation of ELF program's brk
Status in QEMU:
New
Bug description:
There's a discrepancy between the way QEMU user-mode and Linux
calculate the initial program break for statically-linked binaries. I
have a binary with the following segments:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
EXIDX 0x065a14 0x00075a14 0x00075a14 0x00588 0x00588 R 0x4
PHDR 0x0a3000 0x000a3000 0x000a3000 0x00160 0x00160 R 0x1000
LOAD 0x0a3000 0x000a3000 0x000a3000 0x00160 0x00160 R 0x1000
LOAD 0x000000 0x00010000 0x00010000 0x65fa0 0x65fa0 R E 0x10000
LOAD 0x066b7c 0x00086b7c 0x00086b7c 0x02384 0x02384 RW 0x10000
NOTE 0x000114 0x00010114 0x00010114 0x00044 0x00044 R 0x4
TLS 0x066b7c 0x00086b7c 0x00086b7c 0x00010 0x00030 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x8
GNU_RELRO 0x066b7c 0x00086b7c 0x00086b7c 0x00484 0x00484 R 0x1
LOAD 0x07e000 0x00089000 0x00089000 0x03ff4 0x03ff4 R E 0x1000
LOAD 0x098000 0x00030000 0x00030000 0x01000 0x01000 RW 0x1000
The call to set_brk in Linux's binfmt_elf.c receives these arguments:
set_brk(0xa3160, 0xa3160, 1)
Whereas in QEMU, info->brk gets set to 0x88f00. When the binary is run in
QEMU, it crashes on the second call to brk, whereas it runs fine on real ARM
hardware. I think the trouble is that the program break is set to an address
lower than the virtual address of a LOAD segment (the program headers, in this
case).
I believe that this discrepancy arises because in QEMU, info->brk is
only incremented when the LOAD segment in question has PROT_WRITE. For
this binary, the LOAD segment with write permissions and the highest
virtual address is
LOAD 0x066b7c 0x00086b7c 0x00086b7c 0x02384 0x02384 RW 0x10000
which overlaps with the TLS segment:
TLS 0x066b7c 0x00086b7c 0x00086b7c 0x00010 0x00030 R 0x4
However, the Linux kernel puts the program break after the loadable segment
with the highest virtual address, regardless of flags. So I think the fix is
for QEMU to do the same.
To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1886097/+subscriptions
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Bug 1886097] [NEW] Error in user-mode calculation of ELF program's brk,
Langston <=