【问题标题】:uClibc vfork() is causing segmentation faultuClibc vfork() 导致分段错误
【发布时间】:2014-07-07 05:13:00
【问题描述】:

我正在使用 armv7 进行 openwrt 开发,并面临由 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... */

一切似乎都很好。

感谢大家的帮助!

【问题讨论】:

    标签: linux libc openwrt uclibc


    【解决方案1】:

    man (3) vfork

    vfork() 函数应该等效于 fork(),除了如果由 vfork() 创建的进程修改了任何数据而不是用于存储来自 vfork( ),或从调用 vfork() 的函数返回,或在成功调用 _exit() 或 exec 系列函数之一之前调用任何其他函数。

    所以在孩子中你可以打电话给_exitexec。就是这样。

    【讨论】:

    • TL;DR:不要打电话给vfork()。它不适合你。 :)
    • vfork() 用于 uClibc 实现。我能控制吗?
    【解决方案2】:

    这里的解决方案是启用 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.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-06
      • 2020-12-31
      • 2019-07-21
      • 2018-07-28
      • 2014-04-25
      • 2011-07-18
      • 2013-02-26
      • 2022-01-12
      相关资源
      最近更新 更多