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-apps.git


The following commit(s) were added to refs/heads/master by this push:
     new e8af3076a testing/ostest: test process capabilities
e8af3076a is described below

commit e8af3076aa16970d3c23948f1308f7a526c397f9
Author: Royyan Zahir <[email protected]>
AuthorDate: Thu Oct 1 15:14:23 2026 +0400

    testing/ostest: test process capabilities
    
    A child starts with all three, a grandchild inherits a dropped set, and
    task_create() and mount() fail with EPERM once SPAWN and RAWIO are gone.
    The parent keeps its full set. Built only with CONFIG_SCHED_CAPABILITIES
    (apache/nuttx#20417), so small boards that turn it off, and trees without
    it, are untouched.
    
    Signed-off-by: Royyan Zahir <[email protected]>
---
 testing/ostest/CMakeLists.txt |   3 +
 testing/ostest/Makefile       |   5 ++
 testing/ostest/caps.c         | 140 ++++++++++++++++++++++++++++++++++++++++++
 testing/ostest/ostest.h       |   7 +++
 testing/ostest/ostest_main.c  |  14 +++++
 5 files changed, 169 insertions(+)

diff --git a/testing/ostest/CMakeLists.txt b/testing/ostest/CMakeLists.txt
index 2ec79d11c..fdcc9e187 100644
--- a/testing/ostest/CMakeLists.txt
+++ b/testing/ostest/CMakeLists.txt
@@ -66,6 +66,9 @@ if(CONFIG_TESTING_OSTEST)
 
   if(CONFIG_SCHED_WAITPID)
     list(APPEND SRCS waitpid.c)
+    if(CONFIG_SCHED_CAPABILITIES AND NOT CONFIG_BUILD_KERNEL)
+      list(APPEND SRCS caps.c)
+    endif()
   endif()
 
   if(CONFIG_FS_CHROOT)
diff --git a/testing/ostest/Makefile b/testing/ostest/Makefile
index d79b9d87d..ba2883025 100644
--- a/testing/ostest/Makefile
+++ b/testing/ostest/Makefile
@@ -81,6 +81,11 @@ endif
 
 ifeq ($(CONFIG_SCHED_WAITPID),y)
 CSRCS += waitpid.c
+ifeq ($(CONFIG_SCHED_CAPABILITIES),y)
+ifneq ($(CONFIG_BUILD_KERNEL),y)
+CSRCS += caps.c
+endif
+endif
 endif
 
 ifeq ($(CONFIG_FS_CHROOT),y)
diff --git a/testing/ostest/caps.c b/testing/ostest/caps.c
new file mode 100644
index 000000000..30e52670c
--- /dev/null
+++ b/testing/ostest/caps.c
@@ -0,0 +1,140 @@
+/****************************************************************************
+ * apps/testing/ostest/caps.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/compiler.h>
+
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+#include <assert.h>
+#include <errno.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ostest.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define CAPS_PRIO 100
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int caps_fail(FAR const char *msg)
+{
+  printf("caps_test: ERROR %s errno=%d\n", msg, errno);
+  ASSERT(false);
+  return EXIT_FAILURE;
+}
+
+static int caps_wait(pid_t pid)
+{
+  int status;
+
+  if (pid < 0 || waitpid(pid, &status, 0) != pid)
+    {
+      return ERROR;
+    }
+
+  return WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS ?
+         OK : ERROR;
+}
+
+static int caps_grandchild(int argc, FAR char *argv[])
+{
+  UNUSED(argc);
+  UNUSED(argv);
+
+  return prctl(PR_CAPS_GET) == (PR_CAP_ALL & ~PR_CAP_ADMIN) ?
+         EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+static int caps_child(int argc, FAR char *argv[])
+{
+  UNUSED(argc);
+  UNUSED(argv);
+
+  if (prctl(PR_CAPS_GET) != PR_CAP_ALL)
+    {
+      return caps_fail("child does not start with all caps");
+    }
+
+  prctl(PR_CAPS_DROP, PR_CAP_ADMIN);
+  if (caps_wait(task_create("caps_grandchild", CAPS_PRIO, STACKSIZE,
+                            caps_grandchild, NULL)) < 0)
+    {
+      return caps_fail("grandchild did not inherit the set");
+    }
+
+  prctl(PR_CAPS_DROP, PR_CAP_SPAWN);
+  if (task_create("caps_grandchild", CAPS_PRIO, STACKSIZE,
+                  caps_grandchild, NULL) >= 0 || errno != EPERM)
+    {
+      return caps_fail("task_create without PR_CAP_SPAWN");
+    }
+
+  prctl(PR_CAPS_DROP, PR_CAP_RAWIO);
+#ifndef CONFIG_DISABLE_MOUNTPOINT
+  if (mount(NULL, "/caps", "tmpfs", 0, NULL) == 0 ||
+      (errno != EPERM && errno != ENOSYS))
+    {
+      return caps_fail("mount without PR_CAP_RAWIO");
+    }
+#endif
+
+  if (prctl(PR_CAPS_GET) != 0)
+    {
+      return caps_fail("caps left after dropping all");
+    }
+
+  return EXIT_SUCCESS;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int caps_test(void)
+{
+  printf("caps_test: Starting test\n");
+
+  if (caps_wait(task_create("caps_child", CAPS_PRIO, STACKSIZE,
+                            caps_child, NULL)) < 0 ||
+      prctl(PR_CAPS_GET) != PR_CAP_ALL)
+    {
+      printf("caps_test: ERROR\n");
+      ASSERT(false);
+      return ERROR;
+    }
+
+  printf("caps_test: PASSED\n");
+  return OK;
+}
diff --git a/testing/ostest/ostest.h b/testing/ostest/ostest.h
index c889a4354..130dacd72 100644
--- a/testing/ostest/ostest.h
+++ b/testing/ostest/ostest.h
@@ -148,6 +148,13 @@ int waitpid_test(void);
 int chroot_test(void);
 #endif
 
+/* caps.c *******************************************************************/
+
+#if defined(CONFIG_SCHED_CAPABILITIES) && defined(CONFIG_SCHED_WAITPID) && \
+    !defined(CONFIG_BUILD_KERNEL)
+int caps_test(void);
+#endif
+
 /* wqueue.c *****************************************************************/
 
 #ifdef CONFIG_TESTING_OSTEST_WQUEUE
diff --git a/testing/ostest/ostest_main.c b/testing/ostest/ostest_main.c
index 52046c0ec..1ae017eef 100644
--- a/testing/ostest/ostest_main.c
+++ b/testing/ostest/ostest_main.c
@@ -420,6 +420,20 @@ static int user_main(int argc, char *argv[])
       check_test_memory_usage();
 #endif
 
+#if defined(CONFIG_SCHED_CAPABILITIES) && defined(CONFIG_SCHED_WAITPID) && \
+    !defined(CONFIG_BUILD_KERNEL)
+      /* Check process capabilities */
+
+      printf("\nuser_main: caps test\n");
+      if (caps_test() != 0)
+        {
+          printf("user_main: ERROR caps test failed\n");
+          ASSERT(false);
+        }
+
+      check_test_memory_usage();
+#endif
+
 #if defined(CONFIG_TESTING_OSTEST_MULTIUSER) && 
defined(CONFIG_SCHED_USER_IDENTITY)
       /* Multi-user identity and file permission regression tests */
 

Reply via email to