[PATCH 07/22] Add supplementary groups to user environment

Sebastian Huber sebastian.huber at embedded-brains.de
Tue Nov 18 14:37:13 UTC 2014


---
 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 631d773..7d6ffb0 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 <sys/param.h>
 #include <limits.h>
 
 #include <rtems.h>
@@ -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 6803fe6..bd3f90a 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 c0f4432..458201e 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 f6fd0e9..394f945 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 0000000..9645a96
--- /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
+ * <rtems at embedded-brains.de>
+ *
+ * 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 <rtems/userenv.h>
+#include <rtems.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+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 13cd709..f475949 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 <sys/stat.h>
@@ -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);
-- 
1.8.4.5




More information about the devel mailing list