android ndk vfork 缺陷

NDK vfork implementation: push {r4, r7} mov r7, #190 ; 0xbe svc 0x00000000 pop {r4, r7} movs r0, r0 bxpl lr b 0x1475c bionic C vfork implentation(KitKat): ENTRY(vfork) mov ip, r7 ldr r7, =__NR_vfork swi #0 mov r7, ip cmn r0, #(MAX_ERRNO + 1) bxls lr neg r0, r0 b __set_errno END(vfork)
 
与KitKat的vfork实现比较,感觉问题出在 push {r4, r7}
不知道NDK下个版本是否会修改vfork的实现,这样很容易导致栈内存出问题。
 
临时解决方法:
my_vfork.S
/* autogenerated by gensyscalls.py */ #include <asm/unistd.h> #include <linux/err.h> #include <machine/asm.h> ENTRY(my_vfork)     mov     ip, r7     ldr     r7, =__NR_vfork     swi     #0     mov     r7, ip     cmn     r0, #(MAX_ERRNO + 1)     bxls    lr     neg     r0, r0     b       my_set_errno END(my_vfork) 
 
---------------------------------------------------------------------------------------
test.c
int my_set_errno(int n)  {   errno = n;   return -1; } int test(char** argv) {     int status; #if 0     pid_t pid = vfork(); #else     pid_t pid = my_vfork(); #endif     if (pid <0)     {         fprintf(stderr, "vfork failed(%s)\n", strerror(errno));         return;     }     if (pid == 0)     {          execvp(argv[0], argv);         _exit(111);     }else {         pid = waitpid(0, &status, 0);     }     return 0; }
 
==============================================================================================
使用 gdb 跟踪该缺陷
 
# gdb --args /data/local/tmp/vfork ls -l                     Reading symbols from /data/local/tmp/vfork...done. (gdb) b vfork Breakpoint 1 at 0x9684: file bionic/libc/arch-arm/syscalls/vfork.S, line 13. (gdb) set follow-fork-mode child  (gdb) display /4i $pc-8 (gdb) r Starting program: /data/local/tmp/vfork ls -l Breakpoint 1, vfork () at bionic/libc/arch-arm/syscalls/vfork.S:13 13 bionic/libc/arch-arm/syscalls/vfork.S: No such file or directory. 1: x/4i $pc-8    0x967c <_exit+28>: nop ; (mov r0, r0)    0x9680 <vfork>: push {r4, r7} => 0x9684 <vfork+4>: mov r7, #190 ; 0xbe    0x9688 <vfork+8>: svc 0x00000000 (gdb) info registers  r0             0xbeb2f8e4 3199400164 r1             0xbeb2faa8 3199400616 r2             0x0 0 r3             0xc 12 r4             0x3 3 r5             0xbeb2f970 3199400304 r6             0xbeb2f8ec 3199400172 r7             0xbeb2f8f8 3199400184 r8             0x0 0 r9             0x0 0 r10            0x0 0 r11            0xbeb2f95c 3199400284 r12            0x0 0 sp             0xbeb2f8c0 0xbeb2f8c0 lr             0x8165 33125 pc             0x9684 0x9684 <vfork+4> cpsr           0x80000010 -2147483632 (gdb) x/4xw $sp 0xbeb2f8c0: 0x00000003 0xbeb2f8f8 0xbeb2f8e4 0xbeb2f8e4 (gdb) disassemble $pc Dump of assembler code for function vfork:    0x00009680 <+0>: push {r4, r7} => 0x00009684 <+4>: mov r7, #190 ; 0xbe    0x00009688 <+8>: svc 0x00000000    0x0000968c <+12>: pop {r4, r7}    0x00009690 <+16>: movs r0, r0    0x00009694 <+20>: bxpl lr    0x00009698 <+24>: b 0x145c4    0x0000969c <+28>: nop ; (mov r0, r0) End of assembler dump. (gdb) b *0x968c Breakpoint 2 at 0x968c: file bionic/libc/arch-arm/syscalls/vfork.S, line 15.  (gdb) b execvp Breakpoint 3 at 0x9a98: file bionic/libc/unistd/exec.c, line 202. (gdb) c Continuing. [New process 5934] [Switching to process 5934] Breakpoint 2, vfork () at bionic/libc/arch-arm/syscalls/vfork.S:15 15 in bionic/libc/arch-arm/syscalls/vfork.S 1: x/4i $pc-8    0x9684 <vfork+4>: mov r7, #190 ; 0xbe    0x9688 <vfork+8>: svc 0x00000000 => 0x968c <vfork+12>: pop {r4, r7}    0x9690 <vfork+16>: movs r0, r0 (gdb) x/4xw $sp       0xbeb2f8c0: 0x00000003 0xbeb2f8f8 0xbeb2f8e4 0xbeb2f8e4 (gdb) ni vfork () at bionic/libc/arch-arm/syscalls/vfork.S:16 16 in bionic/libc/arch-arm/syscalls/vfork.S 1: x/4i $pc-8    0x9688 <vfork+8>: svc 0x00000000    0x968c <vfork+12>: pop {r4, r7} => 0x9690 <vfork+16>: movs r0, r0    0x9694 <vfork+20>: bxpl lr (gdb)  17 in bionic/libc/arch-arm/syscalls/vfork.S 1: x/4i $pc-8    0x968c <vfork+12>: pop {r4, r7}    0x9690 <vfork+16>: movs r0, r0 => 0x9694 <vfork+20>: bxpl lr    0x9698 <vfork+24>: b 0x145c4 (gdb)  test (argv=0x1f78028) at jni/vfork.c:48 48 jni/vfork.c: No such file or directory. 1: x/4i $pc-8    0x815c <test>: push {r0, r1, r2, r3, r4, lr}    0x815e <test+2>: str r0, [sp, #4]    0x8160 <test+4>: blx 0x9680 <vfork> => 0x8164 <test+8>: cmp r0, #0 (gdb)  0x00008166 48 in jni/vfork.c 1: x/4i $pc-8    0x815e <test+2>: str r0, [sp, #4]    0x8160 <test+4>: blx 0x9680 <vfork>    0x8164 <test+8>: cmp r0, #0 => 0x8166 <test+10>: bge.n 0x8186 <test+42> (gdb)  53 in jni/vfork.c 1: x/4i $pc-8    0x817e <test+34>: adds r0, #168 ; 0xa8    0x8180 <test+36>: bl 0x9d10 <fprintf>    0x8184 <test+40>: b.n 0x81a6 <test+74> => 0x8186 <test+42>: cmp r0, #0 (gdb)  0x00008188 53 in jni/vfork.c 1: x/4i $pc-8    0x8180 <test+36>: bl 0x9d10 <fprintf>    0x8184 <test+40>: b.n 0x81a6 <test+74>    0x8186 <test+42>: cmp r0, #0 => 0x8188 <test+44>: bne.n 0x819a <test+62> (gdb)  55 in jni/vfork.c 1: x/4i $pc-8    0x8182 <test+38>: stc2l 0, cr14, [r6, #60] ; 0x3c    0x8186 <test+42>: cmp r0, #0    0x8188 <test+44>: bne.n 0x819a <test+62> => 0x818a <test+46>: ldr r3, [sp, #4] (gdb)  0x0000818c 55 in jni/vfork.c 1: x/4i $pc-8    0x8184 <test+40>: b.n 0x81a6 <test+74>    0x8186 <test+42>: cmp r0, #0    0x8188 <test+44>: bne.n 0x819a <test+62>    0x818a <test+46>: ldr r3, [sp, #4] (gdb)  0x0000818e 55 in jni/vfork.c 1: x/4i $pc-8    0x8186 <test+42>: cmp r0, #0    0x8188 <test+44>: bne.n 0x819a <test+62>    0x818a <test+46>: ldr r3, [sp, #4]    0x818c <test+48>: ldr r0, [r3, #0] (gdb) c Continuing. Breakpoint 3, execvp (name=0x1f78028 "ls", argv=0xbeb2f8e4)     at bionic/libc/unistd/exec.c:202 202 bionic/libc/unistd/exec.c: No such file or directory. 1: x/4i $pc-8    0x9a90 <execvp>: push {r4, r5, r6, r7, lr}    0x9a92 <execvp+2>: ldr r5, [pc, #464] ; (0x9c64 <execvp+468>)    0x9a94 <execvp+4>: ldr r4, [pc, #464] ; (0x9c68 <execvp+472>)    0x9a96 <execvp+6>: add sp, r5 (gdb) info registers  r0             0x1f78028 32997416 r1             0xbeb2f8e4 3199400164 r2             0x0 0 r3             0xbeb2f8e4 3199400164 r4             0xffffff9c 4294967196 r5             0xffffefb4 4294963124 r6             0xbeb2f8ec 3199400172 r7             0xbeb2f8f8 3199400184 r8             0x0 0 r9             0x0 0 r10            0x0 0 r11            0xbeb2f95c 3199400284 r12            0x0 0 sp             0xbeb2e868 0xbeb2e868 lr             0x8195 33173 pc             0x9a98 0x9a98 <execvp+8> cpsr           0x80000030 -2147483600 (gdb)  
 
最终子进程
0x0000968c <+12>:	pop	{r4, r7}
sp 恢复,而父进程要等到子进程执行到execve才恢复执行,届时sp才能恢复,
而当子进程执行完vfork,执行进入execvp时,执行push指令压入几个寄存器,
0x9a90 <execvp>:	push	{r4, r5, r6, r7, lr}
导致父进程在vfork中压入sp的r4, r7被这里的r7,lr取代,最终子进程执行exeve后,父进程vfork从svc后继续执行
0x0000968c <+12>:	pop	{r4, r7}
弹出的r7已被修改为0x8195,导致后续栈帧被破坏,程序崩溃。
 

你可能感兴趣的:(ASM,android,NDK)