1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-03 12:35:02 +00:00

When entering the scheduler from the signal handler, tell

the kernel to (re)use the alternate signal stack.  In this
case, we don't return normally from the signal handler,
so the kernel still thinks we are using the signal stack.
The fixes a nasty bug where the signal handler can start
fiddling with the stack of a thread while the handler is
actually running on the same stack.

MFC candidate
This commit is contained in:
Daniel Eischen 2000-11-14 20:00:19 +00:00
parent fa167b8eaa
commit eb4463fde6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=68726
12 changed files with 114 additions and 57 deletions

View File

@ -1127,6 +1127,9 @@ SCLASS volatile int _sigq_check_reqd
#endif
;
/* The signal stack. */
SCLASS struct sigaltstack _thread_sigstack;
/* Thread switch hook. */
SCLASS pthread_switch_routine_t _sched_switch_hook
#ifdef GLOBAL_PTHREAD_PRIVATE
@ -1268,7 +1271,7 @@ int _thread_sys_sigsuspend(const sigset_t *);
int _thread_sys_siginterrupt(int, int);
int _thread_sys_sigpause(int);
int _thread_sys_sigreturn(ucontext_t *);
int _thread_sys_sigaltstack(const struct sigaltstack *, struct sigstack *);
int _thread_sys_sigaltstack(const struct sigaltstack *, struct sigaltstack *);
int _thread_sys_sigstack(const struct sigstack *, struct sigstack *);
int _thread_sys_sigvec(int, struct sigvec *, struct sigvec *);
void _thread_sys_psignal(unsigned int, const char *);

View File

@ -92,7 +92,6 @@ _thread_init(void)
int mib[2];
struct clockinfo clockinfo;
struct sigaction act;
struct sigaltstack alt;
/* Check if this function has already been called: */
if (_thread_initial)
@ -281,11 +280,15 @@ _thread_init(void)
/* Clear the signal queue: */
memset(_thread_sigq, 0, sizeof(_thread_sigq));
/* Create and install an alternate signal stack: */
alt.ss_sp = malloc(SIGSTKSZ); /* recommended stack size */
alt.ss_size = SIGSTKSZ;
alt.ss_flags = 0;
if (_thread_sys_sigaltstack(&alt, NULL) != 0)
/*
* Create and install an alternate signal stack of
* the recommended size:
*/
_thread_sigstack.ss_sp = malloc(SIGSTKSZ);
_thread_sigstack.ss_size = SIGSTKSZ;
_thread_sigstack.ss_flags = 0;
if ((_thread_sigstack.ss_sp == NULL) ||
(_thread_sys_sigaltstack(&_thread_sigstack, NULL) != 0))
PANIC("Unable to install alternate signal stack");
/* Enter a loop to get the existing signal status: */

View File

