您的位置:首页 > 移动开发 > Android开发

android ndk vfork 缺陷

2014-05-31 17:48 417 查看
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_errnoEND(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 vforkBreakpoint 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) rStarting program: /data/local/tmp/vfork ls -lBreakpoint 1, vfork () at bionic/libc/arch-arm/syscalls/vfork.S:1313	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	3199400164r1             0xbeb2faa8	3199400616r2             0x0	0r3             0xc	12r4             0x3	3r5             0xbeb2f970	3199400304r6             0xbeb2f8ec	3199400172r7             0xbeb2f8f8	3199400184r8             0x0	0r9             0x0	0r10            0x0	0r11            0xbeb2f95c	3199400284r12            0x0	0sp             0xbeb2f8c0	0xbeb2f8c0lr             0x8165	33125pc             0x9684	0x9684 <vfork+4>cpsr           0x80000010	-2147483632(gdb) x/4xw $sp0xbeb2f8c0:	0x00000003	0xbeb2f8f8	0xbeb2f8e4	0xbeb2f8e4(gdb) disassemble $pcDump 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 *0x968cBreakpoint 2 at 0x968c: file bionic/libc/arch-arm/syscalls/vfork.S, line 15. (gdb) b execvpBreakpoint 3 at 0x9a98: file bionic/libc/unistd/exec.c, line 202.(gdb) cContinuing.[New process 5934][Switching to process 5934]Breakpoint 2, vfork () at bionic/libc/arch-arm/syscalls/vfork.S:1515	in bionic/libc/arch-arm/syscalls/vfork.S1: 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) nivfork () at bionic/libc/arch-arm/syscalls/vfork.S:1616	in bionic/libc/arch-arm/syscalls/vfork.S1: 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.S1: 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:4848	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.c1: 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.c1: 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.c1: 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.c1: 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.c1: 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.c1: 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) cContinuing.Breakpoint 3, execvp (name=0x1f78028 "ls", argv=0xbeb2f8e4)    at bionic/libc/unistd/exec.c:202202	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	32997416r1             0xbeb2f8e4	3199400164r2             0x0	0r3             0xbeb2f8e4	3199400164r4             0xffffff9c	4294967196r5             0xffffefb4	4294963124r6             0xbeb2f8ec	3199400172r7             0xbeb2f8f8	3199400184r8             0x0	0r9             0x0	0r10            0x0	0r11            0xbeb2f95c	3199400284r12            0x0	0sp             0xbeb2e868	0xbeb2e868lr             0x8195	33173pc             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,导致后续栈帧被破坏,程序崩溃。

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android ndk asm