2014-07-07 90 views
0

我正在使用armv7進行openwrt開發,並面臨由vfork引起的段錯誤。uClibc vfork()導致段錯誤

我已經寫了一個小測試程序有以下部分:

... 
    pid_t child_t; 
    if((child_t = vfork()) < 0) 
    { 
     printf("error!\n"); 
     return -1; 
    } 
    else if(child_t == 0) 
    { 
     printf("in child:pid =%d\n",getpid()); 
     sleep(2); 
     _exit(0); 
    } 
    else 
    { 
     printf("in parent:child_t id = %d,pid = %d\n",child_t,getpid()); 
    } 
    ... 

的了vfork()函數總是會導致段錯誤,這是GDB調試跟蹤:

... 
    (gdb) c 
     Breakpoint 1, main (argc=1, argv=0xbefffed4) at handler.c:33 
     33   if((child_t = vfork()) < 0) 
    (gdb) stepi 
     0x00008474 in vfork() at   libpthread/nptl/sysdeps/unix/sysv/linux/arm/../../../../../../../libc/sysdeps/linux/arm/vfo  rk.S:71 
    71  SAVE_PID 
    (gdb) l 
    66  
    67 #else 
    68 __vfork: 
    69  
    70 #ifdef __NR_vfork 
    71  SAVE_PID 
    72  DO_CALL (vfork) 
    73  RESTORE_PID 
    74  cmn r0, #4096 
    75  IT(t, cc) 
    (gdb) b  libpthread/nptl/sysdeps/unix/sysv/linux/arm/../../../../../../../libc/sysdeps/linux/arm/vfo rk.S:72 
     Breakpoint 2 at 0xb6fcf930: file  libpthread/nptl/sysdeps/unix/sysv/linux/arm/../../../../../../../libc/sysdeps/linux/arm/vfo  rk.S, line 72. 
    (gdb) disassemble 
      0x00008584 <+40>:  bl  0x8444 <puts> 
    => 0x00008588 <+44>:   bl  0x8474 <vfork> 
      0x0000858c <+48>:   str r0, [r11, #-12] 
    (gdb)stepi 
    ... 
    (gdb) stepi 
     0x00008474 in vfork() at  libpthread/nptl/sysdeps/unix/sysv/linux/arm/../../../../../../../libc/sysdeps/linux/arm/vfo rk.S:71 
     71    SAVE_PID 
    (gdb) disassemble 
     Dump of assembler code for function vfork: 
     => 0x00008474 <+0>: add r12, pc, #0, 12 
       0x00008478 <+4>: add r12, r12, #8, 20  ; 0x8000 
       0x0000847c <+8>: ldr pc, [r12, #796]!  ; 0x31c 
    (gdb) stepi 
     … 
    (gdb) disassemble 
     Dump of assembler code for function vfork: 
      0x00008474 <+0>: add r12, pc, #0, 12 
      0x00008478 <+4>: add r12, r12, #8, 20  ; 0x8000 
     => 0x0000847c <+8>:  ldr pc, [r12, #796]!  ; 0x31c 
    (gdb)c 
     Continuing. 
     Program received signal SIGSEGV, Segmentation fault. 
     0xffff0fe0 in ??() 
    (gdb) 

我還發現在vfork.S的vfork的代碼: __vfork:

#ifdef __NR_vfork 
    SAVE_PID 
    DO_CALL (vfork) 
    RESTORE_PID 
    cmn r0, #4096 
    IT(t, cc) 
#if defined(__USE_BX__) 
    bxcc lr 
#else 
    movcc pc, lr 
#endif 

    /* Check if vfork even exists. */ 
    ldr  r1, =-ENOSYS 
    teq  r0, r1 
    bne  __error 
#endif 

    /* If we don't have vfork, use fork. */ 
    DO_CALL (fork) 
    cmn  r0, #4096 

    /* Syscall worked. Return to child/parent */ 
    IT(t, cc) 
#if defined(__USE_BX__) 
    bxcc lr 
#else 
    movcc pc, lr 
#endif 

__error: 
    b __syscall_error 
#endif 

一些更信息 - 繞過vfork的時候像這樣的 -

VFORK_LOCK; 

- if ((pid = vfork()) == 0) { /* Child of vfork... */ 

+ // if ((pid = vfork()) == 0) { /* Child of vfork... */ 

+  pid = syscall(__NR_fork, NULL); 

+ if (pid == 0) { /* Child of vfork... */ 

一切似乎很好地工作。

謝謝大家的幫助!

回答

0

man (3) vfork

該了vfork()函數,應等於叉(),所不同的是該行爲是未定義如果()由vfork的創建的流程修改比用於類型將爲pid_t的變量之外的任何數據存儲vfork()的返回值,或從調用vfork()的函數返回,或者在成功調用_exit()或某個exec函數族之前調用任何其他函數。

所以在孩子,你可以撥打_exitexec。而已。

+0

TL; DR:不要調用'vfork()'。這不適合你。 :) – duskwuff

+0

vfork()用於uClibc實現。我可以控制它嗎? –

0

這裏的解決方案是啓用CONFIG_KUSER_HELPER標誌。

來自CONFIG_USERS_HELPERS。

If all of the binaries and libraries which run on your platform 
are built specifically for your platform, and make no use of 
these helpers, then you can turn this option off to hinder 
such exploits. However, in that case, if a binary or library 
relying on those helpers is run, it will receive a SIGILL signal, 
which will terminate the program.