This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 6935c374a2eb40ada74eee1aeb9c534a6b688d6d Author: Royyan Zahir <[email protected]> AuthorDate: Thu Oct 1 15:05:09 2026 +0400 sched: acting on another process needs PR_CAP_ADMIN kill, tgkill, sigqueue, sched_setparam, sched_setscheduler, sched_setaffinity, the pthread set calls, pthread_cancel and PR_SET_NAME_EXT acted on any thread in the system. They now need PR_CAP_ADMIN when the target is outside the caller's process, in every build. Signal 0 stays open. Kernel callers use the nx variants and stay unchecked. Signed-off-by: Royyan Zahir <[email protected]> --- Documentation/os/scheduling/capabilities.rst | 12 +++-- sched/pthread/pthread_cancel.c | 5 ++ sched/pthread/pthread_setaffinity.c | 6 +++ sched/pthread/pthread_setschedparam.c | 6 +++ sched/pthread/pthread_setschedprio.c | 5 ++ sched/sched/CMakeLists.txt | 4 ++ sched/sched/Make.defs | 4 ++ sched/sched/sched.h | 7 +++ .../sched_maycontrol.c} | 60 ++++++---------------- sched/sched/sched_setaffinity.c | 10 +++- sched/sched/sched_setparam.c | 9 +++- sched/sched/sched_setscheduler.c | 9 +++- sched/signal/sig_kill.c | 6 +++ sched/signal/sig_queue.c | 6 +++ sched/signal/sig_tgkill.c | 6 +++ sched/task/task_prctl.c | 6 +++ 16 files changed, 110 insertions(+), 51 deletions(-) diff --git a/Documentation/os/scheduling/capabilities.rst b/Documentation/os/scheduling/capabilities.rst index 23e979a8294..40f23a2b8a2 100644 --- a/Documentation/os/scheduling/capabilities.rst +++ b/Documentation/os/scheduling/capabilities.rst @@ -13,7 +13,9 @@ with ``EPERM``. Every build, the kernel and init start with all three. ``mount()``, ``umount2()`` ``PR_CAP_SPAWN`` ``posix_spawn()``, ``task_spawn()``, ``task_create()``, ``exec()``, ``execve()`` -``PR_CAP_ADMIN`` ``boardctl()`` reset and poweroff +``PR_CAP_ADMIN`` ``boardctl()`` reset and poweroff; signalling, + rescheduling, cancelling or renaming a thread of + another process (signal 0 stays open) ================= ================================================== .. code-block:: c @@ -22,6 +24,8 @@ with ``EPERM``. Every build, the kernel and init start with all three. int caps = prctl(PR_CAPS_GET); A drop is permanent. The set lives in the task group and a new group copies -its creator's. The checks sit in the internal functions, so kernel code -running for a process is held to that process's set. Kernel threads hold -all three. +its creator's. The spawn and raw storage checks sit in the internal +functions, so kernel code running for a process is held to that process's +set. The cross-process checks sit in the public calls, since the kernel +signals and reschedules other processes on its own account through the +unchecked ``nx`` variants. Kernel threads hold all three. diff --git a/sched/pthread/pthread_cancel.c b/sched/pthread/pthread_cancel.c index aa631d984c6..abe2b81b126 100644 --- a/sched/pthread/pthread_cancel.c +++ b/sched/pthread/pthread_cancel.c @@ -57,6 +57,11 @@ int pthread_cancel(pthread_t thread) return ESRCH; } + if (!nxsched_may_control((pid_t)thread)) + { + return EPERM; + } + tcb = nxsched_get_tcb((pid_t)thread); if (tcb == NULL) { diff --git a/sched/pthread/pthread_setaffinity.c b/sched/pthread/pthread_setaffinity.c index 9f49786591d..895712cad8d 100644 --- a/sched/pthread/pthread_setaffinity.c +++ b/sched/pthread/pthread_setaffinity.c @@ -37,6 +37,7 @@ #include <nuttx/sched.h> #include "pthread/pthread.h" +#include "sched/sched.h" #ifdef CONFIG_SMP @@ -79,6 +80,11 @@ int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, sinfo("thread ID=%d cpusetsize=%zu cpuset=%ju\n", (int)thread, cpusetsize, (uintmax_t)*cpuset); + if (!nxsched_may_control((pid_t)thread)) + { + return EPERM; + } + /* Let nxsched_set_affinity do all of the work, adjusting the return * value. */ diff --git a/sched/pthread/pthread_setschedparam.c b/sched/pthread/pthread_setschedparam.c index c1534f26741..adb430e7bc2 100644 --- a/sched/pthread/pthread_setschedparam.c +++ b/sched/pthread/pthread_setschedparam.c @@ -35,6 +35,7 @@ #include <nuttx/sched.h> #include "pthread/pthread.h" +#include "sched/sched.h" /**************************************************************************** * Public Functions @@ -95,6 +96,11 @@ int pthread_setschedparam(pthread_t thread, int policy, sinfo("thread ID=%d policy=%d param=%p\n", thread, policy, param); + if (!nxsched_may_control((pid_t)thread)) + { + return EPERM; + } + /* Let nxsched_set_scheduler do all of the work */ ret = nxsched_set_scheduler((pid_t)thread, policy, param); diff --git a/sched/pthread/pthread_setschedprio.c b/sched/pthread/pthread_setschedprio.c index 5c50d5501b8..46a7c0edac0 100644 --- a/sched/pthread/pthread_setschedprio.c +++ b/sched/pthread/pthread_setschedprio.c @@ -69,6 +69,11 @@ int pthread_setschedprio(pthread_t thread, int prio) struct sched_param param; int ret; + if (!nxsched_may_control((pid_t)thread)) + { + return EPERM; + } + #ifdef CONFIG_SCHED_SPORADIC /* Get the current sporadic scheduling parameters. Those will not be * modified. diff --git a/sched/sched/CMakeLists.txt b/sched/sched/CMakeLists.txt index 9c2cb617da4..5daf47917b5 100644 --- a/sched/sched/CMakeLists.txt +++ b/sched/sched/CMakeLists.txt @@ -64,6 +64,10 @@ if(CONFIG_PRIORITY_INHERITANCE) list(APPEND SRCS sched_reprioritize.c) endif() +if(CONFIG_SCHED_CAPABILITIES) + list(APPEND SRCS sched_maycontrol.c) +endif() + if(CONFIG_SMP) list(APPEND SRCS sched_getaffinity.c sched_setaffinity.c sched_process_delivered.c) diff --git a/sched/sched/Make.defs b/sched/sched/Make.defs index a612b244b0d..a7e5bb8a614 100644 --- a/sched/sched/Make.defs +++ b/sched/sched/Make.defs @@ -46,6 +46,10 @@ ifeq ($(CONFIG_PRIORITY_INHERITANCE),y) CSRCS += sched_reprioritize.c endif +ifeq ($(CONFIG_SCHED_CAPABILITIES),y) +CSRCS += sched_maycontrol.c +endif + ifeq ($(CONFIG_SMP),y) CSRCS += sched_process_delivered.c CSRCS += sched_getaffinity.c sched_setaffinity.c diff --git a/sched/sched/sched.h b/sched/sched/sched.h index bd595f55d1b..bd61caf97b3 100644 --- a/sched/sched/sched.h +++ b/sched/sched/sched.h @@ -460,6 +460,12 @@ void nxsched_critmon_csection(FAR struct tcb_s *tcb, bool state, FAR void *caller); #endif +#ifdef CONFIG_SCHED_CAPABILITIES +bool nxsched_may_control(pid_t pid); +#else +# define nxsched_may_control(pid) true +#endif + /* TCB operations */ bool nxsched_verify_tcb(FAR struct tcb_s *tcb); @@ -639,4 +645,5 @@ static inline_function int nxsched_select_cpu(cpu_set_t affinity) return cpu; } # endif + #endif /* __SCHED_SCHED_SCHED_H */ diff --git a/sched/pthread/pthread_setschedprio.c b/sched/sched/sched_maycontrol.c similarity index 54% copy from sched/pthread/pthread_setschedprio.c copy to sched/sched/sched_maycontrol.c index 5c50d5501b8..37a4461440f 100644 --- a/sched/pthread/pthread_setschedprio.c +++ b/sched/sched/sched_maycontrol.c @@ -1,5 +1,5 @@ /**************************************************************************** - * sched/pthread/pthread_setschedprio.c + * sched/sched/sched_maycontrol.c * * SPDX-License-Identifier: Apache-2.0 * @@ -26,12 +26,8 @@ #include <nuttx/config.h> -#include <sys/types.h> -#include <sched.h> -#include <errno.h> - -#include <nuttx/sched.h> -#include <nuttx/arch.h> +#include <stdbool.h> +#include <sys/prctl.h> #include "sched/sched.h" @@ -40,55 +36,31 @@ ****************************************************************************/ /**************************************************************************** - * Name: pthread_setsetprio + * Name: nxsched_may_control * * Description: - * The pthread_setschedprio() function sets the scheduling priority for - * the thread whose thread ID is given by 'thread' to the value given by - * 'prio'. If the thread_setschedprio() function fails, the scheduling - * priority of the target thread will not be changed. + * Check whether the calling thread may act on the thread pid: pid 0 is + * the caller itself, a thread in the caller's process is always allowed, + * one outside it needs PR_CAP_ADMIN. An unknown pid passes so that the + * caller reports ESRCH as before. * * Input Parameters: - * thread - the thread ID of the task to reprioritize. - * prio - The new thread priority. The range of valid priority numbers is - * from SCHED_PRIORITY_MIN through SCHED_PRIORITY_MAX. + * pid - The target thread ID * * Returned Value: - * OK if successful, otherwise an error number. This function can - * fail for the following reasons: - * - * EINVAL - prio is out of range. - * ESRCH - thread ID does not correspond to any thread. - * - * Assumptions: + * True if the caller may act on the target. * ****************************************************************************/ -int pthread_setschedprio(pthread_t thread, int prio) +bool nxsched_may_control(pid_t pid) { - struct sched_param param; - int ret; - -#ifdef CONFIG_SCHED_SPORADIC - /* Get the current sporadic scheduling parameters. Those will not be - * modified. - */ - - ret = nxsched_get_param((pid_t)thread, ¶m); - if (ret < 0) - { - return -ret; - } -#endif - - /* Call nxsched_set_param() to change the priority */ + FAR struct tcb_s *tcb; - param.sched_priority = prio; - ret = nxsched_set_param((pid_t)thread, ¶m); - if (ret < 0) + if (pid == 0 || nxsched_capable(PR_CAP_ADMIN)) { - return -ret; + return true; } - return OK; + tcb = nxsched_get_tcb(pid); + return tcb == NULL || tcb->group == nxsched_self()->group; } diff --git a/sched/sched/sched_setaffinity.c b/sched/sched/sched_setaffinity.c index 2c0173188f6..a4889145247 100644 --- a/sched/sched/sched_setaffinity.c +++ b/sched/sched/sched_setaffinity.c @@ -188,7 +188,15 @@ errout: int sched_setaffinity(pid_t pid, size_t cpusetsize, FAR const cpu_set_t *mask) { - int ret = nxsched_set_affinity(pid, cpusetsize, mask); + int ret; + + if (!nxsched_may_control(pid)) + { + set_errno(EPERM); + return ERROR; + } + + ret = nxsched_set_affinity(pid, cpusetsize, mask); if (ret < 0) { set_errno(-ret); diff --git a/sched/sched/sched_setparam.c b/sched/sched/sched_setparam.c index d9f031712ca..407d0a42a2f 100644 --- a/sched/sched/sched_setparam.c +++ b/sched/sched/sched_setparam.c @@ -236,8 +236,15 @@ int nxsched_set_param(pid_t pid, FAR const struct sched_param *param) int sched_setparam(pid_t pid, FAR const struct sched_param *param) { - int ret = nxsched_set_param(pid, param); + int ret; + if (!nxsched_may_control(pid)) + { + set_errno(EPERM); + return ERROR; + } + + ret = nxsched_set_param(pid, param); if (ret < 0) { set_errno(-ret); diff --git a/sched/sched/sched_setscheduler.c b/sched/sched/sched_setscheduler.c index fd6f632657c..e17c28141ad 100644 --- a/sched/sched/sched_setscheduler.c +++ b/sched/sched/sched_setscheduler.c @@ -288,8 +288,15 @@ int nxsched_set_scheduler(pid_t pid, int policy, int sched_setscheduler(pid_t pid, int policy, FAR const struct sched_param *param) { - int ret = nxsched_set_scheduler(pid, policy, param); + int ret; + + if (!nxsched_may_control(pid)) + { + set_errno(EPERM); + return ERROR; + } + ret = nxsched_set_scheduler(pid, policy, param); if (ret < 0) { set_errno(-ret); diff --git a/sched/signal/sig_kill.c b/sched/signal/sig_kill.c index f2df8d20ed0..1f0f4119286 100644 --- a/sched/signal/sig_kill.c +++ b/sched/signal/sig_kill.c @@ -160,6 +160,12 @@ int kill(pid_t pid, int signo) { int ret; + if (signo != 0 && !nxsched_may_control(pid)) + { + set_errno(EPERM); + return ERROR; + } + /* Let nxsig_kill() do all of the work */ ret = nxsig_kill(pid, signo); diff --git a/sched/signal/sig_queue.c b/sched/signal/sig_queue.c index 96fb9b7ba24..e89992da673 100644 --- a/sched/signal/sig_queue.c +++ b/sched/signal/sig_queue.c @@ -147,6 +147,12 @@ int sigqueue(int pid, int signo, union sigval value) { int ret; + if (signo != 0 && !nxsched_may_control(pid)) + { + set_errno(EPERM); + return ERROR; + } + /* Let nxsig_queue() do all of the real work */ ret = nxsig_queue(pid, signo, value); diff --git a/sched/signal/sig_tgkill.c b/sched/signal/sig_tgkill.c index 1c13c4ccc52..0a4c188502a 100644 --- a/sched/signal/sig_tgkill.c +++ b/sched/signal/sig_tgkill.c @@ -151,6 +151,12 @@ int tgkill(pid_t pid, pid_t tid, int signo) { int ret; + if (signo != 0 && !nxsched_may_control(tid)) + { + set_errno(EPERM); + return ERROR; + } + ret = nxsig_tgkill(pid, tid, signo); if (ret < 0) { diff --git a/sched/task/task_prctl.c b/sched/task/task_prctl.c index 988613b11f0..9bdd1ad63c5 100644 --- a/sched/task/task_prctl.c +++ b/sched/task/task_prctl.c @@ -87,6 +87,12 @@ int prctl(int option, ...) pid = va_arg(ap, int); } + if (option == PR_SET_NAME_EXT && !nxsched_may_control(pid)) + { + errcode = EPERM; + goto errout; + } + /* Get the TCB associated with the PID (handling the special case * of pid==0 meaning "this thread") */
