Use sigfastblock(2) for masking signals in libthr.

Ensure proper handshake to transfer sigfastblock(2) blocking word
ownership from rtld to libthr.

Unfortunately sigfastblock(2) is not enough to stop intercepting
signals in libthr, because critical sections must ensure more than
just signal blocking.

Tested by:	pho
Disscussed with:	cem, emaste, jilles
Sponsored by:	The FreeBSD Foundation
Differential revision:	https://reviews.freebsd.org/D12773
This commit is contained in:
Konstantin Belousov 2020-02-09 12:27:22 +00:00
parent aef199e563
commit fc908e5001
4 changed files with 69 additions and 6 deletions

View File

@ -257,6 +257,7 @@ thread_start(struct pthread *curthread)
if (curthread->attr.suspend == THR_CREATE_SUSPENDED)
set = curthread->sigmask;
_thr_signal_block_setup(curthread);
/*
* This is used as a serialization point to allow parent

View File

@ -396,6 +396,9 @@ struct pthread {
/* Signal blocked counter. */
int sigblock;
/* Fast sigblock var. */
uint32_t fsigblock;
/* Queue entry for list of all threads. */
TAILQ_ENTRY(pthread) tle; /* link for all threads in process */
@ -813,6 +816,8 @@ void _thr_cancel_leave(struct pthread *, int) __hidden;
void _thr_testcancel(struct pthread *) __hidden;
void _thr_signal_block(struct pthread *) __hidden;
void _thr_signal_unblock(struct pthread *) __hidden;
void _thr_signal_block_check_fast(void) __hidden;
void _thr_signal_block_setup(struct pthread *) __hidden;
void _thr_signal_init(int) __hidden;
void _thr_signal_deinit(void) __hidden;
int _thr_send_sig(struct pthread *, int sig) __hidden;

View File

@ -236,6 +236,8 @@ _thr_rtld_init(void)
_thr_signal_block(curthread);
_rtld_thread_init(&li);
_thr_signal_unblock(curthread);
_thr_signal_block_check_fast();
_thr_signal_block_setup(curthread);
uc_len = __getcontextx_size();
uc = alloca(uc_len);

View File

@ -31,7 +31,8 @@ __FBSDID("$FreeBSD$");
#include "namespace.h"
#include <sys/param.h>
#include <sys/types.h>
#include <sys/auxv.h>
#include <sys/elf.h>
#include <sys/signalvar.h>
#include <sys/syscall.h>
#include <signal.h>
@ -92,10 +93,9 @@ static const sigset_t _thr_maskset={{
0xffffffff,
0xffffffff}};
void
_thr_signal_block(struct pthread *curthread)
static void
thr_signal_block_slow(struct pthread *curthread)
{
if (curthread->sigblock > 0) {
curthread->sigblock++;
return;
@ -104,13 +104,68 @@ _thr_signal_block(struct pthread *curthread)
curthread->sigblock++;
}
void
_thr_signal_unblock(struct pthread *curthread)
static void
thr_signal_unblock_slow(struct pthread *curthread)
{
if (--curthread->sigblock == 0)
__sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
}
static void
thr_signal_block_fast(struct pthread *curthread)
{
atomic_add_32(&curthread->fsigblock, SIGFASTBLOCK_INC);
}
static void
thr_signal_unblock_fast(struct pthread *curthread)
{
uint32_t oldval;
oldval = atomic_fetchadd_32(&curthread->fsigblock, -SIGFASTBLOCK_INC);
if (oldval == (SIGFASTBLOCK_PEND | SIGFASTBLOCK_INC))
__sys_sigfastblock(SIGFASTBLOCK_UNBLOCK, NULL);
}
static bool fast_sigblock;
void
_thr_signal_block(struct pthread *curthread)
{
if (fast_sigblock)
thr_signal_block_fast(curthread);
else
thr_signal_block_slow(curthread);
}
void
_thr_signal_unblock(struct pthread *curthread)
{
if (fast_sigblock)
thr_signal_unblock_fast(curthread);
else
thr_signal_unblock_slow(curthread);
}
void
_thr_signal_block_check_fast(void)
{
int bsdflags, error;
error = elf_aux_info(AT_BSDFLAGS, &bsdflags, sizeof(bsdflags));
if (error != 0)
return;
fast_sigblock = (bsdflags & ELF_BSDF_SIGFASTBLK) != 0;
}
void
_thr_signal_block_setup(struct pthread *curthread)
{
if (!fast_sigblock)
return;
__sys_sigfastblock(SIGFASTBLOCK_SETPTR, &curthread->fsigblock);
}
int
_thr_send_sig(struct pthread *thread, int sig)
{