From b8bd90f68fb787cc321365c6de161d6b77c8353f Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 17 Nov 2014 09:01:53 +0100 Subject: Add supplementary groups to user environment --- cpukit/include/rtems/userenv.h | 74 ++++++++-- cpukit/libcsupport/Makefile.am | 1 + cpukit/libcsupport/include/rtems/libio_.h | 27 +++- cpukit/libcsupport/src/sup_fs_check_permissions.c | 47 ++++-- cpukit/libcsupport/src/uenvgetgroups.c | 36 +++++ testsuites/fstests/fsnofs01/init.c | 171 ++++++++++++++++++++++ 6 files changed, 330 insertions(+), 26 deletions(-) create mode 100644 cpukit/libcsupport/src/uenvgetgroups.c diff --git a/cpukit/include/rtems/userenv.h b/cpukit/include/rtems/userenv.h index 631d773ae5..7d6ffb05a5 100644 --- a/cpukit/include/rtems/userenv.h +++ b/cpukit/include/rtems/userenv.h @@ -25,6 +25,7 @@ * limits.h is supposed to provide _POSIX_LOGIN_NAME_MAX * XXX: We do not rely on this. */ +#include #include #include @@ -52,18 +53,64 @@ extern "C" { #endif #endif +/** + * @brief User environment. + */ typedef struct { + /** + * @brief The anchor directory for relative paths. + */ rtems_filesystem_global_location_t *current_directory; + + /** + * @brief The anchor directory for absolute paths. + */ rtems_filesystem_global_location_t *root_directory; - /* Default mode for all files. */ - mode_t umask; - /* _POSIX_types */ - uid_t uid; - gid_t gid; - uid_t euid; - gid_t egid; - char login_buffer[LOGIN_NAME_MAX]; - pid_t pgrp; /* process group id */ + + /** + * @brief The file mode creation mask. + */ + mode_t umask; + + /** + * @brief The real user ID. + */ + uid_t uid; + + /** + * @brief The real group ID. + */ + gid_t gid; + + /** + * @brief The effective user ID. + */ + uid_t euid; + + /** + * @brief The effective group ID. + */ + gid_t egid; + + /** + * @brief The login buffer. + */ + char login_buffer[LOGIN_NAME_MAX]; + + /** + * @brief The process group ID. + */ + pid_t pgrp; + + /** + * @brief The count of supplementary group IDs. + */ + size_t ngroups; + + /** + * @brief The list of supplementary group IDs. + */ + gid_t groups[NGROUPS]; } rtems_user_env_t; extern rtems_user_env_t rtems_global_user_env; @@ -116,6 +163,15 @@ rtems_status_code rtems_libio_set_private_env(void); */ void rtems_libio_use_global_env(void); +/** + * @brief Gets the supplementary group IDs using the current user ID and + * updates the table of supplementary group IDs in the current user + * environment. + * + * In case of an error, the count of supplementary group IDs is set to zero. + */ +void rtems_current_user_env_getgroups(void); + /** @} */ #ifdef __cplusplus diff --git a/cpukit/libcsupport/Makefile.am b/cpukit/libcsupport/Makefile.am index 6803fe6036..bd3f90a648 100644 --- a/cpukit/libcsupport/Makefile.am +++ b/cpukit/libcsupport/Makefile.am @@ -58,6 +58,7 @@ BASE_FS_C_FILES = src/base_fs.c src/mount.c src/unmount.c src/libio.c \ src/libio_helper_null.c \ src/libio_exit.c \ src/open_dev_console.c src/__usrenv.c src/rtems_mkdir.c +BASE_FS_C_FILES += src/uenvgetgroups.c TERMIOS_C_FILES = src/cfgetispeed.c src/cfgetospeed.c src/cfsetispeed.c \ src/cfsetospeed.c src/tcgetattr.c src/tcsetattr.c src/tcdrain.c \ diff --git a/cpukit/libcsupport/include/rtems/libio_.h b/cpukit/libcsupport/include/rtems/libio_.h index c0f4432d0e..458201ea3f 100644 --- a/cpukit/libcsupport/include/rtems/libio_.h +++ b/cpukit/libcsupport/include/rtems/libio_.h @@ -810,11 +810,30 @@ int rtems_filesystem_location_exists_in_same_instance_as( const rtems_filesystem_location_info_t *b ); +/** + * @brief Checks if access to an object is allowed for the current user. + * + * If the effective UID is zero or equals the UID of the object, then the user + * permission flags of the object will be used. Otherwise if the effective GID + * is zero or equals the GID of the object or one of the supplementary group + * IDs is equal to the GID of the object, then the group permission flags of + * the object will be used. Otherwise the other permission flags of the object + * will be used. + * + * @param[in] flags The flags determining the access type. It can be + * RTEMS_FS_PERMS_READ, RTEMS_FS_PERMS_WRITE or RTEMS_FS_PERMS_EXEC. + * @param[in] object_mode The mode of the object specifying the permission flags. + * @param[in] object_uid The UID of the object. + * @param[in] object_gid The GID of the object. + * + * @retval true Access is allowed. + * @retval false Otherwise. + */ bool rtems_filesystem_check_access( - int eval_flags, - mode_t node_mode, - uid_t node_uid, - gid_t node_gid + int flags, + mode_t object_mode, + uid_t object_uid, + gid_t object_gid ); bool rtems_filesystem_eval_path_check_access( diff --git a/cpukit/libcsupport/src/sup_fs_check_permissions.c b/cpukit/libcsupport/src/sup_fs_check_permissions.c index f6fd0e91c9..394f945b0b 100644 --- a/cpukit/libcsupport/src/sup_fs_check_permissions.c +++ b/cpukit/libcsupport/src/sup_fs_check_permissions.c @@ -70,29 +70,50 @@ RTEMS_STATIC_ASSERT( S_IXOTH ); +static bool equals_supplementary_group( + const rtems_user_env_t *uenv, + gid_t object_gid +) +{ + size_t i; + + for (i = 0; i < uenv->ngroups; ++i) { + if (uenv->groups[i] == object_gid) { + return true; + } + } + + return false; +} + bool rtems_filesystem_check_access( - int eval_flags, - mode_t node_mode, - uid_t node_uid, - gid_t node_gid + int flags, + mode_t object_mode, + uid_t object_uid, + gid_t object_gid ) { - mode_t perm_flags = eval_flags & RTEMS_FS_PERMS_RWX; - uid_t task_uid = geteuid(); + const rtems_user_env_t *uenv = rtems_current_user_env_get(); + mode_t access_flags = flags & RTEMS_FS_PERMS_RWX; + uid_t task_uid = uenv->euid; - if (task_uid == 0 || task_uid == node_uid) { - perm_flags <<= RTEMS_FS_USR_SHIFT; + if (task_uid == 0 || task_uid == object_uid) { + access_flags <<= RTEMS_FS_USR_SHIFT; } else { - gid_t task_gid = getegid(); + gid_t task_gid = uenv->egid; - if (task_gid == 0 || task_gid == node_gid) { - perm_flags <<= RTEMS_FS_GRP_SHIFT; + if ( + task_gid == 0 + || task_gid == object_gid + || equals_supplementary_group(uenv, object_gid) + ) { + access_flags <<= RTEMS_FS_GRP_SHIFT; } else { - perm_flags <<= RTEMS_FS_OTH_SHIFT; + access_flags <<= RTEMS_FS_OTH_SHIFT; } } - return (perm_flags & node_mode) == perm_flags; + return (access_flags & object_mode) == access_flags; } bool rtems_filesystem_eval_path_check_access( diff --git a/cpukit/libcsupport/src/uenvgetgroups.c b/cpukit/libcsupport/src/uenvgetgroups.c new file mode 100644 index 0000000000..9645a9618b --- /dev/null +++ b/cpukit/libcsupport/src/uenvgetgroups.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * D-82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include + +void rtems_current_user_env_getgroups(void) +{ + rtems_user_env_t *uenv = rtems_current_user_env_get(); + int ngroups = (int) RTEMS_ARRAY_SIZE( uenv->groups ); + + ngroups = getgroups( ngroups, &uenv->groups[ 0 ] ); + if ( ngroups > 0 ) { + uenv->ngroups = (size_t) ngroups; + } else { + uenv->ngroups = 0; + } +} diff --git a/testsuites/fstests/fsnofs01/init.c b/testsuites/fstests/fsnofs01/init.c index 13cd7096e7..f4759491ba 100644 --- a/testsuites/fstests/fsnofs01/init.c +++ b/testsuites/fstests/fsnofs01/init.c @@ -16,6 +16,7 @@ #include "config.h" #endif +#define TESTS_USE_PRINTK #include "tmacros.h" #include @@ -321,6 +322,175 @@ static void test_user_env(void) rtems_test_assert(null_loc->reference_count == 4); } +typedef struct { + int flags; + mode_t object_mode; + uid_t object_uid; + gid_t object_gid; + bool expected_ok; +} check_access_case; + +#define FR RTEMS_FS_PERMS_READ +#define FW RTEMS_FS_PERMS_WRITE +#define FX RTEMS_FS_PERMS_EXEC + +#define UR S_IRUSR +#define UW S_IWUSR +#define UX S_IXUSR + +#define GR S_IRGRP +#define GW S_IWGRP +#define GX S_IXGRP + +#define OR S_IROTH +#define OW S_IWOTH +#define OX S_IXOTH + +static const check_access_case check_access_euid_0_cases[] = { + { 0, 0, 6, 7, true }, + { FR, 0, 6, 7, false }, + { FW, 0, 6, 7, false }, + { FX, 0, 6, 7, false }, + { FR, UR, 6, 7, true }, + { FW, UW, 6, 7, true }, + { FX, UX, 6, 7, true }, + { FR, GR, 6, 7, false }, + { FW, GW, 6, 7, false }, + { FX, GX, 6, 7, false }, + { FR, OR, 6, 7, false }, + { FW, OW, 6, 7, false }, + { FX, OX, 6, 7, false } +}; + +static const check_access_case check_access_egid_0_cases[] = { + { 0, 0, 6, 7, true }, + { FR, 0, 6, 7, false }, + { FW, 0, 6, 7, false }, + { FX, 0, 6, 7, false }, + { FR, UR, 6, 7, false }, + { FW, UW, 6, 7, false }, + { FX, UX, 6, 7, false }, + { FR, GR, 6, 7, true }, + { FW, GW, 6, 7, true }, + { FX, GX, 6, 7, true }, + { FR, OR, 6, 7, false }, + { FW, OW, 6, 7, false }, + { FX, OX, 6, 7, false } +}; + +static const check_access_case check_access_other_cases[] = { + { 0, 0, 3, 7, true }, + { FR, 0, 3, 7, false }, + { FW, 0, 3, 7, false }, + { FX, 0, 3, 7, false }, + { FR, UR, 3, 7, true }, + { FW, UW, 3, 7, true }, + { FX, UX, 3, 7, true }, + { FR, GR, 3, 7, false }, + { FW, GW, 3, 7, false }, + { FX, GX, 3, 7, false }, + { FR, OR, 3, 7, false }, + { FW, OW, 3, 7, false }, + { FX, OX, 3, 7, false }, + { 0, 0, 6, 4, true }, + { FR, 0, 6, 4, false }, + { FW, 0, 6, 4, false }, + { FX, 0, 6, 4, false }, + { FR, UR, 6, 4, false }, + { FW, UW, 6, 4, false }, + { FX, UX, 6, 4, false }, + { FR, GR, 6, 4, true }, + { FW, GW, 6, 4, true }, + { FX, GX, 6, 4, true }, + { FR, OR, 6, 4, false }, + { FW, OW, 6, 4, false }, + { FX, OX, 6, 4, false }, + { 0, 0, 6, 5, true }, + { FR, 0, 6, 5, false }, + { FW, 0, 6, 5, false }, + { FX, 0, 6, 5, false }, + { FR, UR, 6, 5, false }, + { FW, UW, 6, 5, false }, + { FX, UX, 6, 5, false }, + { FR, GR, 6, 5, true }, + { FW, GW, 6, 5, true }, + { FX, GX, 6, 5, true }, + { FR, OR, 6, 5, false }, + { FW, OW, 6, 5, false }, + { FX, OX, 6, 5, false }, + { 0, 0, 6, 7, true }, + { FR, 0, 6, 7, false }, + { FW, 0, 6, 7, false }, + { FX, 0, 6, 7, false }, + { FR, UR, 6, 7, false }, + { FW, UW, 6, 7, false }, + { FX, UX, 6, 7, false }, + { FR, GR, 6, 7, false }, + { FW, GW, 6, 7, false }, + { FX, GX, 6, 7, false }, + { FR, OR, 6, 7, true }, + { FW, OW, 6, 7, true }, + { FX, OX, 6, 7, true } +}; + +static void check_access(const check_access_case *table, size_t n) +{ + size_t i; + + for (i = 0; i < n; ++i) { + const check_access_case *cac = &table[i]; + bool ok = rtems_filesystem_check_access( + cac->flags, + cac->object_mode, + cac->object_uid, + cac->object_gid + ); + + rtems_test_assert(ok == cac->expected_ok); + } +} + +static void test_check_access(void) +{ + rtems_user_env_t *uenv = rtems_current_user_env_get(); + + rtems_test_assert(uenv->uid == 0); + rtems_test_assert(uenv->gid == 0); + rtems_test_assert(uenv->euid == 0); + rtems_test_assert(uenv->egid == 0); + rtems_test_assert(uenv->ngroups == 0); + + uenv->uid = 1; + uenv->gid = 2; + + check_access( + &check_access_euid_0_cases[0], + RTEMS_ARRAY_SIZE(check_access_euid_0_cases) + ); + + uenv->euid = 3; + + check_access( + &check_access_egid_0_cases[0], + RTEMS_ARRAY_SIZE(check_access_egid_0_cases) + ); + + uenv->egid = 4; + uenv->ngroups = 1; + uenv->groups[0] = 5; + + check_access( + &check_access_other_cases[0], + RTEMS_ARRAY_SIZE(check_access_other_cases) + ); + + uenv->uid = 0; + uenv->gid = 0; + uenv->euid = 0; + uenv->egid = 0; + uenv->ngroups = 0; +} + static void Init(rtems_task_argument arg) { rtems_test_begink(); @@ -334,6 +504,7 @@ static void Init(rtems_task_argument arg) test_null_location_get_and_replace(); test_path_ops(); test_user_env(); + test_check_access(); rtems_test_endk(); exit(0); -- cgit v1.2.3