diff --git a/Documentation/implementation/user_identity.rst b/Documentation/implementation/user_identity.rst index ab7ecdaa6caaa..5c9486901bd93 100644 --- a/Documentation/implementation/user_identity.rst +++ b/Documentation/implementation/user_identity.rst @@ -59,6 +59,24 @@ the saved ID. Otherwise the function returns ``-1`` with ``errno`` set to 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 ============= @@ -69,3 +87,14 @@ Configuration ``CONFIG_FS_PERMISSION`` Enables filesystem ownership and permission enforcement. Requires ``CONFIG_SCHED_USER_IDENTITY``. + +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. Open-time permission checks +use ``inode_checkopenperm()`` (or ``inode_checkperm()`` for message queues). diff --git a/fs/inode/fs_inode.c b/fs/inode/fs_inode.c index 294f7bb791e4b..e89eb337489a8 100644 --- a/fs/inode/fs_inode.c +++ b/fs/inode/fs_inode.c @@ -229,6 +229,10 @@ void inode_runlock(void) * ****************************************************************************/ +/**************************************************************************** + * Name: inode_checkperm + ****************************************************************************/ + int inode_checkperm(FAR struct inode *inode, int amode) { #ifdef CONFIG_FS_PERMISSION @@ -271,7 +275,16 @@ int inode_checkopenperm(FAR struct inode *inode, int oflags) { FAR const struct file_operations *ops; - if (INODE_IS_PSEUDODIR(inode)) + if (INODE_IS_NAMEDSEM(inode)) + { +#ifdef CONFIG_FS_PERMISSION + return inode_checkperm(inode, R_OK | W_OK); +#else + return OK; +#endif + } + + if (INODE_IS_MQUEUE(inode) || INODE_IS_PSEUDODIR(inode)) { #ifdef CONFIG_FS_PERMISSION return inode_checkperm(inode, fs_open_amode(oflags)); diff --git a/fs/inode/fs_inodereserve.c b/fs/inode/fs_inodereserve.c index 8cd41a5b1869e..e255f3f375301 100644 --- a/fs/inode/fs_inodereserve.c +++ b/fs/inode/fs_inodereserve.c @@ -30,6 +30,7 @@ #include #include +#include #include #include "inode/inode.h" @@ -82,6 +83,9 @@ static FAR struct inode *inode_alloc(FAR const char *name, mode_t mode) { FAR struct inode *inode; int namelen; +#if defined(CONFIG_PSEUDOFS_ATTRIBUTES) && defined(CONFIG_SCHED_USER_IDENTITY) + FAR struct tcb_s *rtcb; +#endif namelen = inode_namelen(name); inode = fs_heap_zalloc(FSNODE_SIZE(namelen)); @@ -94,6 +98,15 @@ static FAR struct inode *inode_alloc(FAR const char *name, mode_t mode) clock_gettime(CLOCK_REALTIME, &inode->i_atime); inode->i_mtime = inode->i_atime; inode->i_ctime = inode->i_atime; +# if defined(CONFIG_SCHED_USER_IDENTITY) + rtcb = nxsched_self(); + if (rtcb != NULL && rtcb->group != NULL) + { + inode->i_owner = rtcb->group->tg_euid; + inode->i_group = rtcb->group->tg_egid; + } + +# endif #endif inode_namecpy(inode->i_name, name); } diff --git a/fs/inode/inode.h b/fs/inode/inode.h index b8280d91bb5ed..7cacd0697f302 100644 --- a/fs/inode/inode.h +++ b/fs/inode/inode.h @@ -461,12 +461,6 @@ int fs_open_amode(int oflags); int fs_checkopenperm(uid_t owner, gid_t group, mode_t mode, int oflags); #endif -#ifdef CONFIG_FS_PERMISSION -int fs_checkmode(uid_t owner, gid_t group, mode_t mode, int amode); -int fs_open_amode(int oflags); -int fs_checkopenperm(uid_t owner, gid_t group, mode_t mode, int oflags); -#endif - /**************************************************************************** * Name: foreach_inode * diff --git a/fs/mqueue/mq_open.c b/fs/mqueue/mq_open.c index 514f053997ebf..feeeea66761ff 100644 --- a/fs/mqueue/mq_open.c +++ b/fs/mqueue/mq_open.c @@ -262,6 +262,26 @@ static int file_mq_vopen(FAR struct file *mq, FAR const char *mq_name, goto errout_with_inode; } +#ifdef CONFIG_FS_PERMISSION + ret = inode_checkopenperm(inode, oflags); + if (ret < 0) + { + goto errout_with_inode; + } +#endif + + if (inode->i_private == NULL) + { + ret = nxmq_alloc_msgq(NULL, &msgq); + if (ret < 0) + { + goto errout_with_inode; + } + + inode->i_private = msgq; + msgq->inode = inode; + } + /* Associate the inode with a file structure */ mq->f_oflags = oflags; diff --git a/fs/semaphore/sem_open.c b/fs/semaphore/sem_open.c index 0fdac9dd2c910..e89e0de746140 100644 --- a/fs/semaphore/sem_open.c +++ b/fs/semaphore/sem_open.c @@ -138,6 +138,14 @@ int nxsem_open(FAR sem_t **sem, FAR const char *name, int oflags, ...) goto errout_with_inode; } +#ifdef CONFIG_FS_PERMISSION + ret = inode_checkopenperm(inode, O_RDWR); + if (ret < 0) + { + goto errout_with_inode; + } +#endif + /* Return a reference to the semaphore, retaining the reference * count on the inode. */ diff --git a/fs/shm/shm_open.c b/fs/shm/shm_open.c index dd609fc79c79c..27279c39867a5 100644 --- a/fs/shm/shm_open.c +++ b/fs/shm/shm_open.c @@ -112,11 +112,10 @@ static int file_shm_open(FAR struct file *shm, FAR const char *name, goto errout_with_sem; } -#ifdef CONFIG_PSEUDOFS_ATTRIBUTES - if (((oflags & O_ACCMODE) != O_RDONLY && !(inode->i_mode & S_IWUSR)) || - ((oflags & O_ACCMODE) != O_WRONLY && !(inode->i_mode & S_IRUSR))) +#ifdef CONFIG_FS_PERMISSION + ret = inode_checkopenperm(inode, oflags); + if (ret < 0) { - ret = -EACCES; inode_release(inode); goto errout_with_sem; } diff --git a/fs/vfs/fs_pseudofile.c b/fs/vfs/fs_pseudofile.c index e5376cfe97e5e..e5204b0641b5a 100644 --- a/fs/vfs/fs_pseudofile.c +++ b/fs/vfs/fs_pseudofile.c @@ -33,7 +33,6 @@ #include #include -#include #include #include #include @@ -468,10 +467,6 @@ int pseudofile_create(FAR struct inode **node, FAR const char *path, mode_t mode) { FAR struct fs_pseudofile_s *pf; -#if defined(CONFIG_PSEUDOFS_ATTRIBUTES) && \ - defined(CONFIG_SCHED_USER_IDENTITY) - FAR struct tcb_s *rtcb; -#endif int ret; if (node == NULL || path == NULL) @@ -498,17 +493,6 @@ int pseudofile_create(FAR struct inode **node, FAR const char *path, (*node)->u.i_ops = &g_pseudofile_ops; (*node)->i_private = pf; -#if defined(CONFIG_PSEUDOFS_ATTRIBUTES) && \ - defined(CONFIG_SCHED_USER_IDENTITY) - - rtcb = nxsched_self(); - if (rtcb != NULL && rtcb->group != NULL) - { - (*node)->i_owner = rtcb->group->tg_euid; - (*node)->i_group = rtcb->group->tg_egid; - } -#endif - atomic_fetch_add(&(*node)->i_crefs, 1); inode_unlock(); diff --git a/include/sys/syscall_lookup.h b/include/sys/syscall_lookup.h index 7a1f37284c85e..97b1cee5b0532 100644 --- a/include/sys/syscall_lookup.h +++ b/include/sys/syscall_lookup.h @@ -71,6 +71,10 @@ SYSCALL_LOOKUP(sethostname, 2) SYSCALL_LOOKUP(geteuid, 0) SYSCALL_LOOKUP(setegid, 1) SYSCALL_LOOKUP(getegid, 0) + SYSCALL_LOOKUP(setreuid, 2) + SYSCALL_LOOKUP(setregid, 2) + SYSCALL_LOOKUP(getresuid, 3) + SYSCALL_LOOKUP(getresgid, 3) #endif /* Semaphores */ diff --git a/include/unistd.h b/include/unistd.h index 63ded5444ac11..e9d1686248c9f 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -494,6 +494,9 @@ gid_t getegid(void); int setreuid(uid_t ruid, uid_t euid); 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 getentropy(FAR void *buffer, size_t length); diff --git a/libs/libc/pwd/Kconfig b/libs/libc/pwd/Kconfig index 2fc6e0fbd5463..4e7b1cb92858a 100644 --- a/libs/libc/pwd/Kconfig +++ b/libs/libc/pwd/Kconfig @@ -22,13 +22,15 @@ if LIBC_PASSWD_FILE config LIBC_PASSWD_FILEPATH string "Path to passwd file" + default "/tmp/ostest_passwd" if TESTING_OSTEST_MULTIUSER default "/etc/passwd" ---help--- Provides the location of the passwd file. The default is /etc/passwd + (/tmp/ostest_passwd when CONFIG_TESTING_OSTEST_MULTIUSER is enabled). config LIBC_PASSWD_LINESIZE int "Maximum line size" - default 80 + default 256 ---help--- The maximum length of one line in the passwd file. This determines the size of the I/O buffer used to access the passwd file. diff --git a/libs/libc/pwd/lib_find_pwdfile.c b/libs/libc/pwd/lib_find_pwdfile.c index 97ac7abbfa1bb..88da93bbdac7f 100644 --- a/libs/libc/pwd/lib_find_pwdfile.c +++ b/libs/libc/pwd/lib_find_pwdfile.c @@ -170,14 +170,18 @@ static int pwd_foreach(pwd_foreach_match_t match, uintptr_t arg, * * The format of the password file is: * - * user:x:uid:uid:geos:home + * user:x:uid:gid:home + * + * Or the standard six-field form with an optional gecos field: + * + * user:x:uid:gid:gecos:home * * Where: * user: User name * x: Encrypted password * uid: User ID - * uid: Group ID - * geos: User information + * gid: Group ID + * gecos: User information (optional) * home: Login directory */ @@ -259,26 +263,45 @@ static int pwd_foreach(pwd_foreach_match_t match, uintptr_t arg, entry->pw_gid = (gid_t)atoi(save); save = ptr; - /* Skip to the end of the user information and properly terminate it. - * The user information must be terminated with the field delimiter - * ':'. + /* NuttX passwd files use user:hash:uid:gid:home. Standard passwd + * files may include an optional gecos field: + * user:hash:uid:gid:gecos:home */ - for (; *ptr != '\n' && *ptr != '\0' && *ptr != ':'; ptr++) + if (*ptr == ':') { - } + /* Skip to the end of the user information and properly terminate + * it. The user information must be terminated with the field + * delimiter ':'. + */ - if (*ptr == '\n' || *ptr == '\0') + for (; *ptr != '\n' && *ptr != '\0' && *ptr != ':'; ptr++) + { + } + + if (*ptr == '\n' || *ptr == '\0') + { + /* Bad line format? */ + + continue; + } + + *ptr++ = '\0'; + entry->pw_gecos = save; + entry->pw_dir = ptr; + } + else if (*save != '\0' && *save != '\n') + { + entry->pw_gecos = ""; + entry->pw_dir = save; + } + else { /* Bad line format? */ continue; } - *ptr++ = '\0'; - entry->pw_gecos = save; - entry->pw_dir = ptr; - /* Skip to the end of the home directory and properly terminate it. * The home directory must be the last thing on the line. */ diff --git a/libs/libc/unistd/CMakeLists.txt b/libs/libc/unistd/CMakeLists.txt index eb4ca8e5e937d..3521d45f607eb 100644 --- a/libs/libc/unistd/CMakeLists.txt +++ b/libs/libc/unistd/CMakeLists.txt @@ -43,8 +43,6 @@ set(SRCS lib_statvfs.c lib_sleep.c lib_nice.c - lib_setreuid.c - lib_setregid.c lib_getrusage.c lib_utime.c lib_utimes.c @@ -87,7 +85,11 @@ if(NOT CONFIG_SCHED_USER_IDENTITY) lib_seteuid.c lib_setegid.c lib_geteuid.c - lib_getegid.c) + lib_getegid.c + lib_setreuid.c + lib_setregid.c + lib_getresuid.c + lib_getresgid.c) endif() if(NOT CONFIG_DISABLE_ENVIRON) diff --git a/libs/libc/unistd/Make.defs b/libs/libc/unistd/Make.defs index e3e5ed3a2148d..602887be4c33a 100644 --- a/libs/libc/unistd/Make.defs +++ b/libs/libc/unistd/Make.defs @@ -27,7 +27,7 @@ CSRCS += lib_getcwd.c lib_getentropy.c lib_getopt_common.c lib_getopt.c CSRCS += lib_getopt_long.c lib_getopt_longonly.c lib_getoptvars.c lib_getoptargp.c CSRCS += lib_getopterrp.c lib_getoptindp.c lib_getoptoptp.c lib_times.c CSRCS += lib_alarm.c lib_fstatvfs.c lib_statvfs.c lib_sleep.c lib_nice.c -CSRCS += lib_setreuid.c lib_setregid.c lib_getrusage.c lib_utime.c lib_utimes.c +CSRCS += lib_getrusage.c lib_utime.c lib_utimes.c 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 @@ -39,6 +39,7 @@ CSRCS += lib_chdir.c lib_fchdir.c lib_confstr.c lib_ulimit.c 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 endif ifneq ($(CONFIG_DISABLE_ENVIRON),y) diff --git a/libs/libc/unistd/lib_getresgid.c b/libs/libc/unistd/lib_getresgid.c new file mode 100644 index 0000000000000..6cddc19fdb10c --- /dev/null +++ b/libs/libc/unistd/lib_getresgid.c @@ -0,0 +1,73 @@ +/**************************************************************************** + * libs/libc/unistd/lib_getresgid.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 + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: getresgid + * + * Description: + * The getresgid() function gets the real, effective, and saved set-group + * IDs of the calling process. + * + * Input Parameters: + * rgid - Location to return the real group ID, or NULL. + * egid - Location to return the effective group ID, or NULL. + * sgid - Location to return the saved set-group ID, or NULL. + * + * Returned Value: + * Zero if successful and -1 in case of failure, in which case errno is set + * appropriately. + * + ****************************************************************************/ + +int getresgid(FAR gid_t *rgid, FAR gid_t *egid, FAR gid_t *sgid) +{ + /* NuttX only supports the group identity 'root' with a gid value of 0. */ + + if (rgid != NULL) + { + *rgid = 0; + } + + if (egid != NULL) + { + *egid = 0; + } + + if (sgid != NULL) + { + *sgid = 0; + } + + return 0; +} diff --git a/libs/libc/unistd/lib_getresuid.c b/libs/libc/unistd/lib_getresuid.c new file mode 100644 index 0000000000000..7621f0e3aa3f5 --- /dev/null +++ b/libs/libc/unistd/lib_getresuid.c @@ -0,0 +1,73 @@ +/**************************************************************************** + * libs/libc/unistd/lib_getresuid.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 + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: getresuid + * + * Description: + * The getresuid() function gets the real, effective, and saved set-user + * IDs of the calling process. + * + * Input Parameters: + * ruid - Location to return the real user ID, or NULL. + * euid - Location to return the effective user ID, or NULL. + * suid - Location to return the saved set-user ID, or NULL. + * + * Returned Value: + * Zero if successful and -1 in case of failure, in which case errno is set + * appropriately. + * + ****************************************************************************/ + +int getresuid(FAR uid_t *ruid, FAR uid_t *euid, FAR uid_t *suid) +{ + /* NuttX only supports the user identity 'root' with a uid value of 0. */ + + if (ruid != NULL) + { + *ruid = 0; + } + + if (euid != NULL) + { + *euid = 0; + } + + if (suid != NULL) + { + *suid = 0; + } + + return 0; +} diff --git a/libs/libc/unistd/lib_setregid.c b/libs/libc/unistd/lib_setregid.c index 0f331e97940db..40cb19c8a494f 100644 --- a/libs/libc/unistd/lib_setregid.c +++ b/libs/libc/unistd/lib_setregid.c @@ -43,7 +43,7 @@ * Input Parameters: * rgid - Real group identity to set. The special value (gid_t)-1 * indicates that the real group ID should not be changed. - * rgid - Effective group identity to set. The special value (gid_t)-1 + * egid - Effective group identity to set. The special value (gid_t)-1 * indicates that the effective group ID should not be changed. * * Returned Value: @@ -54,25 +54,18 @@ int setregid(gid_t rgid, gid_t egid) { - int ret = OK; + /* NuttX only supports the group identity 'root' with a gid value of 0. */ - if (rgid != (gid_t)-1) + if ((rgid == (gid_t)-1 || rgid == 0) && + (egid == (gid_t)-1 || egid == 0)) { - /* Set the real group ID. CAREFUL: This exploits non-standard - * behavior of setgid(): setgid() should set the real, effective, and - * saved group ID. Here we depend on it setting only the real group - * ID. - */ - - ret = setgid(rgid); + return 0; } - if (ret >= 0 && egid != (gid_t)-1) - { - /* Set the effective group ID */ - - ret = setegid(egid); - } + /* All other gid values are considered invalid and not supported by the + * implementation. + */ - return ret; + set_errno(EINVAL); + return -1; } diff --git a/libs/libc/unistd/lib_setreuid.c b/libs/libc/unistd/lib_setreuid.c index f2163a846fe53..bd8f439f42681 100644 --- a/libs/libc/unistd/lib_setreuid.c +++ b/libs/libc/unistd/lib_setreuid.c @@ -43,7 +43,7 @@ * Input Parameters: * ruid - Real user identity to set. The special value (uid_t)-1 * indicates that the real user ID should not be changed. - * ruid - Effective user identity to set. The special value (uid_t)-1 + * euid - Effective user identity to set. The special value (uid_t)-1 * indicates that the effective user ID should not be changed. * * Returned Value: @@ -54,24 +54,18 @@ int setreuid(uid_t ruid, uid_t euid) { - int ret = OK; + /* NuttX only supports the user identity 'root' with a uid value of 0. */ - if (ruid != (uid_t)-1) + if ((ruid == (uid_t)-1 || ruid == 0) && + (euid == (uid_t)-1 || euid == 0)) { - /* Set the real user ID. CAREFUL: This exploits non-standard behavior - * of setuid(): setuid() should set the real, effective, and saved - * user ID. Here we depend on it setting only the real user ID. - */ - - ret = setuid(ruid); + return 0; } - if (ret >= 0 && euid != (uid_t)-1) - { - /* Set the effective user ID */ - - ret = seteuid(euid); - } + /* All other uid values are considered invalid and not supported by the + * implementation. + */ - return ret; + set_errno(EINVAL); + return -1; } diff --git a/sched/group/CMakeLists.txt b/sched/group/CMakeLists.txt index dcb96d6952d42..736b50dcd5822 100644 --- a/sched/group/CMakeLists.txt +++ b/sched/group/CMakeLists.txt @@ -52,7 +52,11 @@ if(CONFIG_SCHED_USER_IDENTITY) group_seteuid.c group_setegid.c group_geteuid.c - group_getegid.c) + group_getegid.c + group_setreuid.c + group_setregid.c + group_getresuid.c + group_getresgid.c) endif() if(CONFIG_SIG_SIGSTOP_ACTION) diff --git a/sched/group/Make.defs b/sched/group/Make.defs index 98ea6d09c6fae..3b822fbf2f51b 100644 --- a/sched/group/Make.defs +++ b/sched/group/Make.defs @@ -41,6 +41,7 @@ endif 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 endif ifeq ($(CONFIG_SIG_SIGSTOP_ACTION),y) diff --git a/sched/group/group_getresgid.c b/sched/group/group_getresgid.c new file mode 100644 index 0000000000000..92db2e1e0e239 --- /dev/null +++ b/sched/group/group_getresgid.c @@ -0,0 +1,79 @@ +/**************************************************************************** + * sched/group/group_getresgid.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 + +#include +#include + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: getresgid + * + * Description: + * The getresgid() function gets the real, effective, and saved set-group + * IDs of the calling process. + * + * Input Parameters: + * rgid - Location to return the real group ID, or NULL. + * egid - Location to return the effective group ID, or NULL. + * sgid - Location to return the saved set-group ID, or NULL. + * + * Returned Value: + * Zero if successful and -1 in case of failure, in which case errno is set + * appropriately. + * + ****************************************************************************/ + +int getresgid(FAR gid_t *rgid, FAR gid_t *egid, FAR gid_t *sgid) +{ + FAR struct tcb_s *rtcb = this_task(); + FAR struct task_group_s *rgroup = rtcb->group; + + DEBUGASSERT(rgroup != NULL); + + if (rgid != NULL) + { + *rgid = rgroup->tg_gid; + } + + if (egid != NULL) + { + *egid = rgroup->tg_egid; + } + + if (sgid != NULL) + { + *sgid = rgroup->tg_sgid; + } + + return OK; +} diff --git a/sched/group/group_getresuid.c b/sched/group/group_getresuid.c new file mode 100644 index 0000000000000..cd247b74db4fe --- /dev/null +++ b/sched/group/group_getresuid.c @@ -0,0 +1,79 @@ +/**************************************************************************** + * sched/group/group_getresuid.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 + +#include +#include + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: getresuid + * + * Description: + * The getresuid() function gets the real, effective, and saved set-user + * IDs of the calling process. + * + * Input Parameters: + * ruid - Location to return the real user ID, or NULL. + * euid - Location to return the effective user ID, or NULL. + * suid - Location to return the saved set-user ID, or NULL. + * + * Returned Value: + * Zero if successful and -1 in case of failure, in which case errno is set + * appropriately. + * + ****************************************************************************/ + +int getresuid(FAR uid_t *ruid, FAR uid_t *euid, FAR uid_t *suid) +{ + FAR struct tcb_s *rtcb = this_task(); + FAR struct task_group_s *rgroup = rtcb->group; + + DEBUGASSERT(rgroup != NULL); + + if (ruid != NULL) + { + *ruid = rgroup->tg_uid; + } + + if (euid != NULL) + { + *euid = rgroup->tg_euid; + } + + if (suid != NULL) + { + *suid = rgroup->tg_suid; + } + + return OK; +} diff --git a/sched/group/group_setregid.c b/sched/group/group_setregid.c new file mode 100644 index 0000000000000..61360f939ddd0 --- /dev/null +++ b/sched/group/group_setregid.c @@ -0,0 +1,154 @@ +/**************************************************************************** + * sched/group/group_setregid.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 + +#include +#include +#include + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: setregid + * + * Description: + * The setregid() function sets the real group ID and/or the effective + * group ID of the calling process. + * + * Input Parameters: + * rgid - Real group identity to set. The special value (gid_t)-1 + * indicates that the real group ID should not be changed. + * egid - Effective group identity to set. The special value (gid_t)-1 + * indicates that the effective group ID should not be changed. + * + * Returned Value: + * Zero if successful and -1 in case of failure, in which case errno is set + * appropriately. + * + ****************************************************************************/ + +int setregid(gid_t rgid, gid_t egid) +{ + FAR struct tcb_s *rtcb; + FAR struct task_group_s *rgroup; + gid_t old_rgid; + 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; + } + + rtcb = this_task(); + rgroup = rtcb->group; + + DEBUGASSERT(rgroup != NULL); + + old_rgid = rgroup->tg_gid; + old_egid = rgroup->tg_egid; + old_sgid = rgroup->tg_sgid; + + if (old_egid == 0) + { + /* Super-user: may set any combination of real and effective IDs. */ + + if (rgid != (gid_t)-1) + { + rgroup->tg_gid = rgid; + + if (egid == (gid_t)-1) + { + rgroup->tg_egid = rgid; + rgroup->tg_sgid = rgid; + } + } + + if (egid != (gid_t)-1) + { + rgroup->tg_egid = egid; + rgroup->tg_sgid = egid; + } + + return OK; + } + + /* Non-super-user */ + + if (rgid != (gid_t)-1 && + rgid != old_egid && rgid != old_sgid) + { + set_errno(EPERM); + return ERROR; + } + + if (egid != (gid_t)-1 && + egid != old_egid && egid != old_sgid && egid != old_rgid) + { + set_errno(EPERM); + return ERROR; + } + + if (rgid != (gid_t)-1) + { + rgroup->tg_gid = rgid; + } + + if (egid != (gid_t)-1) + { + rgroup->tg_egid = egid; + } + + /* If the real group ID is being set, or the effective group ID is being + * changed to a value not equal to the real group ID, update the saved + * set-group-ID to the new effective group ID. + */ + + if ((rgid != (gid_t)-1 && rgroup->tg_gid != old_rgid) || + (egid != (gid_t)-1 && rgroup->tg_egid != old_rgid)) + { + rgroup->tg_sgid = rgroup->tg_egid; + } + + return OK; +} diff --git a/sched/group/group_setreuid.c b/sched/group/group_setreuid.c new file mode 100644 index 0000000000000..0610f9fdda689 --- /dev/null +++ b/sched/group/group_setreuid.c @@ -0,0 +1,155 @@ +/**************************************************************************** + * sched/group/group_setreuid.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 + +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: setreuid + * + * Description: + * The setreuid() function sets the real user ID and/or the effective user + * ID of the calling process. + * + * Input Parameters: + * ruid - Real user identity to set. The special value (uid_t)-1 + * indicates that the real user ID should not be changed. + * euid - Effective user identity to set. The special value (uid_t)-1 + * indicates that the effective user ID should not be changed. + * + * Returned Value: + * Zero if successful and -1 in case of failure, in which case errno is set + * appropriately. + * + ****************************************************************************/ + +int setreuid(uid_t ruid, uid_t euid) +{ + FAR struct tcb_s *rtcb; + FAR struct task_group_s *rgroup; + uid_t old_ruid; + 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; + } + + rtcb = this_task(); + rgroup = rtcb->group; + + DEBUGASSERT(rgroup != NULL); + + old_ruid = rgroup->tg_uid; + old_euid = rgroup->tg_euid; + old_suid = rgroup->tg_suid; + + if (old_euid == 0) + { + /* Super-user: may set any combination of real and effective IDs. */ + + if (ruid != (uid_t)-1) + { + rgroup->tg_uid = ruid; + + if (euid == (uid_t)-1) + { + rgroup->tg_euid = ruid; + rgroup->tg_suid = ruid; + } + } + + if (euid != (uid_t)-1) + { + rgroup->tg_euid = euid; + rgroup->tg_suid = euid; + } + + return OK; + } + + /* Non-super-user */ + + if (ruid != (uid_t)-1 && + ruid != old_euid && ruid != old_suid) + { + set_errno(EPERM); + return ERROR; + } + + if (euid != (uid_t)-1 && + euid != old_euid && euid != old_suid && euid != old_ruid) + { + set_errno(EPERM); + return ERROR; + } + + if (ruid != (uid_t)-1) + { + rgroup->tg_uid = ruid; + } + + if (euid != (uid_t)-1) + { + rgroup->tg_euid = euid; + } + + /* If the real user ID is being set, or the effective user ID is being + * changed to a value not equal to the real user ID, update the saved + * set-user-ID to the new effective user ID. + */ + + if ((ruid != (uid_t)-1 && rgroup->tg_uid != old_ruid) || + (euid != (uid_t)-1 && rgroup->tg_euid != old_ruid)) + { + rgroup->tg_suid = rgroup->tg_euid; + } + + return OK; +} diff --git a/syscall/syscall.csv b/syscall/syscall.csv index 4622a0910b817..582deb3907f4f 100644 --- a/syscall/syscall.csv +++ b/syscall/syscall.csv @@ -39,6 +39,8 @@ "futimens","sys/stat.h","","int","int","const struct timespec [2]|FAR const struct timespec *" "get_environ_ptr","stdlib.h","!defined(CONFIG_DISABLE_ENVIRON)","FAR char **" "getegid","unistd.h","defined(CONFIG_SCHED_USER_IDENTITY)","gid_t" +"getresgid","unistd.h","defined(CONFIG_SCHED_USER_IDENTITY)","int","gid_t *","gid_t *","gid_t *" +"getresuid","unistd.h","defined(CONFIG_SCHED_USER_IDENTITY)","int","uid_t *","uid_t *","uid_t *" "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" @@ -150,6 +152,8 @@ "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" +"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" "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"