Print this page
OS-4470 lxbrand unblocking signals in new threads must be atomic
Reviewed by: Robert Mustacchi <rm@joyent.com>
OS-3561 lxbrand emulation library should execute on alternate stack
OS-3558 lxbrand add support for full in-kernel syscall handling
OS-3545 lx_syscall_regs should not walk stack
OS-3868 many LTP testcases now hang
OS-3901 lxbrand lx_recvmsg fails to translate control messages when 64-bit
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Bryan Cantrill <bryan@joyent.com>
OS-2844 lx brand should support 64-bit user-land

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libc/port/threads/sigaction.c
          +++ new/usr/src/lib/libc/port/threads/sigaction.c
↓ open down ↓ 14 lines elided ↑ open up ↑
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
       25 + * Copyright 2015 Joyent, Inc.
  25   26   */
  26   27  
  27   28  #include "lint.h"
  28   29  #include <sys/feature_tests.h>
  29   30  /*
  30   31   * setcontext() really can return, if UC_CPU is not specified.
  31   32   * Make the compiler shut up about it.
  32   33   */
  33   34  #if defined(__NORETURN)
  34   35  #undef  __NORETURN
↓ open down ↓ 242 lines elided ↑ open up ↑
 277  278          else
 278  279                  sip = &self->ul_siginfo;
 279  280  
 280  281          /* EAGAIN can happen only for a pending SIGSTOP signal */
 281  282          while ((error = __sigresend(sig, sip, &self->ul_sigmask)) == EAGAIN)
 282  283                  continue;
 283  284          if (error)
 284  285                  thr_panic("take_deferred_signal(): __sigresend() failed");
 285  286  }
 286  287  
      288 +/*
      289 + * sigacthandler() attempts to clean up dangling uc_link pointers in
      290 + * signal handling contexts when libc believes us to have escaped
      291 + * a signal handler incorrectly in the past.
      292 + *
      293 + * Branded processes have a legitimate use for a chain including contexts
      294 + * other than those used for signal handling when tracking emulation
      295 + * requests from the kernel.  We allow them to disable this cleanup
      296 + * behaviour.
      297 + */
      298 +static int escaped_context_cleanup = 1;
      299 +
 287  300  void
      301 +set_escaped_context_cleanup(int on)
      302 +{
      303 +        escaped_context_cleanup = on;
      304 +}
      305 +
      306 +void
 288  307  sigacthandler(int sig, siginfo_t *sip, void *uvp)
 289  308  {
 290  309          ucontext_t *ucp = uvp;
 291  310          ulwp_t *self = curthread;
 292  311  
 293  312          /*
 294  313           * Do this in case we took a signal while in a cancelable system call.
 295  314           * It does no harm if we were not in such a system call.
 296  315           */
 297  316          self->ul_sp = 0;
↓ open down ↓ 1 lines elided ↑ open up ↑
 299  318                  self->ul_cancel_async = self->ul_save_async;
 300  319  
 301  320          /*
 302  321           * If this thread has performed a longjmp() from a signal handler
 303  322           * back to main level some time in the past, it has left the kernel
 304  323           * thinking that it is still in the signal context.  We repair this
 305  324           * possible damage by setting ucp->uc_link to NULL if we know that
 306  325           * we are actually executing at main level (self->ul_siglink == NULL).
 307  326           * See the code for setjmp()/longjmp() for more details.
 308  327           */
 309      -        if (self->ul_siglink == NULL)
      328 +        if (escaped_context_cleanup && self->ul_siglink == NULL)
 310  329                  ucp->uc_link = NULL;
 311  330  
 312  331          /*
 313  332           * If we are not in a critical region and are
 314  333           * not deferring signals, take the signal now.
 315  334           */
 316  335          if ((self->ul_critical + self->ul_sigdefer) == 0) {
 317  336                  call_user_handler(sig, sip, ucp);
 318  337                  /*
 319  338                   * On the surface, the following call seems redundant
↓ open down ↓ 131 lines elided ↑ open up ↑
 451  470                      (tactp->sa_handler != SIG_DFL &&
 452  471                      tactp->sa_handler != SIG_IGN);
 453  472          }
 454  473  
 455  474          if (!self->ul_vfork)
 456  475                  lrw_unlock(&udp->siguaction[sig].sig_lock);
 457  476          return (rv);
 458  477  }
 459  478  
 460  479  /*
 461      - * This is a private interface for the linux brand interface.
      480 + * This is a private interface for the lx brand.
 462  481   */
 463  482  void
 464  483  setsigacthandler(void (*nsigacthandler)(int, siginfo_t *, void *),
 465      -    void (**osigacthandler)(int, siginfo_t *, void *))
      484 +    void (**osigacthandler)(int, siginfo_t *, void *),
      485 +    int (*brsetctxt)(const ucontext_t *))
 466  486  {
 467  487          ulwp_t *self = curthread;
 468  488          uberdata_t *udp = self->ul_uberdata;
 469  489  
 470  490          if (osigacthandler != NULL)
 471  491                  *osigacthandler = udp->sigacthandler;
 472  492  
 473  493          udp->sigacthandler = nsigacthandler;
      494 +
      495 +        if (brsetctxt != NULL)
      496 +                udp->setctxt = brsetctxt;
 474  497  }
 475  498  
 476  499  /*
 477  500   * Tell the kernel to block all signals.
 478  501   * Use the schedctl interface, or failing that, use __lwp_sigmask().
 479  502   * This action can be rescinded only by making a system call that
 480  503   * sets the signal mask:
 481  504   *      __lwp_sigmask(), __sigprocmask(), __setcontext(),
 482  505   *      __sigsuspend() or __pollsys().
 483  506   * In particular, this action cannot be reversed by assigning
↓ open down ↓ 26 lines elided ↑ open up ↑
 510  533   * on return from a signal handler via the passed ucontext_t.)
 511  534   */
 512  535  static int setcontext_enforcement = 1;
 513  536  
 514  537  void
 515  538  set_setcontext_enforcement(int on)
 516  539  {
 517  540          setcontext_enforcement = on;
 518  541  }
 519  542  
      543 +/*
      544 + * The LX brand emulation library implements an operation that is analogous to
      545 + * setcontext(), but takes a different path in to the kernel.  So that it can
      546 + * correctly restore a signal mask, we expose just the signal mask handling
      547 + * part of the regular setcontext() routine as a private interface.
      548 + */
      549 +void
      550 +setcontext_sigmask(ucontext_t *ucp)
      551 +{
      552 +        ulwp_t *self = curthread;
      553 +
      554 +        if (ucp->uc_flags & UC_SIGMASK) {
      555 +                block_all_signals(self);
      556 +                delete_reserved_signals(&ucp->uc_sigmask);
      557 +                self->ul_sigmask = ucp->uc_sigmask;
      558 +                if (self->ul_cursig) {
      559 +                        /*
      560 +                         * We have a deferred signal present.
      561 +                         * The signal mask will be set when the
      562 +                         * signal is taken in take_deferred_signal().
      563 +                         */
      564 +                        ASSERT(self->ul_critical + self->ul_sigdefer != 0);
      565 +                        ucp->uc_flags &= ~UC_SIGMASK;
      566 +                }
      567 +        }
      568 +}
      569 +
 520  570  #pragma weak _setcontext = setcontext
 521  571  int
 522  572  setcontext(const ucontext_t *ucp)
 523  573  {
 524  574          ulwp_t *self = curthread;
      575 +        uberdata_t *udp = self->ul_uberdata;
 525  576          int ret;
 526  577          ucontext_t uc;
 527  578  
 528  579          /*
 529  580           * Returning from the main context (uc_link == NULL) causes
 530  581           * the thread to exit.  See setcontext(2) and makecontext(3C).
 531  582           */
 532  583          if (ucp == NULL)
 533  584                  thr_exit(NULL);
 534  585          (void) memcpy(&uc, ucp, sizeof (uc));
 535  586  
 536  587          /*
 537  588           * Restore previous signal mask and context link.
 538  589           */
 539      -        if (uc.uc_flags & UC_SIGMASK) {
 540      -                block_all_signals(self);
 541      -                delete_reserved_signals(&uc.uc_sigmask);
 542      -                self->ul_sigmask = uc.uc_sigmask;
 543      -                if (self->ul_cursig) {
 544      -                        /*
 545      -                         * We have a deferred signal present.
 546      -                         * The signal mask will be set when the
 547      -                         * signal is taken in take_deferred_signal().
 548      -                         */
 549      -                        ASSERT(self->ul_critical + self->ul_sigdefer != 0);
 550      -                        uc.uc_flags &= ~UC_SIGMASK;
 551      -                }
 552      -        }
      590 +        setcontext_sigmask(&uc);
 553  591          self->ul_siglink = uc.uc_link;
 554  592  
 555  593          /*
 556  594           * We don't know where this context structure has been.
 557  595           * Preserve the curthread pointer, at least.
 558  596           *
 559  597           * Allow this feature to be disabled if a particular process
 560  598           * requests it.
 561  599           */
 562  600          if (setcontext_enforcement) {
↓ open down ↓ 8 lines elided ↑ open up ↑
 571  609  #endif
 572  610          }
 573  611  
 574  612          /*
 575  613           * Make sure that if we return to a call to __lwp_park()
 576  614           * or ___lwp_cond_wait() that it returns right away
 577  615           * (giving us a spurious wakeup but not a deadlock).
 578  616           */
 579  617          set_parking_flag(self, 0);
 580  618          self->ul_sp = 0;
 581      -        ret = __setcontext(&uc);
      619 +        ret = udp->setctxt(&uc);
 582  620  
 583  621          /*
 584  622           * It is OK for setcontext() to return if the user has not specified
 585  623           * UC_CPU.
 586  624           */
 587  625          if (uc.uc_flags & UC_CPU)
 588  626                  thr_panic("setcontext(): __setcontext() returned");
 589  627          return (ret);
 590  628  }
 591  629  
↓ open down ↓ 175 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX