1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-16 15:11:52 +00:00

If check_deferred_signal() execution needs binding of PLT symbol,

unlocking the rtld bind lock results in the processing of ast and
recursing into the check_deferred_signal().  Nested execution of
check_deferred_signal() delivers the signal to user code and clears
si_signo.  On return, top-level check_deferred_signal() frame
continues delivering the same signal one more time, but now with zero
si_signo.

Fix this by adding a flag to indicate that deferred delivery is
running, so check_deferred_signal() should avoid doing anything. Since
user signal handler is allowed to modify the passed machine context to
make return from the signal handler to cause arbitrary jump, or do
longjmp(). For this case, also clear the flag in thr_sighandler(),
since kernel signal delivery means that nested delivery code should
not run right now.

Reported by:	Vitaly Magerya <vmagerya@gmail.com>
Reviewed by:	davidxu, jilles
Tested by:	pho
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
This commit is contained in:
Konstantin Belousov 2013-11-23 15:48:17 +00:00
parent 8a8d9d1475
commit 0a9655a082
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=258499
2 changed files with 10 additions and 2 deletions

View File

@ -433,6 +433,9 @@ struct pthread {
/* the sigaction should be used for deferred signal. */
struct sigaction deferred_sigact;
/* deferred signal delivery is performed, do not reenter. */
int deferred_run;
/* Force new thread to exit. */
int force_exit;

View File

@ -162,6 +162,7 @@ thr_sighandler(int sig, siginfo_t *info, void *_ucp)
act = _thr_sigact[sig-1].sigact;
_thr_rwl_unlock(&_thr_sigact[sig-1].lock);
errno = err;
curthread->deferred_run = 0;
/*
* if a thread is in critical region, for example it holds low level locks,
@ -320,14 +321,18 @@ check_deferred_signal(struct pthread *curthread)
siginfo_t info;
int uc_len;
if (__predict_true(curthread->deferred_siginfo.si_signo == 0))
if (__predict_true(curthread->deferred_siginfo.si_signo == 0 ||
curthread->deferred_run))
return;
curthread->deferred_run = 1;
uc_len = __getcontextx_size();
uc = alloca(uc_len);
getcontext(uc);
if (curthread->deferred_siginfo.si_signo == 0)
if (curthread->deferred_siginfo.si_signo == 0) {
curthread->deferred_run = 0;
return;
}
__fillcontextx2((char *)uc);
act = curthread->deferred_sigact;
uc->uc_sigmask = curthread->deferred_sigmask;