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


1540  * system calls to get us back here after the Linux signal handler returns.
1541  * This function is modelled on the in-kernel "sendsig()" signal delivery
1542  * mechanism.
1543  */
1544 void
1545 lx_sigdeliver(int lx_sig, siginfo_t *sip, ucontext_t *ucp, size_t stacksz,
1546     void (*stack_builder)(), void (*user_handler)(),
1547     struct lx_sigaction *lxsap)
1548 {
1549         lx_sigbackup_t sigbackup;
1550         ucontext_t uc;
1551         lx_tsd_t *lxtsd = lx_get_tsd();
1552         int totsz = 0;
1553         uintptr_t flags;
1554         uintptr_t hargs[3];
1555         /*
1556          * These variables must be "volatile", as they are modified after the
1557          * getcontext() stores the register state:
1558          */
1559         volatile boolean_t signal_delivered = B_FALSE;
1560         volatile uintptr_t lxfp;
1561         volatile uintptr_t old_tsd_sp;
1562         volatile int newstack;
1563 
1564         /*
1565          * This function involves modifying the Linux process stack for this
1566          * thread.  To do so without corruption requires us to exclude other
1567          * signal handlers (or emulated system calls called from within those
1568          * handlers) from running while we reserve space on that stack.  We
1569          * defer the execution of further instances of lx_call_user_handler()
1570          * until we have completed this operation.
1571          */
1572         _sigoff();
1573 
1574         /*
1575          * Clear register arguments vector.
1576          */
1577         bzero(hargs, sizeof (hargs));
1578 
1579         /*
1580          * We save a context here so that we can be returned later to complete
1581          * handling the signal.
1582          */


1788                  * uc_link value from this synthetic context, as that would
1789                  * break the signal handling context chain.
1790                  */
1791                 jump_uc.uc_flags = UC_CPU;
1792                 jump_uc.uc_brand_data[0] = (void *)(LX_UC_STACK_BRAND |
1793                     LX_UC_IGNORE_LINK);
1794 
1795                 LX_REG(&jump_uc, REG_FP) = 0;
1796                 LX_REG(&jump_uc, REG_SP) = lxfp;
1797                 LX_REG(&jump_uc, REG_PC) = (uintptr_t)user_handler;
1798 
1799 #if defined(_LP64)
1800                 /*
1801                  * Pass signal handler arguments by registers on AMD64.
1802                  */
1803                 LX_REG(&jump_uc, REG_RDI) = hargs[0];
1804                 LX_REG(&jump_uc, REG_RSI) = hargs[1];
1805                 LX_REG(&jump_uc, REG_RDX) = hargs[2];
1806 #endif
1807 
1808                 if (syscall(SYS_brand, B_JUMP_TO_LINUX, &jump_uc) == -1) {
1809                         lx_err_fatal("B_JUMP_TO_LINUX failed: %s",
1810                             strerror(errno));
1811                 }
1812         }
1813 
1814         assert(0);

1815 
1816 after_signal_handler:
1817         /*
1818          * Ensure all nested signal handlers have completed correctly
1819          * and then remove our stack reservation.
1820          */
1821         _sigoff();
1822         LX_SIGNAL_POST_HANDLER(lxfp, old_tsd_sp);
1823         assert(lxtsd->lxtsd_lx_sp == lxfp);
1824         lx_debug("lx_sigdeliver: after; Linux tsd sp %p -> %p\n", lxfp,
1825             old_tsd_sp);
1826         lxtsd->lxtsd_lx_sp = old_tsd_sp;
1827         if (newstack) {
1828                 LX_SIGNAL_ALTSTACK_DISABLE();
1829                 lx_debug("lx_sigdeliver: disabling ALTSTACK sp %p\n", lxfp);
1830                 lxtsd->lxtsd_sigaltstack.ss_flags &= ~LX_SS_ONSTACK;
1831         }
1832         /*
1833          * Restore backup signal tracking chain pointer to previous value:
1834          */




