diff --git a/drivers/input/button_upper.c b/drivers/input/button_upper.c index ed9f239ba50..40cca92c40d 100644 --- a/drivers/input/button_upper.c +++ b/drivers/input/button_upper.c @@ -638,7 +638,7 @@ static int btn_ioctl(FAR struct file *filep, int cmd, unsigned long arg) FAR struct btn_notify_s *notify = (FAR struct btn_notify_s *)((uintptr_t)arg); - if (notify) + if (notify && nxsig_event_valid(¬ify->bn_event) == OK) { /* Save the notification events */ diff --git a/drivers/ioexpander/gpio.c b/drivers/ioexpander/gpio.c index f4bb08468eb..3fbcb0e0db6 100644 --- a/drivers/ioexpander/gpio.c +++ b/drivers/ioexpander/gpio.c @@ -829,6 +829,13 @@ static int gpio_ioctl(FAR struct file *filep, int cmd, unsigned long arg) #if CONFIG_DEV_GPIO_NSIGNALS > 0 if (arg) { + ret = nxsig_event_valid((FAR struct sigevent *)arg); + if (ret < 0) + { + leave_critical_section(flags); + break; + } + pid = nxsched_getpid(); for (i = 0; i < CONFIG_DEV_GPIO_NSIGNALS; i++) { diff --git a/drivers/net/phy_notify.c b/drivers/net/phy_notify.c index 57d086fdaa3..88a6beec642 100644 --- a/drivers/net/phy_notify.c +++ b/drivers/net/phy_notify.c @@ -290,6 +290,12 @@ int phy_notify_subscribe(FAR const char *intf, pid_t pid, return phy_notify_unsubscribe(intf, pid); } + ret = nxsig_event_valid(event); + if (ret < 0) + { + return ret; + } + /* Check if this client already exists */ client = phy_find_assigned(intf, pid); diff --git a/include/nuttx/signal.h b/include/nuttx/signal.h index f58dc6f901f..7c334517be5 100644 --- a/include/nuttx/signal.h +++ b/include/nuttx/signal.h @@ -691,6 +691,24 @@ unsigned int nxsig_sleep(unsigned int seconds); int nxsig_usleep(useconds_t usec); +/**************************************************************************** + * Name: nxsig_event_valid + * + * Description: + * Check a sigevent handed in by the calling task before it is stored: + * its signal must exist and a SIGEV_THREAD_ID target must be one of the + * caller's own threads. + * + * Input Parameters: + * event - The instance of struct sigevent to check. + * + * Returned Value: + * Zero (OK) if the event may be stored; -EINVAL if not. + * + ****************************************************************************/ + +int nxsig_event_valid(FAR const struct sigevent *event); + /**************************************************************************** * Name: nxsig_notification * diff --git a/sched/signal/sig_notification.c b/sched/signal/sig_notification.c index a7948c33974..2a3778f2ef6 100644 --- a/sched/signal/sig_notification.c +++ b/sched/signal/sig_notification.c @@ -92,6 +92,50 @@ static void nxsig_notification_worker(FAR void *arg) * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: nxsig_event_valid + * + * Description: + * Check a sigevent handed in by the calling task before it is stored: + * its signal must exist and a SIGEV_THREAD_ID target must be one of the + * caller's own threads. + * + * Input Parameters: + * event - The instance of struct sigevent to check. + * + * Returned Value: + * Zero (OK) if the event may be stored; -EINVAL if not. + * + ****************************************************************************/ + +int nxsig_event_valid(FAR const struct sigevent *event) +{ + FAR struct tcb_s *target; + + if ((event->sigev_notify & SIGEV_SIGNAL) == 0) + { + return OK; + } + + if (!GOOD_SIGNO(event->sigev_signo)) + { + return -EINVAL; + } + + if ((event->sigev_notify & SIGEV_THREAD_ID) == 0) + { + return OK; + } + + target = nxsched_get_tcb(event->sigev_notify_thread_id); + if (target == NULL || target->group != nxsched_self()->group) + { + return -EINVAL; + } + + return OK; +} + /**************************************************************************** * Name: nxsig_notification * diff --git a/sched/timer/timer_create.c b/sched/timer/timer_create.c index c756ed2c66e..42c39b84f87 100644 --- a/sched/timer/timer_create.c +++ b/sched/timer/timer_create.c @@ -169,8 +169,7 @@ int timer_create(clockid_t clockid, FAR struct sigevent *evp, if (timerid == NULL || (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC && clockid != CLOCK_BOOTTIME) || - (evp != NULL && evp->sigev_notify == SIGEV_SIGNAL && - !GOOD_SIGNO(evp->sigev_signo))) + (evp != NULL && nxsig_event_valid(evp) < 0)) { set_errno(EINVAL); }