sched/signal: add sanity check for siginfo

add sanity check for siginfo to ensure whether there is really a
consumer waiting for the signal, since the task state will not be
changed appropriately if in cancel/killed case

Test Case:
https://github.com/linux-test-project/ltp/blob/master/testcases/open_posix_testsuite/conformance/interfaces/sigpause/1-1.c#L63

Signed-off-by: chao an <anchao@lixiang.com>
This commit is contained in:
chao an
2024-03-26 09:15:32 +08:00
committed by Xiang Xiao
parent 33485cfe7c
commit a8de85de0b
2 changed files with 30 additions and 14 deletions
+8
View File
@@ -397,8 +397,12 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t *info)
if (stcb->task_state == TSTATE_WAIT_SIG && if (stcb->task_state == TSTATE_WAIT_SIG &&
(masked == 0 || (masked == 0 ||
nxsig_ismember(&stcb->sigwaitmask, info->si_signo))) nxsig_ismember(&stcb->sigwaitmask, info->si_signo)))
{
if (stcb->sigunbinfo != NULL)
{ {
memcpy(stcb->sigunbinfo, info, sizeof(siginfo_t)); memcpy(stcb->sigunbinfo, info, sizeof(siginfo_t));
}
sigemptyset(&stcb->sigwaitmask); sigemptyset(&stcb->sigwaitmask);
if (WDOG_ISACTIVE(&stcb->waitdog)) if (WDOG_ISACTIVE(&stcb->waitdog))
@@ -460,8 +464,12 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t *info)
*/ */
if (stcb->task_state == TSTATE_WAIT_SIG) if (stcb->task_state == TSTATE_WAIT_SIG)
{
if (stcb->sigunbinfo != NULL)
{ {
memcpy(stcb->sigunbinfo, info, sizeof(siginfo_t)); memcpy(stcb->sigunbinfo, info, sizeof(siginfo_t));
}
sigemptyset(&stcb->sigwaitmask); sigemptyset(&stcb->sigwaitmask);
if (WDOG_ISACTIVE(&stcb->waitdog)) if (WDOG_ISACTIVE(&stcb->waitdog))
+8
View File
@@ -99,6 +99,8 @@ static void nxsig_timeout(wdparm_t arg)
{ {
FAR struct tcb_s *rtcb = this_task(); FAR struct tcb_s *rtcb = this_task();
if (wtcb->sigunbinfo != NULL)
{
wtcb->sigunbinfo->si_signo = SIG_WAIT_TIMEOUT; wtcb->sigunbinfo->si_signo = SIG_WAIT_TIMEOUT;
wtcb->sigunbinfo->si_code = SI_TIMER; wtcb->sigunbinfo->si_code = SI_TIMER;
wtcb->sigunbinfo->si_errno = ETIMEDOUT; wtcb->sigunbinfo->si_errno = ETIMEDOUT;
@@ -107,6 +109,7 @@ static void nxsig_timeout(wdparm_t arg)
wtcb->sigunbinfo->si_pid = 0; /* Not applicable */ wtcb->sigunbinfo->si_pid = 0; /* Not applicable */
wtcb->sigunbinfo->si_status = OK; wtcb->sigunbinfo->si_status = OK;
#endif #endif
}
/* Remove the task from waitting list */ /* Remove the task from waitting list */
@@ -166,6 +169,8 @@ void nxsig_wait_irq(FAR struct tcb_s *wtcb, int errcode)
{ {
FAR struct tcb_s *rtcb = this_task(); FAR struct tcb_s *rtcb = this_task();
if (wtcb->sigunbinfo != NULL)
{
wtcb->sigunbinfo->si_signo = SIG_CANCEL_TIMEOUT; wtcb->sigunbinfo->si_signo = SIG_CANCEL_TIMEOUT;
wtcb->sigunbinfo->si_code = SI_USER; wtcb->sigunbinfo->si_code = SI_USER;
wtcb->sigunbinfo->si_errno = errcode; wtcb->sigunbinfo->si_errno = errcode;
@@ -174,6 +179,7 @@ void nxsig_wait_irq(FAR struct tcb_s *wtcb, int errcode)
wtcb->sigunbinfo->si_pid = 0; /* Not applicable */ wtcb->sigunbinfo->si_pid = 0; /* Not applicable */
wtcb->sigunbinfo->si_status = OK; wtcb->sigunbinfo->si_status = OK;
#endif #endif
}
/* Remove the task from waitting list */ /* Remove the task from waitting list */
@@ -376,6 +382,8 @@ int nxsig_timedwait(FAR const sigset_t *set, FAR struct siginfo *info,
} }
else else
{ {
rtcb->sigunbinfo = NULL;
leave_critical_section(flags); leave_critical_section(flags);
return -EAGAIN; return -EAGAIN;
} }