1540  * system calls to get us back here after the Linux signal handler returns.
1541  * This function is modelled on the in-kernel "sendsig()" signal delivery
1542  * mechanism.
1543  */
1544 void
1545 lx_sigdeliver(int lx_sig, siginfo_t *sip, ucontext_t *ucp, size_t stacksz,
1546     void (*stack_builder)(), void (*user_handler)(),
1547     struct lx_sigaction *lxsap)
1548 {
1549         lx_sigbackup_t sigbackup;
1550         ucontext_t uc;
1551         lx_tsd_t *lxtsd = lx_get_tsd();
1552         int totsz = 0;
1553         uintptr_t flags;
1554         uintptr_t hargs[3];
1555         /*
1556          * These variables must be "volatile", as they are modified after the
1557          * getcontext() stores the register state:
1558          */
1559         volatile boolean_t signal_delivered = B_FALSE;
1560         volatile uintptr_t lxfp = 0;
1561         volatile uintptr_t old_tsd_sp = 0;
1562         volatile int newstack = 0;
1563 
1564         /*
1565          * This function involves modifying the Linux process stack for this
1566          * thread.  To do so without corruption requires us to exclude other
1567          * signal handlers (or emulated system calls called from within those
1568          * handlers) from running while we reserve space on that stack.  We
1569          * defer the execution of further instances of lx_call_user_handler()
1570          * until we have completed this operation.
1571          */
1572         _sigoff();
1573 
1574         /*
1575          * Clear register arguments vector.
1576          */
1577         bzero(hargs, sizeof (hargs));
1578 
1579         /*
1580          * We save a context here so that we can be returned later to complete
1581          * handling the signal.
1582          */


1788                  * uc_link value from this synthetic context, as that would
1789                  * break the signal handling context chain.
1790                  */
1791                 jump_uc.uc_flags = UC_CPU;
1792                 jump_uc.uc_brand_data[0] = (void *)(LX_UC_STACK_BRAND |
1793                     LX_UC_IGNORE_LINK);
1794 
1795                 LX_REG(&jump_uc, REG_FP) = 0;
1796                 LX_REG(&jump_uc, REG_SP) = lxfp;
1797                 LX_REG(&jump_uc, REG_PC) = (uintptr_t)user_handler;
1798 
1799 #if defined(_LP64)
1800                 /*
1801                  * Pass signal handler arguments by registers on AMD64.
1802                  */
1803                 LX_REG(&jump_uc, REG_RDI) = hargs[0];
1804                 LX_REG(&jump_uc, REG_RSI) = hargs[1];
1805                 LX_REG(&jump_uc, REG_RDX) = hargs[2];
1806 #endif
1807 
1808                 lx_jump_to_linux(&jump_uc);


1809         }

1810 
1811         assert(0);
1812         abort();
1813 
1814 after_signal_handler:
1815         /*
1816          * Ensure all nested signal handlers have completed correctly
1817          * and then remove our stack reservation.
1818          */
1819         _sigoff();
1820         LX_SIGNAL_POST_HANDLER(lxfp, old_tsd_sp);
1821         assert(lxtsd->lxtsd_lx_sp == lxfp);
1822         lx_debug("lx_sigdeliver: after; Linux tsd sp %p -> %p\n", lxfp,
1823             old_tsd_sp);
1824         lxtsd->lxtsd_lx_sp = old_tsd_sp;
1825         if (newstack) {
1826                 LX_SIGNAL_ALTSTACK_DISABLE();
1827                 lx_debug("lx_sigdeliver: disabling ALTSTACK sp %p\n", lxfp);
1828                 lxtsd->lxtsd_sigaltstack.ss_flags &= ~LX_SS_ONSTACK;
1829         }
1830         /*
1831          * Restore backup signal tracking chain pointer to previous value:
1832          */