@ -71,6 +71,7 @@ thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in);
/* Static variables: */
static int last_tick = 0;
static int called_from_handler = 0;
/*
* This is called when a signal handler finishes and wants to
@ -106,20 +107,12 @@ _thread_kern_sched(ucontext_t *scp)
/* Check if this function was called from the signal handler: */
if (scp != NULL) {
/*
* The signal handler should have saved the state of
* the current thread. Restore the process signal
* mask.
*/
if (_thread_sys_sigprocmask(SIG_SETMASK,
&_process_sigmask, NULL) != 0)
PANIC("Unable to restore process mask after signal");
called_from_handler = 1;
/*
* We're running on the signal stack; just call the
* kernel scheduler directly.
*/
DBG_MSG("Entering scheduler due to signal\n");
_thread_kern_scheduler();
} else {
/* Save the state of the current thread: */
if (_setjmp(_thread_run->ctx.jb) == 0) {
@ -162,9 +155,9 @@ _thread_kern_sched(ucontext_t *scp)
}
return;
}
/* Switch to the thread scheduler: */
___longjmp(_thread_kern_sched_jb, 1);
}
/* Switch to the thread scheduler: */
___longjmp(_thread_kern_sched_jb, 1);
}
void
@ -188,6 +181,26 @@ _thread_kern_scheduler(void)
if ((_thread_run->flags & PTHREAD_FLAGS_PRIVATE) == 0)
_last_user_thread = _thread_run;
if (called_from_handler != 0) {
called_from_handler = 0;
/*
* The signal handler should have saved the state of
* the current thread. Restore the process signal
* mask.
*/
if (_thread_sys_sigprocmask(SIG_SETMASK,
&_process_sigmask, NULL) != 0)
PANIC("Unable to restore process mask after signal");
/*
* Since the signal handler didn't return normally, we
* have to tell the kernel to reuse the signal stack.
*/
if (_thread_sys_sigaltstack(&_thread_sigstack, NULL) != 0)
PANIC("Unable to restore alternate signal stack");
}
/* Are there pending signals for this thread? */
if (_thread_run->check_pending != 0) {
_thread_run->check_pending = 0;

View File

@ -1066,7 +1066,7 @@ thread_sigframe_add(pthread_t thread, int sig, int has_args)
/*
* Set up the context:
*/
stackp += sizeof(double);
stackp -= sizeof(double);
_setjmp(thread->ctx.jb);
SET_STACK_JB(thread->ctx.jb, stackp);
SET_RETURN_ADDR_JB(thread->ctx.jb, _thread_sig_wrapper);

View File

@ -92,7 +92,6 @@ _thread_init(void)
int mib[2];
struct clockinfo clockinfo;
struct sigaction act;
struct sigaltstack alt;
/* Check if this function has already been called: */
if (_thread_initial)
@ -281,11 +280,15 @@ _thread_init(void)
/* Clear the signal queue: */
memset(_thread_sigq, 0, sizeof(_thread_sigq));
/* Create and install an alternate signal stack: */
alt.ss_sp = malloc(SIGSTKSZ); /* recommended stack size */
alt.ss_size = SIGSTKSZ;
alt.ss_flags = 0;
if (_thread_sys_sigaltstack(&alt, NULL) != 0)
/*
* Create and install an alternate signal stack of
* the recommended size:
*/
_thread_sigstack.ss_sp = malloc(SIGSTKSZ);
_thread_sigstack.ss_size = SIGSTKSZ;
_thread_sigstack.ss_flags = 0;
if ((_thread_sigstack.ss_sp == NULL) ||
(_thread_sys_sigaltstack(&_thread_sigstack, NULL) != 0))
PANIC("Unable to install alternate signal stack");
/* Enter a loop to get the existing signal status: */

View File

@ -71,6 +71,7 @@ thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in);
/* Static variables: */
static int last_tick = 0;
static int called_from_handler = 0;
/*
* This is called when a signal handler finishes and wants to
@ -106,20 +107,12 @@ _thread_kern_sched(ucontext_t *scp)
/* Check if this function was called from the signal handler: */
if (scp != NULL) {
/*
* The signal handler should have saved the state of
* the current thread. Restore the process signal
* mask.
*/
if (_thread_sys_sigprocmask(SIG_SETMASK,
&_process_sigmask, NULL) != 0)
PANIC("Unable to restore process mask after signal");
called_from_handler = 1;
/*
* We're running on the signal stack; just call the
* kernel scheduler directly.
*/
DBG_MSG("Entering scheduler due to signal\n");
_thread_kern_scheduler();
} else {
/* Save the state of the current thread: */
if (_setjmp(_thread_run->ctx.jb) == 0) {
@ -162,9 +155,9 @@ _thread_kern_sched(ucontext_t *scp)
}
return;
}
/* Switch to the thread scheduler: */
___longjmp(_thread_kern_sched_jb, 1);
}
/* Switch to the thread scheduler: */
___longjmp(_thread_kern_sched_jb, 1);
}
void
@ -188,6 +181,26 @@ _thread_kern_scheduler(void)
if ((_thread_run->flags & PTHREAD_FLAGS_PRIVATE) == 0)
_last_user_thread = _thread_run;
if (called_from_handler != 0) {
called_from_handler = 0;
/*
* The signal handler should have saved the state of
* the current thread. Restore the process signal
* mask.
*/
if (_thread_sys_sigprocmask(SIG_SETMASK,
&_process_sigmask, NULL) != 0)
PANIC("Unable to restore process mask after signal");
/*
* Since the signal handler didn't return normally, we
* have to tell the kernel to reuse the signal stack.
*/
if (_thread_sys_sigaltstack(&_thread_sigstack, NULL) != 0)
PANIC("Unable to restore alternate signal stack");
}
/* Are there pending signals for this thread? */
if (_thread_run->check_pending != 0) {
_thread_run->check_pending = 0;

View File

@ -1127,6 +1127,9 @@ SCLASS volatile int _sigq_check_reqd
#endif
;
/* The signal stack. */
SCLASS struct sigaltstack _thread_sigstack;
/* Thread switch hook. */
SCLASS pthread_switch_routine_t _sched_switch_hook
#ifdef GLOBAL_PTHREAD_PRIVATE
@ -1268,7 +1271,7 @@ int _thread_sys_sigsuspend(const sigset_t *);
int _thread_sys_siginterrupt(int, int);
int _thread_sys_sigpause(int);
int _thread_sys_sigreturn(ucontext_t *);
int _thread_sys_sigaltstack(const struct sigaltstack *, struct sigstack *);
int _thread_sys_sigaltstack(const struct sigaltstack *, struct sigaltstack *);
int _thread_sys_sigstack(const struct sigstack *, struct sigstack *);
int _thread_sys_sigvec(int, struct sigvec *, struct sigvec *);
void _thread_sys_psignal(unsigned int, const char *);

View File

@ -1066,7 +1066,7 @@ thread_sigframe_add(pthread_t thread, int sig, int has_args)
/*
* Set up the context:
*/
stackp += sizeof(double);
stackp -= sizeof(double);
_setjmp(thread->ctx.jb);
SET_STACK_JB(thread->ctx.jb, stackp);
SET_RETURN_ADDR_JB(thread->ctx.jb, _thread_sig_wrapper);

View File

@ -92,7 +92,6 @@ _thread_init(void)
int mib[2];
struct clockinfo clockinfo;
struct sigaction act;
struct sigaltstack alt;
/* Check if this function has already been called: */
if (_thread_initial)
@ -281,11 +280,15 @@ _thread_init(void)
/* Clear the signal queue: */
memset(_thread_sigq, 0, sizeof(_thread_sigq));
/* Create and install an alternate signal stack: */
alt.ss_sp = malloc(SIGSTKSZ); /* recommended stack size */
alt.ss_size = SIGSTKSZ;
alt.ss_flags = 0;
if (_thread_sys_sigaltstack(&alt, NULL) != 0)
/*
* Create and install an alternate signal stack of
* the recommended size:
*/
_thread_sigstack.ss_sp = malloc(SIGSTKSZ);
_thread_sigstack.ss_size = SIGSTKSZ;
_thread_sigstack.ss_flags = 0;
if ((_thread_sigstack.ss_sp == NULL) ||
(_thread_sys_sigaltstack(&_thread_sigstack, NULL) != 0))
PANIC("Unable to install alternate signal stack");
/* Enter a loop to get the existing signal status: */

View File

@ -71,6 +71,7 @@ thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in);
/* Static variables: */
static int last_tick = 0;
static int called_from_handler = 0;
/*
* This is called when a signal handler finishes and wants to
@ -106,20 +107,12 @@ _thread_kern_sched(ucontext_t *scp)
/* Check if this function was called from the signal handler: */
if (scp != NULL) {
/*
* The signal handler should have saved the state of
* the current thread. Restore the process signal
* mask.
*/
if (_thread_sys_sigprocmask(SIG_SETMASK,
&_process_sigmask, NULL) != 0)
PANIC("Unable to restore process mask after signal");
called_from_handler = 1;
/*
* We're running on the signal stack; just call the
* kernel scheduler directly.
*/
DBG_MSG("Entering scheduler due to signal\n");
_thread_kern_scheduler();
} else {
/* Save the state of the current thread: */
if (_setjmp(_thread_run->ctx.jb) == 0) {
@ -162,9 +155,9 @@ _thread_kern_sched(ucontext_t *scp)
}
return;
}
/* Switch to the thread scheduler: */
___longjmp(_thread_kern_sched_jb, 1);
}
/* Switch to the thread scheduler: */
___longjmp(_thread_kern_sched_jb, 1);
}
void
@ -188,6 +181,26 @@ _thread_kern_scheduler(void)
if ((_thread_run->flags & PTHREAD_FLAGS_PRIVATE) == 0)
_last_user_thread = _thread_run;
if (called_from_handler != 0) {
called_from_handler = 0;
/*
* The signal handler should have saved the state of
* the current thread. Restore the process signal
* mask.
*/
if (_thread_sys_sigprocmask(SIG_SETMASK,
&_process_sigmask, NULL) != 0)
PANIC("Unable to restore process mask after signal");
/*
* Since the signal handler didn't return normally, we
* have to tell the kernel to reuse the signal stack.
*/
if (_thread_sys_sigaltstack(&_thread_sigstack, NULL) != 0)
PANIC("Unable to restore alternate signal stack");
}
/* Are there pending signals for this thread? */
if (_thread_run->check_pending != 0) {
_thread_run->check_pending = 0;

View File

@ -1127,6 +1127,9 @@ SCLASS volatile int _sigq_check_reqd
#endif
;
/* The signal stack. */
SCLASS struct sigaltstack _thread_sigstack;
/* Thread switch hook. */
SCLASS pthread_switch_routine_t _sched_switch_hook
#ifdef GLOBAL_PTHREAD_PRIVATE
@ -1268,7 +1271,7 @@ int _thread_sys_sigsuspend(const sigset_t *);
int _thread_sys_siginterrupt(int, int);
int _thread_sys_sigpause(int);
int _thread_sys_sigreturn(ucontext_t *);
int _thread_sys_sigaltstack(const struct sigaltstack *, struct sigstack *);
int _thread_sys_sigaltstack(const struct sigaltstack *, struct sigaltstack *);
int _thread_sys_sigstack(const struct sigstack *, struct sigstack *);
int _thread_sys_sigvec(int, struct sigvec *, struct sigvec *);
void _thread_sys_psignal(unsigned int, const char *);

View File

@ -1066,7 +1066,7 @@ thread_sigframe_add(pthread_t thread, int sig, int has_args)
/*
* Set up the context:
*/
stackp += sizeof(double);
stackp -= sizeof(double);
_setjmp(thread->ctx.jb);
SET_STACK_JB(thread->ctx.jb, stackp);
SET_RETURN_ADDR_JB(thread->ctx.jb, _thread_sig_wrapper);