#android #segmentation-fault #emulation #qemu
#Android #ошибка сегментации #эмуляция #qemu
Вопрос:
Я запускаю qemu на хосте Ubuntu 18.04 x64 и пытаюсь выполнить пользовательскую эмуляцию динамических двоичных файлов, созданных для Android (для aarch64 или i386), используя Android NDK, но я всегда получаю ошибку segfault. Например:
Строить
$ i686-linux-android28-clang hello_world.c -o hello_world
Проверьте зависимости и пути
$ file ./hello_world
./hello_world: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /system/bin/linker, not stripped
$ readelf -d ./hello_world
Dynamic section at offset 0xef4 contains 24 entries:
Tag Type Name/Value
0x00000003 (PLTGOT) 0x1fdc
0x00000002 (PLTRELSZ) 48 (bytes)
0x00000017 (JMPREL) 0x318
0x00000014 (PLTREL) REL
0x00000015 (DEBUG) 0x0
0x00000006 (SYMTAB) 0x200
0x0000000b (SYMENT) 16 (bytes)
0x00000005 (STRTAB) 0x270
0x0000000a (STRSZ) 96 (bytes)
0x6ffffef5 (GNU_HASH) 0x2d0
0x00000001 (NEEDED) Shared library: [libdl.so]
0x00000001 (NEEDED) Shared library: [libc.so]
...
Скопируйте в распакованный образ эмулятора Android Pixel 2 Android 9 i386.
$ ls ~/android_28_img/
acct cache d dev init.environ.rc init.usb.rc metadata oem sbin sys vendor
bin charger data etc init.rc init.zygote32.rc mnt proc sdcard system
bugreports config default.prop init init.usb.configfs.rc lost found odm product storage ueventd.rc
$ sudo cp ./hello_world ~/android_28_img/system/bin
Скопируйте статический qemu туда же
$ sudo cp /usr/bin/qemu-i386-static ~/android_28_img/system/bin
Запускать эмулятор различными способами
$ sudo chroot /home/user/android_28_img ./system/bin/qemu-i386-static /system/bin/hello_world
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
Segmentation fault
$ qemu-i386 -L /home/user/android_38_img ./system/bin/hello_world
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
Segmentation fault
strace
$ sudo chroot /home/user/android_28_img ./system/bin/qemu-i386-static -strace /system/bin/hello_world
60785 set_thread_area(0xffffa3f0) = 0
60785 mmap2(NULL,20480,PROT_NONE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0xff6a5000
60785 madvise(-9809920,20480,12,-9809920,-8432404,-23672) = 0
60785 prctl(1398164801,0,-9809920,20480,-8681506,-23528) = -1 errno=22 (Invalid argument)
60785 mprotect(0xff6a6000,12288,PROT_READ|PROT_WRITE) = 0
60785 prctl(1398164801,0,-9805824,12288,-8681440,-23528) = -1 errno=22 (Invalid argument)
60785 set_tid_address(-8432484,0,20480,-9781248,-8432492,-23480) = 60785
60785 faccessat(AT_FDCWD,"/dev/urandom",R_OK,AT_SYMLINK_NOFOLLOW|0xff7f601c) = -1 errno=2 (No such file or directory)
60785 futex(0xff7f2a44,FUTEX_PRIVATE_FLAG|FUTEX_WAKE,2147483647,NULL,NULL,0) = 0
60785 sched_getscheduler(0,0,-8432496,-8432492,-8432492,-23528) = 0
60785 mmap2(NULL,20480,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0xff6a0000
60785 madvise(-9830400,20480,12,-9830400,-8432404,-23688) = 0
60785 mprotect(0xff6a0000,4096,PROT_NONE) = 0
60785 sigaltstack(0xffffa3e8,(nil)) = 0
60785 prctl(1398164801,0,-9826304,16384,-8681429,-23528) = -1 errno=22 (Invalid argument)
60785 prctl(1398164801,0,-9830400,4096,-8681409,-23528) = -1 errno=22 (Invalid argument)
60785 mprotect(0xff7eb000,24576,PROT_READ) = 0
60785 mprotect(0xff7f4000,4096,PROT_READ) = 0
60785 mprotect(0xff7f4000,4096,PROT_READ|PROT_WRITE) = 0
60785 mprotect(0xff7f4000,4096,PROT_READ) = 0
60785 mmap2(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0xff69f000
60785 madvise(-9834496,4096,12,-9834496,-8432404,-23848) = 0
60785 prctl(1398164801,0,-9834496,4096,-8680817,-23704) = -1 errno=22 (Invalid argument)
60785 mprotect(0xff69f000,4096,PROT_READ) = 0
60785 mprotect(0xff69f000,4096,PROT_READ|PROT_WRITE) = 0
60785 mprotect(0xff69f000,4096,PROT_READ) = 0
60785 mprotect(0xff69f000,4096,PROT_READ|PROT_WRITE) = 0
60785 mprotect(0xff69f000,4096,PROT_READ) = 0
60785 mprotect(0xff69f000,4096,PROT_READ|PROT_WRITE) = 0
60785 mprotect(0xff69f000,4096,PROT_READ) = 0
60785 mprotect(0xff69f000,4096,PROT_READ|PROT_WRITE) = 0
60785 mprotect(0xff69f000,4096,PROT_READ) = 0
60785 mprotect(0xff69f000,4096,PROT_READ|PROT_WRITE) = 0
60785 mprotect(0xff69f000,4096,PROT_READ) = 0
60785 mprotect(0xff69f000,4096,PROT_READ|PROT_WRITE) = 0
60785 mprotect(0xff69f000,4096,PROT_READ) = 0
60785 mprotect(0xff69f000,4096,PROT_READ|PROT_WRITE) = 0
60785 mprotect(0xff69f000,4096,PROT_READ) = 0
60785 mprotect(0xff69f000,4096,PROT_READ|PROT_WRITE) = 0
60785 mprotect(0xff69f000,4096,PROT_READ) = 0
60785 mprotect(0xff69f000,4096,PROT_READ|PROT_WRITE) = 0
60785 mprotect(0xff69f000,4096,PROT_READ) = 0
60785 mprotect(0xff69f000,4096,PROT_READ|PROT_WRITE) = 0
60785 mprotect(0xff69f000,4096,PROT_READ) = 0
60785 mprotect(0xff69f000,4096,PROT_READ|PROT_WRITE) = 0
60785 mprotect(0xff69f000,4096,PROT_READ) = 0
60785 mprotect(0xff69f000,4096,PROT_READ|PROT_WRITE) = 0
60785 mprotect(0xff69f000,4096,PROT_READ) = 0
60785 mmap2(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0xff69e000
60785 madvise(-9838592,4096,12,-9838592,-8432404,-24136) = 0
60785 prctl(1398164801,0,-9838592,4096,-8693379,-23944) = -1 errno=22 (Invalid argument)
60785 mmap2(NULL,12,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0xff69d000
60785 madvise(-9842688,12,12,-9842688,-8432404,-24280) = 0
60785 prctl(1398164801,0,-9842688,12,-8693213,-24136) = -1 errno=22 (Invalid argument)
60785 getrandom(-23744,40,1,40,-23744,-23768) = 40
60785 mmap2(NULL,1096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0xff69c000
60785 madvise(-9846784,1096,12,-9846784,-8432404,-23896) = 0
60785 prctl(1398164801,0,-9846784,1096,-8682952,-23752) = -1 errno=22 (Invalid argument)
60785 mmap2(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0xff69b000
60785 madvise(-9850880,4096,12,-9850880,-8432404,-24072) = 0
60785 prctl(1398164801,0,-9850880,4096,-8693379,-23880) = -1 errno=22 (Invalid argument)
60785 mmap2(NULL,12,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0xff69a000
60785 madvise(-9854976,12,12,-9854976,-8432404,-24216) = 0
60785 prctl(1398164801,0,-9854976,12,-8693213,-24072) = -1 errno=22 (Invalid argument)
60785 mmap2(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0xff699000
60785 madvise(-9859072,4096,12,-9859072,-8432404,-23640) = 0
60785 prctl(1398164801,0,-9859072,4096,-8728674,-23496) = -1 errno=22 (Invalid argument)
60785 mprotect(0xff699000,4096,PROT_READ|PROT_WRITE) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=1, si_addr=0x0000014e} ---
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
Segmentation fault
Глядя на аварийный дамп
$ sudo apport-unpack /var/crash/_usr_bin_qemu-i386.101461.crash ~/crash-unpacked/
$ gdb /usr/bin/qemu-i386 ~/crash-unpacked/CoreDump
$ gdb /usr/bin/qemu-i386 ~/crash-unpacked/CoreDump
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3 : GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
pwndbg: loaded 175 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from /usr/bin/qemu-i386...(no debugging symbols found)...done.
[New LWP 61385]
[New LWP 61386]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `qemu-i386 -L /home/user/android_28_img ./system/bin/hello_world'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00007f0853f7b2e6 in __GI___sigsuspend (set=0x7ffdb0445f48) at ../sysdeps/unix/sysv/linux/sigsuspend.c:26
26 ../sysdeps/unix/sysv/linux/sigsuspend.c: No such file or directory.
[Current thread is 1 (Thread 0x7f0855413e00 (LWP 61385))]
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────────────────────[ REGISTERS ]──────────────────────────────────────────────────────────────────
RAX 0xfffffffffffffdfe
RBX 0x7ffdb0445f48 ◂— 0xfffffffe7ffffbff
RCX 0x7f0853f7b2e6 (sigsuspend 70) ◂— cmp rax, -0x1000 /* 'H=' */
RDX 0x0
RDI 0x7ffdb0445f48 ◂— 0xfffffffe7ffffbff
RSI 0x8
R8 0x0
R9 0xb
R10 0x8
R11 0x293
R12 0x7ffdb0445f40 ◂— 0x0
R13 0x5581b1e9c210 ◂— 0xefc9
R14 0xb
R15 0x0
RBP 0xb
RSP 0x7ffdb0445f10 ◂— 0xb /* 'x0b' */
RIP 0x7f0853f7b2e6 (sigsuspend 70) ◂— cmp rax, -0x1000 /* 'H=' */
───────────────────────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────────────────────
► 0x7f0853f7b2e6 <sigsuspend 70> cmp rax, -0x1000
0x7f0853f7b2ec <sigsuspend 76> ja sigsuspend 122 <0x7f0853f7b31a>
↓
0x7f0853f7b31a <sigsuspend 122> mov rcx, qword ptr [rip 0x3abb47]
0x7f0853f7b321 <sigsuspend 129> neg eax
0x7f0853f7b323 <sigsuspend 131> mov dword ptr fs:[rcx], eax
0x7f0853f7b326 <sigsuspend 134> mov eax, 0xffffffff
0x7f0853f7b32b <sigsuspend 139> jmp sigsuspend 78 <0x7f0853f7b2ee>
↓
0x7f0853f7b2ee <sigsuspend 78> mov edi, edx
0x7f0853f7b2f0 <sigsuspend 80> mov dword ptr [rsp 0xc], eax
0x7f0853f7b2f4 <sigsuspend 84> call __libc_disable_asynccancel <0x7f085406c8f0>
0x7f0853f7b2f9 <sigsuspend 89> mov eax, dword ptr [rsp 0xc]
───────────────────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7ffdb0445f10 ◂— 0xb /* 'x0b' */
01:0008│ 0x7ffdb0445f18 ◂— 0xdb8b156e6a07500
02:0010│ 0x7ffdb0445f20 —▸ 0x7ffdb0445f48 ◂— 0xfffffffe7ffffbff
03:0018│ 0x7ffdb0445f28 —▸ 0x5581ae7bbb14 ◂— call 0x5581ae770710
04:0020│ 0x7ffdb0445f30 ◂— 0x0
05:0028│ 0x7ffdb0445f38 ◂— 0xffffffffffffffff
06:0030│ r12 0x7ffdb0445f40 ◂— 0x0
07:0038│ rbx rdi 0x7ffdb0445f48 ◂— 0xfffffffe7ffffbff
─────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────
► f 0 7f0853f7b2e6 sigsuspend 70
f 1 5581ae7bbb14
f 2 5581ae7bc6b8
f 3 5581ae7bd4db process_pending_signals 363
f 4 5581ae7a06e8 cpu_loop 504
f 5 5581ae773504 main 1860
f 6 7f0853f5db97 __libc_start_main 231
Я получаю такое же построение поведения и эмуляцию для aarch64 и использую библиотеки из распакованного изображения Galaxy S9.
Ответ №1:
Вероятно, двоичный файл Android пытается использовать функцию ядра, которую QEMU не реализует, или же он делает что-то неожиданное — в основном режим эмуляции пользователя QEMU тестируется на обычных двоичных файлах пользовательского пространства Linux, а не на Android. Например, вы можете видеть в strace() множество неудачных вызовов prctl(): хорошим началом для отладки было бы выяснить, что они пытаются сделать, и проверить, внедряет ли их QEMU.
Вам также может оказаться полезным использовать встроенную отладочную заглушку QEMU и подключить к ней gdb с поддержкой x86: тогда вы сможете пошагово выполнить гостевой код и посмотреть, что он делает, когда что-то идет не так.
Наконец, вы не указываете, какую версию QEMU вы используете — если это не последняя версия, всегда стоит попробовать последнюю, чтобы проверить, исправлено ли что-то уже. (В частности, в любой версии QEMU до версии 4.0 есть некоторые действительно серьезные ошибки, связанные с многопоточностью и сигналами в эмуляции пользовательского режима.)
Ответ №2:
Возникла та же проблема при запуске программ, скомпилированных для aarch64 Android (API 32). Странно то, что некоторые программы работают:
pajko@vortex:/work/target/usr/bin$ ./bzip2
bzip2: I won't write compressed data to a terminal.
bzip2: For help, type: `bzip2 --help'.
pajko@vortex:/work/target/usr/bin$ file bzip2
bzip2: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /system/bin/linker64, with debug_info, not stripped
а другие нет:
pajko@vortex:/work/target/usr/bin$ ./tclsh8.6
Segmentation fault
pajko@vortex:/work/target/usr/bin$ file ./tclsh8.6
./tclsh8.6: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /system/bin/linker64, not stripped
но может быть запущен путем выполнения с linker64 в качестве оболочки:
pajko@vortex:/work/target/usr/bin$ /system/bin/linker64 /work/target/usr/bin/tclsh8.6
%
И я не обманываю:
pajko@vortex:/work/target/usr/bin$ uname -a
Linux vortex 5.10.0-17-amd64 #1 SMP Debian 5.10.136-1 (2022-08-13) x86_64 GNU/Linux
Файлы в / system были извлечены с планшета (фактически извлечены из обновления прошивки).
Странно то, что bzip2 автоматически выполняется через linker64:
pajko@vortex:/work/target/usr/bin$ strace ./bzip2 amp;> /dev/stdout | grep -E "config|SEGV"
stat("/etc/gnutls/config", 0x7fff257cac70) = -1 ENOENT (No such file or directory)
rt_sigprocmask(SIG_SETMASK, ~[ILL FPE SEGV RTMIN RT_1], [], 8) = 0
rt_sigaction(SIGSEGV, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGSEGV, {sa_handler=0x5616f71b5250, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7f525d8d0140}, NULL, 8) = 0
access("/etc/qemu-binfmt/aarch64/system/etc/ld.config.arm64.txt", F_OK) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/system/etc/ld.config.arm64.txt", 0x7fff257c9360, 0) = -1 ENOENT (No such file or directory)
access("/etc/qemu-binfmt/aarch64/linkerconfig/ld.config.txt", F_OK) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/linkerconfig/ld.config.txt", {st_mode=S_IFREG|0644, st_size=1655, ...}, 0) = 0
openat(AT_FDCWD, "/linkerconfig/ld.config.txt", O_RDONLY|O_NOFOLLOW|O_CLOEXEC) = 3
Но tclsh8.6 — это не так, а какой-то обычный ld вместо этого:
pajko@vortex:/work/target/usr/bin$ strace ./tclsh8.6 amp;> /dev/stdout | grep -E "config|SEGV"
stat("/etc/gnutls/config", 0x7ffce33054f0) = -1 ENOENT (No such file or directory)
rt_sigprocmask(SIG_SETMASK, ~[ILL FPE SEGV RTMIN RT_1], [], 8) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, si_addr=0x5500003d78} ---
killed by SIGSEGV
Оба файла соответствуют /var / lib /binfmts /qemu-aarch64 и больше ничего. Также то же самое происходит при попытке выполнить tclsh8.6, используя qemu-aarch64 напрямую, вместо того, чтобы полагаться на поддержку binfmt.
pajko@vortex:/var/lib/binfmts$ qemu-aarch64 --version
qemu-aarch64 version 5.2.0 (Debian 1:5.2 dfsg-11 deb11u2)
Copyright (c) 2003-2020 Fabrice Bellard and the QEMU Project developers