Box64 Seems Failing to Handle `.init_array`
Coekjan opened this issue · comments
Description
These days, I tried to run my simple x64 applications with box64 on rv64gc platform. Box64 did run my simple hello-world program with all used libraries wrapped (e.g. libc), but failed to run my hash program with some libraries emulated (e.g. libcrypto). Here is my hash program:
/* test.c */
#include <stdio.h>
#include <openssl/sha.h>
const char *hello = "Hello World";
int main() {
unsigned char hash[SHA_DIGEST_LENGTH];
SHA1((unsigned char *)hello, sizeof(hello) - 1, hash);
for (int i = 0; i < SHA_DIGEST_LENGTH; i++) {
printf("%02x", hash[i]);
}
return 0;
}
I compiled this program with gcc test.c -o test -lssl -lcrypto
, and run BOX64_PREFER_EMULATED=1 ./box64 ./test
. It emited the log:
the log
Dynarec for RISC-V With extension: I M A F D C Zba Zbb Zbc Zbs Vector PageSize:4096 Running on Unknown CPU with 16 Cores Will use Hardware counter measured at 2.3 GHz Params database has 14 entries Box64 with Dynarec v0.2.9 cb064f9e built on Jun 29 2024 21:39:07 BOX64: Didn't detect 48bits of address space, considering it's 39bits Counted 119 Env var BOX64 LIB PATH: /usr/riscv64-linux-gnu/lib/:/lib/:./:lib/:lib64/:x86_64/:bin64/:libs64/ BOX64 BIN PATH: (( omitted )) Looking for test Rename process to "test" Error initializing native libssl.so.3 (last dlerror is libssl.so.3: cannot open shared object file: No such file or directory) Using emulated /lib/libssl.so.3 Error initializing native libcrypto.so.3 (last dlerror is libcrypto.so.3: cannot open shared object file: No such file or directory) Using emulated /lib/libcrypto.so.3 Using native(wrapped) libc.so.6 Using native(wrapped) ld-linux-x86-64.so.2 Using native(wrapped) libpthread.so.0 Using native(wrapped) libdl.so.2 Using native(wrapped) libutil.so.1 Using native(wrapped) libresolv.so.2 Using native(wrapped) librt.so.1 Using native(wrapped) libbsd.so.0 FillBlock triggered a segfault at 0x4d100 from 0x3528682a FillBlock at 0x4d100 triggered a segfault, canceling 393292|SIGSEGV @0x351b2a96 (???(test+0x9b2a96)) (x64pc=0x4d100/???:"???", rsp=0x7470313fe1f8, stack=0x747030c00000:0x747031400000 own=(nil) fp=0x7470313fe200), for accessing 0x4d100 (code=1/prot=87), db=(nil)((nil):(nil)/(nil):(nil)/???:clean, hash:0/0) handler=(nil) RSP-0x20:0x00007470313fe200 RSP-0x18:0x0000000000000000 RSP-0x10:0x0000003f0104c01b RSP-0x08:0x0000000000000000 RSP+0x00:0x0000000000010080 RSP+0x08:0x0000000000000000 RSP+0x10:0x0000000000000001 RSP+0x18:0x00007470313fe6e1 RAX:0x0000000002d82203 RCX:0x0000000000000000 RDX:0x00007470313fe220 RBX:0x0000000000000000 RSP:0x00007470313fe1f8 RBP:0x00007470313fe200 RSI:0x00007470313fe210 RDI:0x0000000000000001 R8:0x0000000000000000 R9:0x02d8220300000000 R10:0x0000000047888915 R11:0x000000000000000f R12:0x0000000000000000 R13:0x0000000000000000 R14:0x0000000000000000 R15:0x0000000000000000 ES:0x002b CS:0x0033 SS:0x002b DS:0x002b FS:0x0043 GS:0x0053
the log (with `BOX64_LOG=2`)
Debug level is 2 Dynarec for RISC-V With extension: I M A F D C Zba Zbb Zbc Zbs Vector PageSize:4096 Running on Unknown CPU with 16 Cores Will use Hardware counter measured at 2.3 GHz Params database has 14 entries Box64 with Dynarec v0.2.9 cb064f9e built on Jun 29 2024 21:39:07 BOX64: Didn't detect 48bits of address space, considering it's 39bits Setting up canary (for Stack protector) at FS:0x28, value:91314800 Counted 119 Env var Env... (( omitted )) BOX64 LIB PATH: /usr/riscv64-linux-gnu/lib/:/lib/:./:lib/:lib64/:x86_64/:bin64/:libs64/ BOX64 BIN PATH: (( omitted )) Looking for ./test Read 30 Section header Read 13 Program header Loading Sections Table String (idx = 29) Loading SymTab Strings (idx = 28) Loading SymTab (idx = 27) Loading Dynamic (idx = 21) The DT_INIT is at address 0x1000 The DT_FINI is at address 0x11dc The DT_INIT_ARRAY is at address 0x3db0 The DT_INIT_ARRAYSZ is 1 The DT_FINI_ARRAY is at address 0x3db8 The DT_FINI_ARRAYSZ is 1 The DT_GNU_HASH is at address 0x3c0 The DT_VERNEED is at address 0x5a8 The DT_VERNEEDNUM is 2 RelA Table @0x608 (0xd8/0x18) PLT Table @0x6e0 (type=7 0x48/0x18) The GOT.PLT Table is at address 0x3fe8 The GOT Table is at address 0x3fc0..0x3fe8 The PLT Table is at address 0x1020..0x1060 The .gnu.version is at address 0x590 The .text is at address 0x1060, and is 377 big The .eh_frame section is at address 0x2040..0x20bc The .eh_frame_hdr section is at address 0x2018 Loading DynSym Strings (idx = 7) Loading DynSym (idx = 6) Adding "(( omitted ))/test" as #0 in elf collection Elf Addr(v/p)=(nil)/(nil) Memsize=0x4038 (align=0x1000) Elf Stack Memsize=1048576 (align=16) Elf TLS Memsize=0 (align=0) Pre-allocated 0x4038 byte at 0x100000000 for (( omitted ))/test Delta of 0x100000000 (vaddr=(nil)) for Elf "(( omitted ))/test" Mmaping 0x728(0x1000) bytes @0x100000000 for Elf "(( omitted ))/test" Mmaping 0x1e9(0x1000) bytes @0x100001000 for Elf "(( omitted ))/test" Mmaping 0xbc(0x1000) bytes @0x100002000 for Elf "(( omitted ))/test" Allocating 0x3000 (0x100003000/0x288) bytes @0x100003000, will read 0x280 @0x100003db0 for Elf "(( omitted ))/test" Rename process to "test" Program linked with GLIBC 2.34+ Calc stack size, based on 1 elf(s) Stack is @0x765a8b800000 size=0x800000 align=0x10 Allocate a new X86_64 Emu, with EIP=(nil) and Stack=0x765a8b800000/0x800000 Setup X86_64 Emu Grabbing R_X86_64_COPY Relocation(s) in advance for (( omitted ))/test Trying to add "libssl.so.3" to maplib Trying to load "libssl.so.3" Simplified name is "libssl.so.3" Error initializing native libssl.so.3 (last dlerror is libssl.so.3: cannot open shared object file: No such file or directory) Read 27 Section header Read 11 Program header Loading Sections Table String (idx = 26) Loading SymTab Strings (idx = 0) Loading SymTab (idx = 0) Loading Dynamic (idx = 20) The DT_INIT is at address 0x13000 The DT_FINI is at address 0xa0da4 The DT_INIT_ARRAY is at address 0xca730 The DT_INIT_ARRAYSZ is 1 The DT_FINI_ARRAY is at address 0xca738 The DT_FINI_ARRAYSZ is 1 The DT_GNU_HASH is at address 0x310 The DT_VERDEF is at address 0xf138 The DT_VERDEFNUM is 4 The DT_FLAGS is 0xa The DT_VERNEED is at address 0xf1b8 The DT_VERNEEDNUM is 2 RelA Table @0xf2a8 (0x3768/0x18) The GOT Table is at address 0xd3e50..0xd5000 The .gnu.version is at address 0xe82e The .text is at address 0x13020, and is 580995 big The .eh_frame section is at address 0xb7668..0xc9600 The .eh_frame_hdr section is at address 0xb4548 Loading DynSym Strings (idx = 5) Loading DynSym (idx = 4) Elf Addr(v/p)=(nil)/(nil) Memsize=0xd8770 (align=0x1000) Elf Stack Memsize=1048576 (align=16) Elf TLS Memsize=0 (align=0) Pre-allocated 0xd8770 byte at 0x3f00000000 for /lib/libssl.so.3 Delta of 0x3f00000000 (vaddr=(nil)) for Elf "/lib/libssl.so.3" Mmaping 0x12d68(0x13000) bytes @0x3f00000000 for Elf "/lib/libssl.so.3" Mmaping 0x8ddb1(0x8e000) bytes @0x3f00013000 for Elf "/lib/libssl.so.3" Mmaping 0x28600(0x29000) bytes @0x3f000a1000 for Elf "/lib/libssl.so.3" Allocating 0x10000 (0x3f000ca000/0xe040) bytes @0x3f000ca000, will read 0xe000 @0x3f000ca730 for Elf "/lib/libssl.so.3" Adding "/lib/libssl.so.3" as #1 in elf collection Using emulated /lib/libssl.so.3 Trying to add "libcrypto.so.3" to maplib Trying to load "libcrypto.so.3" Simplified name is "libcrypto.so.3" Error initializing native libcrypto.so.3 (last dlerror is libcrypto.so.3: cannot open shared object file: No such file or directory) Read 27 Section header Read 11 Program header Loading Sections Table String (idx = 26) Loading SymTab Strings (idx = 0) Loading SymTab (idx = 0) Loading Dynamic (idx = 20) The DT_INIT is at address 0x4c000 The DT_FINI is at address 0x388d24 The DT_INIT_ARRAY is at address 0x465b90 The DT_INIT_ARRAYSZ is 1 The DT_FINI_ARRAY is at address 0x465b98 The DT_FINI_ARRAYSZ is 1 The DT_GNU_HASH is at address 0x310 The DT_VERDEF is at address 0x48da0 The DT_VERDEFNUM is 8 The DT_FLAGS is 0xa The DT_VERNEED is at address 0x48eb0 The DT_VERNEEDNUM is 1 RelA Table @0x48fc0 (0xee8/0x18) The GOT Table is at address 0x4c49f0..0x4c5000 The .gnu.version is at address 0x46156 The .text is at address 0x4d000, and is 3390755 big The .eh_frame section is at address 0x3faa68..0x464a10 The .eh_frame_hdr section is at address 0x3e670c Loading DynSym Strings (idx = 5) Loading DynSym (idx = 4) Elf Addr(v/p)=(nil)/(nil) Memsize=0x4cacc0 (align=0x1000) Elf Stack Memsize=1048576 (align=16) Elf TLS Memsize=0 (align=0) Pre-allocated 0x4cacc0 byte at 0x3f01000000 for /lib/libcrypto.so.3 Delta of 0x3f01000000 (vaddr=(nil)) for Elf "/lib/libcrypto.so.3" Mmaping 0x4b770(0x4c000) bytes @0x3f01000000 for Elf "/lib/libcrypto.so.3" Mmaping 0x33cd31(0x33d000) bytes @0x3f0104c000 for Elf "/lib/libcrypto.so.3" Mmaping 0xdba10(0xdc000) bytes @0x3f01389000 for Elf "/lib/libcrypto.so.3" Allocating 0x67000 (0x3f01465000/0x65130) bytes @0x3f01465000, will read 0x61ff8 @0x3f01465b90 for Elf "/lib/libcrypto.so.3" Adding "/lib/libcrypto.so.3" as #2 in elf collection Using emulated /lib/libcrypto.so.3 Trying to add "libc.so.6" to maplib Trying to load "libc.so.6" Simplified name is "libc.so.6" Using native(wrapped) libc.so.6 Trying to add "ld-linux-x86-64.so.2" to maplib Trying to load "ld-linux-x86-64.so.2" Simplified name is "ld-linux-x86-64.so.2" Using native(wrapped) ld-linux-x86-64.so.2 Trying to add "libpthread.so.0" to maplib Trying to load "libpthread.so.0" Simplified name is "libpthread.so.0" Using native(wrapped) libpthread.so.0 Trying to add "libdl.so.2" to maplib Trying to load "libdl.so.2" Simplified name is "libdl.so.2" Using native(wrapped) libdl.so.2 Trying to add "libutil.so.1" to maplib Trying to load "libutil.so.1" Simplified name is "libutil.so.1" Using native(wrapped) libutil.so.1 Trying to add "libresolv.so.2" to maplib Trying to load "libresolv.so.2" Simplified name is "libresolv.so.2" Using native(wrapped) libresolv.so.2 Trying to add "librt.so.1" to maplib Trying to load "librt.so.1" Simplified name is "librt.so.1" Using native(wrapped) librt.so.1 Trying to add "libbsd.so.0" to maplib Trying to load "libbsd.so.0" Simplified name is "libbsd.so.0" Using native(wrapped) libbsd.so.0 Created lib and added to maplib => success Created lib and added to maplib => success Created lib and added to maplib => success Created lib and added to maplib => success Created lib and added to maplib => success Created lib and added to maplib => success Created lib and added to maplib => success Created lib and added to maplib => success Trying to add "libc.so.6" to maplib Already present in maplib => success Created lib and added to maplib => success Forcing /lib/libcrypto.so.3 to Bind Now Applying 159 Relocation(s) with Addend for /lib/libcrypto.so.3 bindnow=1, deepbind=0 Forcing /lib/libcrypto.so.3 to Bind Now Created lib and added to maplib => success Trying to add "libcrypto.so.3" to maplib Already present in maplib => success Trying to add "libc.so.6" to maplib Already present in maplib => success Created lib and added to maplib => success Created lib and added to maplib => success Forcing /lib/libssl.so.3 to Bind Now Applying 591 Relocation(s) with Addend for /lib/libssl.so.3 bindnow=1, deepbind=0 Forcing /lib/libssl.so.3 to Bind Now Created lib and added to maplib => success And now export symbols / relocation for (( omitted ))/test... Applying 9 Relocation(s) with Addend for (( omitted ))/test bindnow=0, deepbind=0 Applying 3 PLT Relocation(s) with Addend for (( omitted ))/test bindnow=0, deepbind=0 PLT Resolver injected in plt.got at 0x100003ff8 Calling Init for /lib/libcrypto.so.3 @0x3f0104c000 394474|0x3f011654eb: Calling getenv("OPENSSL_ia32cap") => return 0x0(nil) Run X86 (0x36ecab30), RIP=0x3f011655aa, Stack=0x765a8bffe1d0 is32bits=0 Done Init for /lib/libcrypto.so.3 Calling Init[0] for /lib/libcrypto.so.3 @0x4d100 FillBlock triggered a segfault at 0x4d100 from 0x3528682a FillBlock at 0x4d100 triggered a segfault, canceling Run X86 (0x36ecab30), RIP=0x4d100, Stack=0x765a8bffe1f8 is32bits=0 394474|SIGSEGV @0x351b2a96 (???(./test+0x9b2a96)) (x64pc=0x4d100/???:"???", rsp=0x765a8bffe1f8, stack=0x765a8b800000:0x765a8c000000 own=(nil) fp=0x765a8bffe200), for accessing 0x4d100 (code=1/prot=87), db=(nil)((nil):(nil)/(nil):(nil)/???:clean, hash:0/0) handler=(nil) RSP-0x20:0x0000765a8bffe200 RSP-0x18:0x0000000000000000 RSP-0x10:0x0000003f0104c01b RSP-0x08:0x0000000000000000 RSP+0x00:0x0000000000010080 RSP+0x08:0x0000000000000000 RSP+0x10:0x0000000000000001 RSP+0x18:0x0000765a8bffe6e1 RAX:0x0000000002d82203 RCX:0x0000000000000000 RDX:0x0000765a8bffe220 RBX:0x0000000000000000 RSP:0x0000765a8bffe1f8 RBP:0x0000765a8bffe200 RSI:0x0000765a8bffe210 RDI:0x0000000000000001 R8:0x0000000000000000 R9:0x02d8220300000000 R10:0x0000000047888915 R11:0x000000000000000f R12:0x0000000000000000 R13:0x0000000000000000 R14:0x0000000000000000 R15:0x0000000000000000 ES:0x002b CS:0x0033 SS:0x002b DS:0x002b FS:0x0043 GS:0x0053
Investigation
I investigated the code via gdb, and found that the function RunElfInit
in src/elfs/elfloader.c
called RunFunctionWithEmu
for .init
and functions in .init_array
:
Lines 1108 to 1118 in f9b7464
When this issue happened, the pointer p
is 0x0000003f0104c000
and addr[i]
is 0x4d100
(SEEMS TOO LOW???)
I read /proc/(( the pid ))/maps
and saw
... (( omitted ))
3f00000000-3f000ca000 r--p 00000000 103:09 39607298 /usr/lib/libssl.so.3
3f000ca000-3f000da000 rw-p 00000000 00:00 0
3f01000000-3f01465000 r--p 00000000 103:09 39607296 /usr/lib/libcrypto.so.3
3f01465000-3f014cc000 rw-p 00000000 00:00 0
... (( omitted ))
Here is the problem. The pointer p
was ok because 0x3f0104c000 - 0x3f01000000
is 0x4c000
and objdump -alDS /usr/libcrypto.so.3
told me:
Disassembly of section .init:
000000000004c000 <.init>:
4c000: f3 0f 1e fa endbr64
4c004: 48 83 ec 08 sub $0x8,%rsp
(( omitted ))
However, addr[i]
(value = 0x4d100
) seemed too low! objdump -alDS /usr/libcrypto.so.3
told me:
Disassembly of section .init_array:
0000000000465b90 <.init_array>:
465b90: 00 d1 add %dl,%cl
465b92: 04 00 add $0x0,%al
465b94: 00 00 add %al,(%rax)
...
Here was why addr[i]
is 0x4d100
(actually a 4 bytes value: 0x0004d100
).
Possible Fixes
I think box64 should handle .init_array
properly, for example, relocating the entries in .init_array
.
By the way, I can help to fix it if this is ok.
It is my first time to fix something for box64, so I would appreciate it if you tell me the proper way to fix this bug and guide me how to contribute for box64. Thanks!
Well, as you have see in the code, INIT_ARRAY should be handled properly.
Currently, the value of the array are just translated by the "delta" (difference between loaded memory and physical elf file offset). and this value is called yes.
Regarding your crash, I'm unclear what box64 should do there? delta+ainit_array[i]
is not correct? What should it be then?
The problem comes from
Line 1116 in f9b7464
The address of .init_array
is correctly relocated, but the entries inside it seems not.
I debugged box64 and saw that:
- if the ELF was the program (i.e. my x64 applications) itself, the
addr[i]
was correct enough: the program was loaded to0x0000000100000000
and theaddr[i]
here was0x0000000100001150
. - if the ELF was the shared object (i.e. libcrypto.so, libssl.so), the
addr[i]
was definitely wrong: the shared object was loaded to0x0000003f01000000
but theaddr[i]
here was too low (0x000000000004d100
).
I found that:
- in my x64 app,
.rela.dyn
section contains someR_X86_64_RELATIVE
about.init_array
, so the entries in.init_array
are relocated correctly. - in my
/usr/lib/libcrypto.so.3
,.rela.dyn
section does not contain anyR_X86_64_RELATIVE
, so the entries in.init_array
are not relocated.
2. in my `/usr/lib/libcrypto.so.3`, `.rela.dyn` section does not contain any `R_X86_64_RELATIVE`, so the entries in `.init_array` are not relocated.
This alone does not really help. Is there any section containing a relocation for the .init_array
entries? If so, in which section is it, and what type of relocation is it? (You can probably find some of this using objdump -rR
.)
Also, from the USAGE.md:
Lines 11 to 16 in aeeb9b7
Since this is an ELF loader issue, you should use
BOX64_LOG=3
or BOX64_LOG=DUMP
(these two are functionally equivalent), not just 2
(or DEBUG
).There is also an undocumented
BOX64_DUMP=1
which only enables the dumping of loader informations (with which you can keep the log level at whatever you want). BOX64_LOG=3
is in fact equivalent to BOX64_LOG=2 BOX64_DUMP=1
.
As a side note, on my (x86_64) machine, your test file runs with no issue with my libcrypto
. After analyzing, I found out that my version of the library contains no .init_array
section, only a .init
(which is correctly relocated and executed).
If you want more help for debugging, providing at least which version of the library you have would be useful (along with where/how you downloaded the library, ie. which package manager or url). As it is, I cannot help more with the informations you have given.
Happy to tell you that I have fixed this issue!
I finally found that it was because box64 did not handle .relr.dyn
section, and I tried to handle it (referring to glibc ld.so implementation).
I will send a PR soon.