2014-07-07 2 views
0

openwrt 개발을 위해 armv7을 사용 중이며 vfork로 인한 segfault를 마주하고 있습니다. 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 계열의 함수 중 하나를 성공적으로 호출하기 전에 다른 함수를 호출합니다.

어린이의 경우 _exit 또는 exec으로 전화 할 수 있습니다. 그게 전부 야.

+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. 
관련 문제