Print this page
OS-4470 lxbrand unblocking signals in new threads must be atomic

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/brand/lx/lx_brand/common/clone.c
          +++ new/usr/src/lib/brand/lx/lx_brand/common/clone.c
↓ open down ↓ 83 lines elided ↑ open up ↑
  84   84  };
  85   85  
  86   86  struct clone_state {
  87   87          void            *c_retaddr;     /* instr after clone()'s int80 */
  88   88          int             c_flags;        /* flags to clone(2) */
  89   89          int             c_sig;          /* signal to send on thread exit */
  90   90          void            *c_stk;         /* %esp of new thread */
  91   91          void            *c_ptidp;
  92   92          struct lx_desc  *c_ldtinfo;     /* thread-specific segment */
  93   93          void            *c_ctidp;
  94      -        ucontext_t      c_uc;           /* original register state */
  95      -        sigset_t        c_sigmask;      /* signal mask */
       94 +        ucontext_t      c_uc;           /* original register state/sigmask */
  96   95          lx_affmask_t    c_affmask;      /* CPU affinity mask */
  97   96          volatile int    *c_clone_res;   /* pid/error returned to cloner */
  98   97          int             c_ptrace_event; /* ptrace(2) event for child stop */
  99   98          void            *c_ntv_stk;     /* native stack for this thread */
 100   99          size_t          c_ntv_stk_sz;   /* native stack size */
 101  100          lx_tsd_t        *c_lx_tsd;      /* tsd area for thread */
 102  101  };
 103  102  
 104  103  /*
 105  104   * Counter incremented when we vfork(2) ourselves, and decremented when the
↓ open down ↓ 126 lines elided ↑ open up ↑
 232  231          lx_init_tsd(lxtsd);
 233  232          lxtsd->lxtsd_clone_state = cs;
 234  233  
 235  234          /*
 236  235           * Install the emulation stack for this thread.  Register the
 237  236           * thread-specific data structure with the stack list so that it may be
 238  237           * freed at thread exit or fork(2).
 239  238           */
 240  239          lx_install_stack(cs->c_ntv_stk, cs->c_ntv_stk_sz, lxtsd);
 241  240  
 242      -        if (sigprocmask(SIG_SETMASK, &cs->c_sigmask, NULL) < 0) {
 243      -                *(cs->c_clone_res) = -errno;
 244      -
 245      -                lx_err_fatal("Unable to release held signals for child "
 246      -                    "thread: %s", strerror(errno));
 247      -        }
 248      -
 249  241          /*
 250  242           * Let the parent know that the clone has (effectively) been
 251  243           * completed.
 252  244           */
 253  245          *(cs->c_clone_res) = rval;
 254  246  
 255  247          /*
 256      -         * We want to load the general registers from this context, and
 257      -         * switch to the BRAND stack.
      248 +         * We want to load the general registers from this context, restore the
      249 +         * original signal mask, and switch to the BRAND stack.  The original
      250 +         * signal mask was saved to the context by lx_clone().
 258  251           */
 259      -        cs->c_uc.uc_flags = UC_CPU;
      252 +        cs->c_uc.uc_flags = UC_CPU | UC_SIGMASK;
 260  253          cs->c_uc.uc_brand_data[0] = (void *)LX_UC_STACK_BRAND;
 261  254  
 262  255          /*
 263  256           * New threads will not link into the existing context chain.
 264  257           */
 265  258          cs->c_uc.uc_link = NULL;
 266  259  
 267  260          /*
 268  261           * Set stack pointer and entry point for new thread:
 269  262           */
↓ open down ↓ 4 lines elided ↑ open up ↑
 274  267           * Return 0 to the child:
 275  268           */
 276  269          LX_REG(&cs->c_uc, REG_R0) = (uintptr_t)0;
 277  270  
 278  271          /*
 279  272           * Fire the ptrace(2) event stop in the new thread:
 280  273           */
 281  274          lx_ptrace_stop_if_option(cs->c_ptrace_event, B_TRUE, 0, &cs->c_uc);
 282  275  
 283  276          /*
 284      -         * Jump to the Linux process.  The system call must not return.
      277 +         * Jump to the Linux process.  This call cannot return.
 285  278           */
 286      -        if (syscall(SYS_brand, B_JUMP_TO_LINUX, &cs->c_uc) == -1) {
 287      -                lx_err_fatal("B_JUMP_TO_LINUX failed: %s",
 288      -                    strerror(errno));
 289      -        }
 290      -        abort();
 291      -
 292      -        /*NOTREACHED*/
 293      -        return (NULL);
      279 +        lx_jump_to_linux(&cs->c_uc);
 294  280  }
 295  281  
 296  282  /*
 297  283   * The way Linux handles stopping for FORK vs. CLONE does not map exactly to
 298  284   * which syscall was used. Instead, it has to do with which signal is set in
 299  285   * the low byte of the clone flag. The only time the CLONE event is emitted is
 300  286   * if the clone signal (the low byte of the flags argument) is set to something
 301  287   * other than SIGCHLD (see the Linux src in kernel/fork.c do_fork() for the
 302  288   * actual code).
 303  289   */
↓ open down ↓ 355 lines elided ↑ open up ↑
 659  645          }
 660  646  
 661  647          if (lx_sched_getaffinity(0, sizeof (cs->c_affmask),
 662  648              (uintptr_t)&cs->c_affmask) == -1) {
 663  649                  lx_err_fatal("Unable to get affinity mask for parent "
 664  650                      "thread: %s", strerror(errno));
 665  651          }
 666  652  
 667  653          clone_res = 0;
 668  654  
 669      -        (void) sigfillset(&sigmask);
 670      -
 671  655          /*
 672  656           * Block all signals because the thread we create won't be able to
 673  657           * properly handle them until it's fully set up.
 674  658           */
      659 +        (void) sigfillset(&sigmask);
 675  660          if (sigprocmask(SIG_BLOCK, &sigmask, &osigmask) < 0) {
 676  661                  lx_debug("lx_clone sigprocmask() failed: %s", strerror(errno));
 677  662                  free(cs->c_lx_tsd);
 678  663                  free(cs);
 679  664                  return (-errno);
 680  665          }
 681      -        cs->c_sigmask = osigmask;
      666 +        cs->c_uc.uc_sigmask = osigmask;
 682  667  
 683  668          /*
 684  669           * Allocate the native stack for this new thread now, so that we
 685  670           * can return failure gracefully as ENOMEM.
 686  671           */
 687  672          if (lx_alloc_stack(&cs->c_ntv_stk, &cs->c_ntv_stk_sz) != 0) {
 688  673                  free(cs->c_lx_tsd);
 689  674                  free(cs);
 690  675                  return (-ENOMEM);
 691  676          }
↓ open down ↓ 37 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX