This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 1014c49881b880bcbc60c6f6443f05ff9e0736b9 Author: Abhishek Mishra <[email protected]> AuthorDate: Wed Aug 12 07:13:36 2026 +0000 sched: add supplementary group IDs (setgroups/getgroups/initgroups) Track supplementary GIDs per task group, wire setgroups/getgroups syscalls when CONFIG_SCHED_NGROUPS > 0, and honor them in DAC checks via nxsched_has_gid(). When NGROUPS is 0, libc provides getgroups/ setgroups stubs. initgroups() fails instead of silently truncating when membership exceeds CONFIG_SCHED_NGROUPS. Signed-off-by: Abhishek Mishra <[email protected]> --- binfmt/binfmt_checkexec.c | 9 ++-- fs/inode/fs_inode.c | 8 +-- include/limits.h | 6 ++- include/nuttx/sched.h | 41 +++++++++++++++ include/sys/syscall_lookup.h | 6 +++ include/unistd.h | 6 ++- libs/libc/grp/lib_find_grpfile.c | 11 ---- libs/libc/grp/lib_initgroups.c | 53 +++++++++++++++---- libs/libc/pwd/lib_find_pwdfile.c | 10 ---- libs/libc/unistd/CMakeLists.txt | 9 +++- libs/libc/unistd/Make.defs | 9 +++- libs/libc/unistd/lib_getgroups.c | 33 ++++-------- .../lib_initgroups.c => unistd/lib_setgroups.c} | 34 ++++--------- libs/libc/unistd/lib_sysconf.c | 4 ++ sched/Kconfig | 15 ++++++ sched/group/CMakeLists.txt | 5 ++ sched/group/Make.defs | 4 ++ sched/group/group_create.c | 9 ++++ .../group/group_getgroups.c | 59 ++++++++++++++-------- sched/group/group_setegid.c | 11 ---- sched/group/group_seteuid.c | 11 ---- sched/group/group_setgid.c | 11 ---- sched/group/{group_setegid.c => group_setgroups.c} | 51 +++++++++---------- sched/group/group_setregid.c | 12 ----- sched/group/group_setreuid.c | 12 ----- sched/group/group_setuid.c | 11 ---- syscall/syscall.csv | 4 ++ 27 files changed, 245 insertions(+), 209 deletions(-) diff --git a/binfmt/binfmt_checkexec.c b/binfmt/binfmt_checkexec.c index 1436298dc24..9d94d36300c 100644 --- a/binfmt/binfmt_checkexec.c +++ b/binfmt/binfmt_checkexec.c @@ -57,6 +57,7 @@ int binfmt_checkexecperm(FAR struct binary_s *bin) { FAR struct tcb_s *rtcb; + FAR struct task_group_s *rgroup; mode_t xbits; rtcb = nxsched_self(); @@ -66,7 +67,9 @@ int binfmt_checkexecperm(FAR struct binary_s *bin) return OK; } - if (rtcb->group->tg_euid == 0) + rgroup = rtcb->group; + + if (rgroup->tg_euid == 0) { /* Root can execute any file that has at least one execute bit set */ @@ -78,11 +81,11 @@ int binfmt_checkexecperm(FAR struct binary_s *bin) return OK; } - if (rtcb->group->tg_euid == bin->uid) + if (rgroup->tg_euid == bin->uid) { xbits = S_IXUSR; } - else if (rtcb->group->tg_egid == bin->gid) + else if (nxsched_has_gid(rtcb, bin->gid)) { xbits = S_IXGRP; } diff --git a/fs/inode/fs_inode.c b/fs/inode/fs_inode.c index cc9b4115356..4b1838ed7aa 100644 --- a/fs/inode/fs_inode.c +++ b/fs/inode/fs_inode.c @@ -66,9 +66,9 @@ static rw_semaphore_t g_inode_lock = RWSEM_INITIALIZER; int fs_checkmode(uid_t owner, gid_t group, mode_t mode, int amode) { FAR struct tcb_s *rtcb; + FAR struct task_group_s *rgroup; mode_t perm; uid_t uid; - gid_t gid; rtcb = nxsched_self(); if ((rtcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_KERNEL) @@ -77,14 +77,14 @@ int fs_checkmode(uid_t owner, gid_t group, mode_t mode, int amode) } DEBUGASSERT(rtcb->group != NULL); - uid = rtcb->group->tg_euid; - gid = rtcb->group->tg_egid; + rgroup = rtcb->group; + uid = rgroup->tg_euid; if (uid == owner) { perm = (mode >> 6) & 7; } - else if (gid == group) + else if (nxsched_has_gid(rtcb, group)) { perm = (mode >> 3) & 7; } diff --git a/include/limits.h b/include/limits.h index 047dc3d6b85..4e8bd5599e4 100644 --- a/include/limits.h +++ b/include/limits.h @@ -124,7 +124,11 @@ #define _POSIX_MAX_CANON 255 #define _POSIX_MAX_INPUT 255 #define _POSIX_NAME_MAX CONFIG_NAME_MAX -#define _POSIX_NGROUPS_MAX 0 +#if defined(CONFIG_SCHED_NGROUPS) && CONFIG_SCHED_NGROUPS > 0 +# define _POSIX_NGROUPS_MAX CONFIG_SCHED_NGROUPS +#else +# define _POSIX_NGROUPS_MAX 0 +#endif #define _POSIX_OPEN_MAX 16 #define _POSIX_PATH_MAX CONFIG_PATH_MAX #define _POSIX_PIPE_BUF 512 diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index c2f6df13982..a0534906621 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -466,6 +466,10 @@ struct task_group_s gid_t tg_egid; /* Effective group identity */ uid_t tg_suid; /* Saved set-user identity */ gid_t tg_sgid; /* Saved set-group identity */ +# if CONFIG_SCHED_NGROUPS > 0 + int tg_ngroups; /* Number of supplementary group IDs */ + gid_t tg_groups[CONFIG_SCHED_NGROUPS]; +# endif #endif /* Group membership *******************************************************/ @@ -861,6 +865,43 @@ EXTERN const struct tcbinfo_s g_tcbinfo; * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: nxsched_has_gid + * + * Description: + * Return true if the task's group matches 'gid' via the effective GID or + * any supplementary group ID. + * + ****************************************************************************/ + +#ifdef CONFIG_SCHED_USER_IDENTITY +static inline_function bool nxsched_has_gid(FAR struct tcb_s *tcb, + gid_t gid) +{ + FAR struct task_group_s *group = tcb->group; +#if CONFIG_SCHED_NGROUPS > 0 + int i; +#endif + + if (group->tg_egid == gid) + { + return true; + } + +#if CONFIG_SCHED_NGROUPS > 0 + for (i = 0; i < group->tg_ngroups; i++) + { + if (group->tg_groups[i] == gid) + { + return true; + } + } +#endif + + return false; +} +#endif + /**************************************************************************** * Name: nxsched_self * diff --git a/include/sys/syscall_lookup.h b/include/sys/syscall_lookup.h index 242366c8fd6..55a20f7f135 100644 --- a/include/sys/syscall_lookup.h +++ b/include/sys/syscall_lookup.h @@ -71,8 +71,14 @@ SYSCALL_LOOKUP(sethostname, 2) SYSCALL_LOOKUP(geteuid, 0) SYSCALL_LOOKUP(setegid, 1) SYSCALL_LOOKUP(getegid, 0) +# if CONFIG_SCHED_NGROUPS > 0 + SYSCALL_LOOKUP(setgroups, 2) + SYSCALL_LOOKUP(getgroups, 2) +# endif SYSCALL_LOOKUP(setreuid, 2) SYSCALL_LOOKUP(setregid, 2) + SYSCALL_LOOKUP(setresuid, 3) + SYSCALL_LOOKUP(setresgid, 3) SYSCALL_LOOKUP(getresuid, 3) SYSCALL_LOOKUP(getresgid, 3) #endif diff --git a/include/unistd.h b/include/unistd.h index 885bbed12a5..e46dda9d3cb 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -506,7 +506,11 @@ int setregid(gid_t rgid, gid_t egid); int getresuid(FAR uid_t *ruid, FAR uid_t *euid, FAR uid_t *suid); int getresgid(FAR gid_t *rgid, FAR gid_t *egid, FAR gid_t *sgid); -int getgroups(int, gid_t[]); +int setresuid(uid_t ruid, uid_t euid, uid_t suid); +int setresgid(gid_t rgid, gid_t egid, gid_t sgid); + +int getgroups(int, FAR gid_t[]); +int setgroups(int, FAR const gid_t *); int getentropy(FAR void *buffer, size_t length); diff --git a/libs/libc/grp/lib_find_grpfile.c b/libs/libc/grp/lib_find_grpfile.c index 98c4cc48150..999f082ad19 100644 --- a/libs/libc/grp/lib_find_grpfile.c +++ b/libs/libc/grp/lib_find_grpfile.c @@ -36,7 +36,6 @@ #include <nuttx/lib/lib.h> #include "grp/lib_grp.h" - /**************************************************************************** * Private Types ****************************************************************************/ @@ -396,16 +395,6 @@ int grp_findby_name(FAR const char *gname, FAR struct group *entry, int grp_findby_gid(gid_t gid, FAR struct group *entry, FAR char *buffer, size_t buflen) { - /* Verify that the GID is in the valid range of 0 through INT16_MAX. - * OpenGroup.org does not specify a GID_MAX or GID_MIN. Instead we use a - * priori knowledge that gid_t is type int16_t. - */ - - if ((uint16_t)gid > INT16_MAX) - { - return -EINVAL; - } - return grp_foreach(grp_match_gid, (uintptr_t)gid, entry, buffer, buflen); } diff --git a/libs/libc/grp/lib_initgroups.c b/libs/libc/grp/lib_initgroups.c index 5329ba96095..5ae27b62fdb 100644 --- a/libs/libc/grp/lib_initgroups.c +++ b/libs/libc/grp/lib_initgroups.c @@ -27,6 +27,11 @@ #include <nuttx/config.h> #include <grp.h> +#include <limits.h> +#include <unistd.h> +#include <errno.h> + +#include <nuttx/debug.h> /**************************************************************************** * Public Functions @@ -36,28 +41,56 @@ * Name: initgroups * * Description: - * The group database /etc/group is read to determine all groups of which - * user is a member. The additional group group is also added to this set, - * which is then used to set the supplementary group IDs of the calling - * process. + * The group database is read to determine all groups of which user is a + * member. The additional group 'group' is also included. The resulting + * set is installed as the calling process's supplementary group IDs via + * setgroups(). * * Input Parameters: - * user - Name of the user to query the /etc/group database for. + * user - Name of the user to query the group database for. * group - Additional gid to add to the list of group IDs. * * Returned Value: - * The initgroups() function returns zero if successful, and -1 in case of - * failure, in which case errno is set appropriately. + * Zero if successful, and -1 on failure with errno set. * ****************************************************************************/ int initgroups(FAR const char *user, gid_t group) { - /* There currently is no support for supplementary group IDs in NuttX. - * Thus, just ignore this request silently and report success. - */ +#if defined(CONFIG_SCHED_NGROUPS) && CONFIG_SCHED_NGROUPS > 0 + gid_t groups[NGROUPS_MAX]; + int ngroups = NGROUPS_MAX; + int ret; + + if (user == NULL) + { + set_errno(EINVAL); + return ERROR; + } + + ret = getgrouplist(user, group, groups, &ngroups); + if (ret < 0) + { + /* Buffer too small or lookup failure — errno already set by + * getgrouplist when applicable. + */ + + if (ngroups > NGROUPS_MAX) + { + swarn("initgroups: user '%s' has %d groups, NGROUPS_MAX=%d\n", + user, ngroups, NGROUPS_MAX); + set_errno(EINVAL); + } + + return ERROR; + } + + return setgroups(ret, groups); +#else + /* Without supplementary group storage, succeed silently. */ UNUSED(user); UNUSED(group); return 0; +#endif } diff --git a/libs/libc/pwd/lib_find_pwdfile.c b/libs/libc/pwd/lib_find_pwdfile.c index 88da93bbdac..bd520c998b7 100644 --- a/libs/libc/pwd/lib_find_pwdfile.c +++ b/libs/libc/pwd/lib_find_pwdfile.c @@ -382,16 +382,6 @@ int pwd_findby_name(FAR const char *uname, FAR struct passwd *entry, int pwd_findby_uid(uid_t uid, FAR struct passwd *entry, FAR char *buffer, size_t buflen) { - /* Verify that the UID is in the valid range of 0 through INT16_MAX. - * OpenGroup.org does not specify a UID_MAX or UID_MIN. Instead we use a - * priori knowledge that uid_t is type int16_t. - */ - - if ((uint16_t)uid > INT16_MAX) - { - return -EINVAL; - } - return pwd_foreach(pwd_match_uid, (uintptr_t)uid, entry, buffer, buflen); } diff --git a/libs/libc/unistd/CMakeLists.txt b/libs/libc/unistd/CMakeLists.txt index 834d61355ff..b85e65e54d6 100644 --- a/libs/libc/unistd/CMakeLists.txt +++ b/libs/libc/unistd/CMakeLists.txt @@ -63,7 +63,6 @@ set(SRCS lib_getpgrp.c lib_getpgid.c lib_getsid.c - lib_getgroups.c lib_setpgid.c lib_setsid.c lib_lockf.c @@ -90,7 +89,13 @@ if(NOT CONFIG_SCHED_USER_IDENTITY) lib_setregid.c lib_getresuid.c lib_getresgid.c - lib_issetugid.c) + lib_setresuid.c + lib_setresgid.c + lib_issetugid.c + lib_getgroups.c + lib_setgroups.c) +elseif(NOT CONFIG_SCHED_NGROUPS) + list(APPEND SRCS lib_getgroups.c lib_setgroups.c) endif() if(NOT CONFIG_DISABLE_ENVIRON) diff --git a/libs/libc/unistd/Make.defs b/libs/libc/unistd/Make.defs index d4fbc70879b..3e9c6dfeb21 100644 --- a/libs/libc/unistd/Make.defs +++ b/libs/libc/unistd/Make.defs @@ -32,7 +32,7 @@ CSRCS += lib_setrlimit.c lib_getrlimit.c lib_setpriority.c lib_getpriority.c CSRCS += lib_futimes.c lib_lutimes.c lib_gethostname.c lib_sethostname.c CSRCS += lib_fchownat.c lib_linkat.c lib_readlinkat.c lib_symlinkat.c CSRCS += lib_unlinkat.c lib_usleep.c lib_getpgrp.c lib_getpgid.c -CSRCS += lib_getsid.c lib_getgroups.c lib_setpgid.c lib_setsid.c +CSRCS += lib_getsid.c lib_setpgid.c lib_setsid.c CSRCS += lib_lockf.c lib_flock.c lib_getpass.c CSRCS += lib_chdir.c lib_fchdir.c lib_confstr.c lib_ulimit.c @@ -40,7 +40,12 @@ ifneq ($(CONFIG_SCHED_USER_IDENTITY),y) CSRCS += lib_setuid.c lib_setgid.c lib_getuid.c lib_getgid.c CSRCS += lib_seteuid.c lib_setegid.c lib_geteuid.c lib_getegid.c CSRCS += lib_setreuid.c lib_setregid.c lib_getresuid.c lib_getresgid.c -CSRCS += lib_issetugid.c +CSRCS += lib_setresuid.c lib_setresgid.c +CSRCS += lib_issetugid.c lib_getgroups.c lib_setgroups.c +else +ifeq ($(CONFIG_SCHED_NGROUPS),0) +CSRCS += lib_getgroups.c lib_setgroups.c +endif endif ifneq ($(CONFIG_DISABLE_ENVIRON),y) diff --git a/libs/libc/unistd/lib_getgroups.c b/libs/libc/unistd/lib_getgroups.c index 53cbc11ba82..f28704b2376 100644 --- a/libs/libc/unistd/lib_getgroups.c +++ b/libs/libc/unistd/lib_getgroups.c @@ -38,9 +38,10 @@ * * Description: * The getgroups() function returns the supplementary group IDs of the - * calling process in the array grouplist. NuttX does not support - * supplementary group IDs, so the calling process is treated as belonging - * to a single group: its effective group ID. + * calling process in the array grouplist. Stub when + * CONFIG_SCHED_USER_IDENTITY is disabled or CONFIG_SCHED_NGROUPS is 0: + * there is no supplementary group list. The effective group ID is not + * synthesized; callers that need it should use getegid(). * * Input Parameters: * gidsetsize - The number of elements available in grouplist. @@ -55,31 +56,15 @@ int getgroups(int gidsetsize, gid_t grouplist[]) { + UNUSED(grouplist); + if (gidsetsize < 0) { set_errno(EINVAL); - return -1; - } - - /* If gidsetsize is zero, return the number of group IDs without touching - * grouplist. - */ - - if (gidsetsize == 0) - { - return 1; - } - - if (grouplist == NULL) - { - set_errno(EFAULT); - return -1; + return ERROR; } - /* NuttX has no notion of supplementary group IDs. Report the single - * effective group ID of the calling process. - */ + /* Empty supplementary list (do not synthesize egid). */ - grouplist[0] = getegid(); - return 1; + return 0; } diff --git a/libs/libc/grp/lib_initgroups.c b/libs/libc/unistd/lib_setgroups.c similarity index 64% copy from libs/libc/grp/lib_initgroups.c copy to libs/libc/unistd/lib_setgroups.c index 5329ba96095..2ff3bb2ee2d 100644 --- a/libs/libc/grp/lib_initgroups.c +++ b/libs/libc/unistd/lib_setgroups.c @@ -1,5 +1,5 @@ /**************************************************************************** - * libs/libc/grp/lib_initgroups.c + * libs/libc/unistd/lib_setgroups.c * * SPDX-License-Identifier: Apache-2.0 * @@ -26,38 +26,26 @@ #include <nuttx/config.h> -#include <grp.h> +#include <unistd.h> +#include <errno.h> /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** - * Name: initgroups + * Name: setgroups * * Description: - * The group database /etc/group is read to determine all groups of which - * user is a member. The additional group group is also added to this set, - * which is then used to set the supplementary group IDs of the calling - * process. - * - * Input Parameters: - * user - Name of the user to query the /etc/group database for. - * group - Additional gid to add to the list of group IDs. - * - * Returned Value: - * The initgroups() function returns zero if successful, and -1 in case of - * failure, in which case errno is set appropriately. + * Stub when CONFIG_SCHED_USER_IDENTITY is disabled or + * CONFIG_SCHED_NGROUPS is 0. Supplementary groups are not supported. * ****************************************************************************/ -int initgroups(FAR const char *user, gid_t group) +int setgroups(int size, FAR const gid_t *list) { - /* There currently is no support for supplementary group IDs in NuttX. - * Thus, just ignore this request silently and report success. - */ - - UNUSED(user); - UNUSED(group); - return 0; + UNUSED(size); + UNUSED(list); + set_errno(ENOSYS); + return ERROR; } diff --git a/libs/libc/unistd/lib_sysconf.c b/libs/libc/unistd/lib_sysconf.c index dc6bfb8cba1..428482aea52 100644 --- a/libs/libc/unistd/lib_sysconf.c +++ b/libs/libc/unistd/lib_sysconf.c @@ -29,6 +29,7 @@ #include <nuttx/atexit.h> #include <unistd.h> +#include <limits.h> #include <sched.h> #include <errno.h> @@ -241,6 +242,9 @@ long sysconf(int name) case _SC_OPEN_MAX: return OPEN_MAX; + case _SC_NGROUPS_MAX: + return NGROUPS_MAX; + case _SC_ATEXIT_MAX: return ATEXIT_MAX; diff --git a/sched/Kconfig b/sched/Kconfig index 5532fc4114b..bac8e961aa2 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -803,6 +803,21 @@ config SCHED_USER_IDENTITY If this option is not selected, stub root-only versions of these interfaces are available instead. +if SCHED_USER_IDENTITY + +config SCHED_NGROUPS + int "Maximum supplementary group IDs" + default 8 + range 0 64 + ---help--- + Maximum number of supplementary group IDs per task group. This + value becomes NGROUPS_MAX and sizes the getgroups()/setgroups() + list stored in each task group. Set to 0 to disable supplementary + group storage (getgroups then always returns an empty list). + The effective GID is separate and available via getegid(). + +endif # SCHED_USER_IDENTITY + config SCHED_THREAD_LOCAL bool "Support __thread/thread_local keyword" default n diff --git a/sched/group/CMakeLists.txt b/sched/group/CMakeLists.txt index 42f21d504bc..5353552c849 100644 --- a/sched/group/CMakeLists.txt +++ b/sched/group/CMakeLists.txt @@ -57,7 +57,12 @@ if(CONFIG_SCHED_USER_IDENTITY) group_setregid.c group_getresuid.c group_getresgid.c + group_setresuid.c + group_setresgid.c group_issetugid.c) + if(CONFIG_SCHED_NGROUPS) + list(APPEND SRCS group_setgroups.c group_getgroups.c) + endif() endif() if(CONFIG_SIG_SIGSTOP_ACTION) diff --git a/sched/group/Make.defs b/sched/group/Make.defs index f505a0d80f5..b2605e53fe5 100644 --- a/sched/group/Make.defs +++ b/sched/group/Make.defs @@ -42,7 +42,11 @@ ifeq ($(CONFIG_SCHED_USER_IDENTITY),y) CSRCS += group_setuid.c group_setgid.c group_getuid.c group_getgid.c CSRCS += group_seteuid.c group_setegid.c group_geteuid.c group_getegid.c CSRCS += group_setreuid.c group_setregid.c group_getresuid.c group_getresgid.c +CSRCS += group_setresuid.c group_setresgid.c CSRCS += group_issetugid.c +ifneq ($(CONFIG_SCHED_NGROUPS),0) +CSRCS += group_setgroups.c group_getgroups.c +endif endif ifeq ($(CONFIG_SIG_SIGSTOP_ACTION),y) diff --git a/sched/group/group_create.c b/sched/group/group_create.c index c7b1af1fd46..1fb32bf7ff2 100644 --- a/sched/group/group_create.c +++ b/sched/group/group_create.c @@ -26,6 +26,7 @@ #include <nuttx/config.h> +#include <string.h> #include <sched.h> #include <assert.h> #include <errno.h> @@ -84,6 +85,14 @@ static inline void group_inherit_identity(FAR struct task_group_s *group) group->tg_egid = rgroup->tg_egid; group->tg_suid = rgroup->tg_suid; group->tg_sgid = rgroup->tg_sgid; +#if CONFIG_SCHED_NGROUPS > 0 + group->tg_ngroups = rgroup->tg_ngroups; + if (rgroup->tg_ngroups > 0) + { + memcpy(group->tg_groups, rgroup->tg_groups, + rgroup->tg_ngroups * sizeof(gid_t)); + } +#endif } #else # define group_inherit_identity(group) diff --git a/libs/libc/unistd/lib_getgroups.c b/sched/group/group_getgroups.c similarity index 62% copy from libs/libc/unistd/lib_getgroups.c copy to sched/group/group_getgroups.c index 53cbc11ba82..90d9a8dd538 100644 --- a/libs/libc/unistd/lib_getgroups.c +++ b/sched/group/group_getgroups.c @@ -1,5 +1,5 @@ /**************************************************************************** - * libs/libc/unistd/lib_getgroups.c + * sched/group/group_getgroups.c * * SPDX-License-Identifier: Apache-2.0 * @@ -27,8 +27,12 @@ #include <nuttx/config.h> #include <unistd.h> +#include <string.h> +#include <assert.h> #include <errno.h> +#include <sched/sched.h> + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -37,49 +41,60 @@ * Name: getgroups * * Description: - * The getgroups() function returns the supplementary group IDs of the - * calling process in the array grouplist. NuttX does not support - * supplementary group IDs, so the calling process is treated as belonging - * to a single group: its effective group ID. + * getgroups() returns the supplementary group IDs of the calling + * process. The returned list is exactly the set installed by + * setgroups()/initgroups() (may be empty). The effective group ID is + * not synthesized into an empty list; callers that need it should use + * getegid(). * * Input Parameters: - * gidsetsize - The number of elements available in grouplist. - * grouplist - The buffer used to return the group IDs. + * gidsetsize - Number of slots in grouplist, or 0 to query the count. + * grouplist - Buffer for group IDs (unused when gidsetsize is 0). * * Returned Value: - * On success, the number of group IDs is returned. If gidsetsize is zero, - * the total number of group IDs is returned without modifying grouplist. - * On failure, -1 is returned and errno is set appropriately. + * Number of group IDs on success; -1 on failure with errno set. * ****************************************************************************/ -int getgroups(int gidsetsize, gid_t grouplist[]) +int getgroups(int gidsetsize, FAR gid_t grouplist[]) { + FAR struct tcb_s *rtcb; + FAR struct task_group_s *rgroup; + int count; + if (gidsetsize < 0) { set_errno(EINVAL); - return -1; + return ERROR; } - /* If gidsetsize is zero, return the number of group IDs without touching - * grouplist. - */ + rtcb = this_task(); + rgroup = rtcb->group; + DEBUGASSERT(rgroup != NULL); + + count = rgroup->tg_ngroups; if (gidsetsize == 0) { - return 1; + return count; } if (grouplist == NULL) { set_errno(EFAULT); - return -1; + return ERROR; } - /* NuttX has no notion of supplementary group IDs. Report the single - * effective group ID of the calling process. - */ + if (gidsetsize < count) + { + set_errno(EINVAL); + return ERROR; + } + + if (count > 0) + { + memcpy(grouplist, rgroup->tg_groups, count * sizeof(gid_t)); + } - grouplist[0] = getegid(); - return 1; + return count; } diff --git a/sched/group/group_setegid.c b/sched/group/group_setegid.c index 733f11f84dc..e80d503e395 100644 --- a/sched/group/group_setegid.c +++ b/sched/group/group_setegid.c @@ -62,17 +62,6 @@ int setegid(gid_t gid) FAR struct tcb_s *rtcb; FAR struct task_group_s *rgroup; - /* Verify that the GID is in the valid range of 0 through INT16_MAX. - * OpenGroup.org does not specify a GID_MAX or GID_MIN. Instead we use a - * priori knowledge that gid_t is type int16_t. - */ - - if ((uint16_t)gid > INT16_MAX) - { - set_errno(EINVAL); - return ERROR; - } - /* Get the currently executing thread's task group. */ rtcb = this_task(); diff --git a/sched/group/group_seteuid.c b/sched/group/group_seteuid.c index 758a6355365..3fd4469b98e 100644 --- a/sched/group/group_seteuid.c +++ b/sched/group/group_seteuid.c @@ -64,17 +64,6 @@ int seteuid(uid_t uid) FAR struct tcb_s *rtcb; FAR struct task_group_s *rgroup; - /* Verify that the UID is in the valid range of 0 through INT16_MAX. - * OpenGroup.org does not specify a UID_MAX or UID_MIN. Instead we use a - * priori knowledge that uid_t is type int16_t. - */ - - if ((uint16_t)uid > INT16_MAX) - { - set_errno(EINVAL); - return ERROR; - } - /* Get the currently executing thread's task group. */ rtcb = this_task(); diff --git a/sched/group/group_setgid.c b/sched/group/group_setgid.c index 72131e5ee5f..812958b2f9b 100644 --- a/sched/group/group_setgid.c +++ b/sched/group/group_setgid.c @@ -63,17 +63,6 @@ int setgid(gid_t gid) FAR struct tcb_s *rtcb; FAR struct task_group_s *rgroup; - /* Verify that the GID is in the valid range of 0 through INT16_MAX. - * OpenGroup.org does not specify a GID_MAX or GID_MIN. Instead we use a - * priori knowledge that gid_t is type int16_t. - */ - - if ((uint16_t)gid > INT16_MAX) - { - set_errno(EINVAL); - return ERROR; - } - /* Get the currently executing thread's task group. */ rtcb = this_task(); diff --git a/sched/group/group_setegid.c b/sched/group/group_setgroups.c similarity index 63% copy from sched/group/group_setegid.c copy to sched/group/group_setgroups.c index 733f11f84dc..7f6243dbb1c 100644 --- a/sched/group/group_setegid.c +++ b/sched/group/group_setgroups.c @@ -1,5 +1,5 @@ /**************************************************************************** - * sched/group/group_setegid.c + * sched/group/group_setgroups.c * * SPDX-License-Identifier: Apache-2.0 * @@ -27,6 +27,7 @@ #include <nuttx/config.h> #include <unistd.h> +#include <string.h> #include <assert.h> #include <errno.h> @@ -37,61 +38,55 @@ ****************************************************************************/ /**************************************************************************** - * Name: setegid + * Name: setgroups * * Description: - * The setegid() function sets the effective group ID of the calling - * process to gid, given appropriate privileges. + * setgroups() sets the supplementary group IDs for the calling process. + * Only a process with an effective user ID of 0 may change the list. * * Input Parameters: - * gid - Identity to set the various process's group ID attributes to. + * size - Number of group IDs in list (0 to clear). + * list - Array of supplementary group IDs, or NULL when size is 0. * * Returned Value: - * Zero if successful and -1 in case of failure, in which case errno is set - * to one of he following values: - * - * EINVAL - The value of the uid argument is invalid and not supported by - * the implementation. - * EPERM - The process does not have appropriate privileges and uid does - * not match the effective group ID or the saved set-group-ID. + * Zero on success; -1 on failure with errno set. * ****************************************************************************/ -int setegid(gid_t gid) +int setgroups(int size, FAR const gid_t *list) { FAR struct tcb_s *rtcb; FAR struct task_group_s *rgroup; - /* Verify that the GID is in the valid range of 0 through INT16_MAX. - * OpenGroup.org does not specify a GID_MAX or GID_MIN. Instead we use a - * priori knowledge that gid_t is type int16_t. - */ - - if ((uint16_t)gid > INT16_MAX) + if (size < 0 || size > CONFIG_SCHED_NGROUPS) { set_errno(EINVAL); return ERROR; } - /* Get the currently executing thread's task group. */ + if (size > 0 && list == NULL) + { + set_errno(EFAULT); + return ERROR; + } rtcb = this_task(); rgroup = rtcb->group; - DEBUGASSERT(rgroup != NULL); - 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. */ + /* Only root (effective UID 0) may install a new supplementary set. */ - rgroup->tg_egid = gid; - } - else + if (rgroup->tg_euid != 0) { set_errno(EPERM); return ERROR; } + if (size > 0) + { + memcpy(rgroup->tg_groups, list, size * sizeof(gid_t)); + } + + rgroup->tg_ngroups = size; return OK; } diff --git a/sched/group/group_setregid.c b/sched/group/group_setregid.c index 61360f939dd..5ec7676d8b0 100644 --- a/sched/group/group_setregid.c +++ b/sched/group/group_setregid.c @@ -63,18 +63,6 @@ int setregid(gid_t rgid, gid_t egid) gid_t old_egid; gid_t old_sgid; - if (rgid != (gid_t)-1 && (uint16_t)rgid > INT16_MAX) - { - set_errno(EINVAL); - return ERROR; - } - - if (egid != (gid_t)-1 && (uint16_t)egid > INT16_MAX) - { - set_errno(EINVAL); - return ERROR; - } - if (rgid == (gid_t)-1 && egid == (gid_t)-1) { return OK; diff --git a/sched/group/group_setreuid.c b/sched/group/group_setreuid.c index 0610f9fdda6..1d37e070e2c 100644 --- a/sched/group/group_setreuid.c +++ b/sched/group/group_setreuid.c @@ -64,18 +64,6 @@ int setreuid(uid_t ruid, uid_t euid) uid_t old_euid; uid_t old_suid; - if (ruid != (uid_t)-1 && (uint16_t)ruid > INT16_MAX) - { - set_errno(EINVAL); - return ERROR; - } - - if (euid != (uid_t)-1 && (uint16_t)euid > INT16_MAX) - { - set_errno(EINVAL); - return ERROR; - } - if (ruid == (uid_t)-1 && euid == (uid_t)-1) { return OK; diff --git a/sched/group/group_setuid.c b/sched/group/group_setuid.c index 16073ed5313..38424108594 100644 --- a/sched/group/group_setuid.c +++ b/sched/group/group_setuid.c @@ -64,17 +64,6 @@ int setuid(uid_t uid) FAR struct tcb_s *rtcb; FAR struct task_group_s *rgroup; - /* Verify that the UID is in the valid range of 0 through INT16_MAX. - * OpenGroup.org does not specify a UID_MAX or UID_MIN. Instead we use a - * priori knowledge that uid_t is type int16_t. - */ - - if ((uint16_t)uid > INT16_MAX) - { - set_errno(EINVAL); - return ERROR; - } - /* Get the currently executing thread's task group. */ rtcb = this_task(); diff --git a/syscall/syscall.csv b/syscall/syscall.csv index f5675cea0a0..c488776b3c4 100644 --- a/syscall/syscall.csv +++ b/syscall/syscall.csv @@ -45,6 +45,7 @@ "getenv","stdlib.h","!defined(CONFIG_DISABLE_ENVIRON)","FAR char *","FAR const char *" "geteuid","unistd.h","defined(CONFIG_SCHED_USER_IDENTITY)","uid_t" "getgid","unistd.h","defined(CONFIG_SCHED_USER_IDENTITY)","gid_t" +"getgroups","unistd.h","defined(CONFIG_SCHED_USER_IDENTITY) && (CONFIG_SCHED_NGROUPS > 0)","int","int","FAR gid_t *" "gethostname","unistd.h","","int","FAR char *","size_t" "getitimer","sys/time.h","!defined(CONFIG_DISABLE_POSIX_TIMERS)","int","int","FAR struct itimerval *" "getpeername","sys/socket.h","defined(CONFIG_NET)","int","int","FAR struct sockaddr *","FAR socklen_t *" @@ -158,8 +159,11 @@ "sendmsg","sys/socket.h","defined(CONFIG_NET)","ssize_t","int","FAR const struct msghdr *","int" "sendto","sys/socket.h","defined(CONFIG_NET)","ssize_t","int","FAR const void *","size_t","int","FAR const struct sockaddr *","socklen_t" "setegid","unistd.h","defined(CONFIG_SCHED_USER_IDENTITY)","int","gid_t" +"setgroups","unistd.h","defined(CONFIG_SCHED_USER_IDENTITY) && (CONFIG_SCHED_NGROUPS > 0)","int","int","FAR const gid_t *" "setregid","unistd.h","defined(CONFIG_SCHED_USER_IDENTITY)","int","gid_t","gid_t" "setreuid","unistd.h","defined(CONFIG_SCHED_USER_IDENTITY)","int","uid_t","uid_t" +"setresgid","unistd.h","defined(CONFIG_SCHED_USER_IDENTITY)","int","gid_t","gid_t","gid_t" +"setresuid","unistd.h","defined(CONFIG_SCHED_USER_IDENTITY)","int","uid_t","uid_t","uid_t" "setenv","stdlib.h","!defined(CONFIG_DISABLE_ENVIRON)","int","FAR const char *","FAR const char *","int" "seteuid","unistd.h","defined(CONFIG_SCHED_USER_IDENTITY)","int","uid_t" "setgid","unistd.h","defined(CONFIG_SCHED_USER_IDENTITY)","int","gid_t"
