User and Group Identity

When CONFIG_SCHED_USER_IDENTITY is enabled, each task group maintains POSIX process credentials. All threads within a task group share the same credentials (see Tasks vs. Threads).

Credentials

The full POSIX three-field credential model is stored in struct task_group_s (include/nuttx/sched.h):

  • tg_uid / tg_gid — real user and group IDs.

  • tg_euid / tg_egid — effective IDs used for permission checks.

  • tg_suid / tg_sgid — saved set-IDs that allow a non-root process to restore a previously held effective ID.

All six fields are zero-initialized at task creation, so the initial task runs as root (UID/GID 0) unless explicitly changed.

Inheritance

When a new task is created, group_inherit_identity() in sched/group/group_create.c copies all six credential fields from the parent task group to the child task group.

Privilege Transitions

setuid() and setgid()

When the effective ID is zero (root):

  • setuid(uid) sets tg_uid, tg_euid, and tg_suid to uid.

  • setgid(gid) sets tg_gid, tg_egid, and tg_sgid to gid.

When the effective ID is non-zero:

  • The caller may only set the effective ID to the current real or saved value.

  • Any other value causes the function to return -1 with errno set to EPERM.

seteuid() and setegid()

When the effective ID is zero, any value may be assigned as the new effective ID.

When the effective ID is non-zero, the requested value must equal the real or the saved ID. Otherwise the function returns -1 with errno set to EPERM.

This implements the standard POSIX pattern of temporarily dropping privileges with seteuid() or setegid() and later restoring them to the saved value.

setreuid() and setregid()

These functions set the real and/or effective IDs in a single call. When the effective ID is zero, any requested real and effective values may be assigned and the saved set-ID is updated accordingly. When the effective ID is non-zero, each requested value must equal the current effective ID, saved set-ID, or (for the effective argument only) the real ID; otherwise the call returns -1 with errno set to EPERM. When the real ID is changed, or the effective ID is changed to a value not equal to the real ID, the saved set-ID is set to the new effective ID.

getresuid() and getresgid()

These functions return the real, effective, and saved set-IDs for the calling task group. Any output pointer may be NULL if that ID is not needed.

Configuration

CONFIG_SCHED_USER_IDENTITY

Enables per-task-group credential tracking. Without this option, stub root-only versions of all credential interfaces are provided.

CONFIG_FS_PERMISSION

Enables filesystem ownership and permission enforcement. Requires CONFIG_SCHED_USER_IDENTITY and CONFIG_PSEUDOFS_ATTRIBUTES. See Filesystem Permission Interface for the VFS helpers, mount-crossing traverse rules, and testing notes.

Pseudo-Filesystem Ownership

When CONFIG_PSEUDOFS_ATTRIBUTES and CONFIG_SCHED_USER_IDENTITY are both enabled, inode_alloc() assigns i_owner and i_group from the caller’s effective credentials. This covers message queues (mq_open()), named semaphores (sem_open()), shared memory objects (shm_open()), FIFOs (mkfifo()), and pseudo-files created through the same inode reservation path.

Path resolution requires directory search permission (X_OK) on ancestors via inode_checkpathperm(). Open-time checks on the final node use inode_checkopenperm() (or inode_checkperm() for named IPC objects). Full details, including mounts under private pseudoFS parents, are in Filesystem Permission Interface.