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, &param);
-  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, &param);
-  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")
            */

Reply via email to