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 14661fdba07b4389e8ed7ae2539609da9841756a
Author: Abhishek Mishra <[email protected]>
AuthorDate: Wed Jun 10 08:03:35 2026 +0000

    sched/group: implement POSIX saved-set-UID/GID semantics
    
    Adds tg_suid and tg_sgid fields to task_group_s to complete the
    POSIX three-field identity model (real, effective, saved-set).
    
    Updates group_inherit_identity() to propagate the new fields from
    parent to child task group on task creation.
    
    Fixes setuid(), setgid(), seteuid(), and setegid() to implement
    correct POSIX privilege transition logic:
    - Root (euid==0): may set any value; all three IDs updated by setuid/setgid
    - Non-root: may only set effective ID to real or saved value; else EPERM
    
    Signed-off-by: Abhishek Mishra <[email protected]>
---
 include/nuttx/sched.h       |  2 ++
 sched/group/group_create.c  |  6 ++++--
 sched/group/group_setegid.c | 17 ++++++++++++++---
 sched/group/group_seteuid.c | 17 ++++++++++++++---
 sched/group/group_setgid.c  | 24 +++++++++++++++++++++---
 sched/group/group_setuid.c  | 24 +++++++++++++++++++++---
 6 files changed, 76 insertions(+), 14 deletions(-)

diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h
index 61e9c461108..ca3781995bd 100644
--- a/include/nuttx/sched.h
+++ b/include/nuttx/sched.h
@@ -462,6 +462,8 @@ struct task_group_s
   gid_t   tg_gid;                   /* User group identity                     
 */
   uid_t   tg_euid;                  /* Effective user identity                 
 */
   gid_t   tg_egid;                  /* Effective user group identity           
 */
+  uid_t   tg_suid;                  /* Saved set-user identity                 
 */
+  gid_t   tg_sgid;                  /* Saved set-group identity                
 */
 #endif
 
   /* Group membership *******************************************************/
diff --git a/sched/group/group_create.c b/sched/group/group_create.c
index 473f6df0acf..677d818b37c 100644
--- a/sched/group/group_create.c
+++ b/sched/group/group_create.c
@@ -78,10 +78,12 @@ static inline void group_inherit_identity(FAR struct 
task_group_s *group)
   /* Inherit the user identity from the parent task group. */
 
   DEBUGASSERT(group != NULL);
-  group->tg_uid = rgroup->tg_uid;
-  group->tg_gid = rgroup->tg_gid;
+  group->tg_uid  = rgroup->tg_uid;
+  group->tg_gid  = rgroup->tg_gid;
   group->tg_euid = rgroup->tg_euid;
   group->tg_egid = rgroup->tg_egid;
+  group->tg_suid = rgroup->tg_suid;
+  group->tg_sgid = rgroup->tg_sgid;
 }
 #else
 #  define group_inherit_identity(group)
diff --git a/sched/group/group_setegid.c b/sched/group/group_setegid.c
index ac5dee2d7f9..733f11f84dc 100644
--- a/sched/group/group_setegid.c
+++ b/sched/group/group_setegid.c
@@ -78,9 +78,20 @@ int setegid(gid_t gid)
   rtcb   = this_task();
   rgroup = rtcb->group;
 
-  /* Set the task group's group identity. */
-
   DEBUGASSERT(rgroup != NULL);
-  rgroup->tg_egid = gid;
+
+  if (rgroup->tg_egid == 0 ||
+      gid == rgroup->tg_gid || gid == rgroup->tg_sgid)
+    {
+      /* Root may set any value; non-root may only set to real or saved. */
+
+      rgroup->tg_egid = gid;
+    }
+  else
+    {
+      set_errno(EPERM);
+      return ERROR;
+    }
+
   return OK;
 }
diff --git a/sched/group/group_seteuid.c b/sched/group/group_seteuid.c
index b306f9a58b2..758a6355365 100644
--- a/sched/group/group_seteuid.c
+++ b/sched/group/group_seteuid.c
@@ -80,9 +80,20 @@ int seteuid(uid_t uid)
   rtcb   = this_task();
   rgroup = rtcb->group;
 
-  /* Set the task group's group identity. */
-
   DEBUGASSERT(rgroup != NULL);
-  rgroup->tg_euid = uid;
+
+  if (rgroup->tg_euid == 0 ||
+      uid == rgroup->tg_uid || uid == rgroup->tg_suid)
+    {
+      /* Root may set any value; non-root may only set to real or saved. */
+
+      rgroup->tg_euid = uid;
+    }
+  else
+    {
+      set_errno(EPERM);
+      return ERROR;
+    }
+
   return OK;
 }
diff --git a/sched/group/group_setgid.c b/sched/group/group_setgid.c
index 2fc0b423148..72131e5ee5f 100644
--- a/sched/group/group_setgid.c
+++ b/sched/group/group_setgid.c
@@ -79,9 +79,27 @@ int setgid(gid_t gid)
   rtcb   = this_task();
   rgroup = rtcb->group;
 
-  /* Set the task group's group identity. */
-
   DEBUGASSERT(rgroup != NULL);
-  rgroup->tg_gid = gid;
+
+  if (rgroup->tg_egid == 0)
+    {
+      /* Root: set real, effective, and saved set-group-ID. */
+
+      rgroup->tg_gid  = gid;
+      rgroup->tg_egid = gid;
+      rgroup->tg_sgid = gid;
+    }
+  else if (gid == rgroup->tg_gid || gid == rgroup->tg_sgid)
+    {
+      /* Non-root: may only set effective GID to real or saved value. */
+
+      rgroup->tg_egid = gid;
+    }
+  else
+    {
+      set_errno(EPERM);
+      return ERROR;
+    }
+
   return OK;
 }
diff --git a/sched/group/group_setuid.c b/sched/group/group_setuid.c
index 46cf4f8b16f..16073ed5313 100644
--- a/sched/group/group_setuid.c
+++ b/sched/group/group_setuid.c
@@ -80,9 +80,27 @@ int setuid(uid_t uid)
   rtcb   = this_task();
   rgroup = rtcb->group;
 
-  /* Set the task group's group identity. */
-
   DEBUGASSERT(rgroup != NULL);
-  rgroup->tg_uid = uid;
+
+  if (rgroup->tg_euid == 0)
+    {
+      /* Root: set real, effective, and saved set-user-ID. */
+
+      rgroup->tg_uid  = uid;
+      rgroup->tg_euid = uid;
+      rgroup->tg_suid = uid;
+    }
+  else if (uid == rgroup->tg_uid || uid == rgroup->tg_suid)
+    {
+      /* Non-root: may only set effective UID to real or saved value. */
+
+      rgroup->tg_euid = uid;
+    }
+  else
+    {
+      set_errno(EPERM);
+      return ERROR;
+    }
+
   return OK;
 }

Reply via email to