]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
SOLARIS: Use AFS_PAG_ONEGROUP_ENV for Solaris 11
authorAndrew Deason <adeason@dson.org>
Sat, 8 Aug 2015 21:49:50 +0000 (16:49 -0500)
committerStephan Wiesand <stephan.wiesand@desy.de>
Wed, 15 Mar 2017 18:04:56 +0000 (14:04 -0400)
On Solaris 11 (specifically, Solaris 11.1+), the supplemental group
list for a process is supposed to be sorted. Starting with Solaris
11.2, more authorization checks are done that assume the list is
sorted (e.g., to do a binary search), so having them out of order
can cause incorrect behavior. For example:

  $ echo foo > /tmp/testfile
  $ chmod 660 /tmp/testfile
  $ sudo chown root:daemon /tmp/testfile
  $ cat /tmp/testfile
  foo
  $ id -a
  uid=100(adeason) gid=10(staff) groups=10(staff),12(daemon),20(games),21(ftp),50(gdm),60(xvm),90(postgres)
  $ pagsh
  $ cat /tmp/testfile
  cat: cannot open /tmp/testfile: Permission denied
  $ id -a
  uid=100(adeason) gid=10(staff) groups=33536,32514,10(staff),12(daemon),20(games),21(ftp),50(gdm),60(xvm),90(postgres)

Solaris sorts the groups given to crsetgroups() on versions which
required the group ids to be sorted, but we currently manually put our
PAG groups in our own order in afs_setgroups(). This is currently
required, since various places in the code assume that PAG groups are
the first two groups in a process's group list.

To get around this, do not require the PAG gids to be the first two
gids anymore. To more easily identify PAG gids in group processes, use
a single gid instead of two gids to identify a PAG, like modern Linux
currently uses (under the AFS_PAG_ONEGROUP_ENV). High-numbered groups
have been possible for quite a long time on Solaris, allegedly further
back than Solaris 8. Only do this for Solaris 11, though, to reduce
the platforms we affect.

[mmeffie@sinenomine.net: Define AFS_PAG_ONEGROUP_ENV in param.h.]

Reviewed-on: https://gerrit.openafs.org/11979
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
Tested-by: BuildBot <buildbot@rampaginggeek.com>
(cherry picked from commit aab1e71628e6a4ce68c5e59e2f815867438280d1)

Change-Id: I54c1f4c1be4eed1804293aebae795b165954a3a4
Reviewed-on: https://gerrit.openafs.org/12526
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Mark Vitale <mvitale@sinenomine.net>
Reviewed-by: Michael Meffie <mmeffie@sinenomine.net>
Reviewed-by: Stephan Wiesand <stephan.wiesand@desy.de>
src/afs/SOLARIS/osi_groups.c
src/afs/afs_osi_pag.c
src/afs/afs_pioctl.c
src/afs/afs_prototypes.h
src/config/param.sun4x_511.h
src/config/param.sunx86_511.h

index 321e0c28214b78b3e59e63670acea7b91eff51e8..a33736d8b4b3d11de299b66069c50ea5d473e24e 100644 (file)
@@ -78,6 +78,91 @@ afs_xsetgroups(uap, rvp)
     return code;
 }
 
+#ifdef AFS_PAG_ONEGROUP_ENV
+/**
+ * Take a PAG, and put it into the given array of gids.
+ *
+ * @param[in] pagvalue     The numeric id for the PAG to assign (must not be -1)
+ * @param[in] gidset       An array of gids
+ * @param[inout] a_ngroups How many entries in 'gidset' have valid gids
+ * @param[in] gidset_sz    The number of bytes allocated for 'gidset'
+ *
+ * @return error code
+ */
+static int
+pag_to_gidset(afs_uint32 pagvalue, gid_t *gidset, int *a_ngroups,
+              size_t gidset_sz)
+{
+    int i;
+    gid_t *gidslot = NULL;
+    int ngroups = *a_ngroups;
+
+    osi_Assert(pagvalue != -1);
+
+    /* See if we already have a PAG gid */
+    for (i = 0; i < ngroups; i++) {
+        if (((gidset[i] >> 24) & 0xff) == 'A') {
+            gidslot = &gidset[i];
+            break;
+        }
+    }
+
+    if (gidslot != NULL) {
+        /* If we don't already have a PAG, grow the groups list by one, and put
+         * our PAG in the new empty slot. */
+        if ((sizeof(gidset[0])) * (ngroups + 1) > gidset_sz) {
+            return E2BIG;
+        }
+        ngroups += 1;
+        gidslot = &gidset[ngroups-1];
+    }
+
+    /*
+     * For newer Solaris releases (Solaris 11), we cannot control the order of
+     * the supplemental groups list of a process, so we can't store PAG gids as
+     * the first two gids anymore. To make finding a PAG gid easier to find,
+     * just use a single gid to represent a PAG, and just store the PAG id
+     * itself in there, like is currently done on Linux. Note that our PAG ids
+     * all start with the byte 0x41 ('A'), so we should not collide with
+     * anything. GIDs with the highest bit set are special (used for Windows
+     * SID mapping), but anything under that range should be fine.
+     */
+    *gidslot = pagvalue;
+
+    *a_ngroups = ngroups;
+
+    return 0;
+}
+#else
+/* For earlier Solaris releases, convert a PAG number into two gids, and store
+ * those gids as the first groups in the supplemental group list. */
+static int
+pag_to_gidset(afs_uint32 pagvalue, gid_t *gidset, int *a_ngroups,
+              size_t gidset_sz)
+{
+    int j;
+    int ngroups = *a_ngroups;
+
+    osi_Assert(pagvalue != -1);
+
+    if (afs_get_pag_from_groups(gidset[0], gidset[1]) == NOPAG) {
+       /* We will have to shift grouplist to make room for pag */
+       if ((sizeof(gidset[0])) * (ngroups + 2) > gidset_sz) {
+           return E2BIG;
+       }
+       for (j = ngroups - 1; j >= 0; j--) {
+           gidset[j + 2] = gidset[j];
+       }
+       ngroups += 2;
+    }
+    afs_get_groups_from_pag(pagvalue, &gidset[0], &gidset[1]);
+
+    *a_ngroups = ngroups;
+
+    return 0;
+}
+#endif
+
 int
 setpag(cred, pagvalue, newpag, change_parent)
      struct cred **cred;
@@ -87,7 +172,6 @@ setpag(cred, pagvalue, newpag, change_parent)
 {
     gid_t *gidset;
     int ngroups, code;
-    int j;
     size_t gidset_sz;
 
     AFS_STATCNT(setpag);
@@ -101,23 +185,19 @@ setpag(cred, pagvalue, newpag, change_parent)
     /* must use osi_Alloc, osi_AllocSmallSpace may not be enough. */
     gidset = osi_Alloc(gidset_sz);
 
+    pagvalue = (pagvalue == -1 ? genpag() : pagvalue);
+
     mutex_enter(&curproc->p_crlock);
     ngroups = afs_getgroups(*cred, gidset);
 
-    if (afs_get_pag_from_groups(gidset[0], gidset[1]) == NOPAG) {
-       /* We will have to shift grouplist to make room for pag */
-       if ((sizeof gidset[0]) * (ngroups + 2) > gidset_sz) {
-           mutex_exit(&curproc->p_crlock);
-           code = E2BIG;
-           goto done;
-       }
-       for (j = ngroups - 1; j >= 0; j--) {
-           gidset[j + 2] = gidset[j];
-       }
-       ngroups += 2;
+    code = pag_to_gidset(pagvalue, gidset, &ngroups, gidset_sz);
+    if (code != 0) {
+        mutex_exit(&curproc->p_crlock);
+        goto done;
     }
-    *newpag = (pagvalue == -1 ? genpag() : pagvalue);
-    afs_get_groups_from_pag(*newpag, &gidset[0], &gidset[1]);
+
+    *newpag = pagvalue;
+
     /* afs_setgroups will release curproc->p_crlock */
     /* exit action is same regardless of code */
     code = afs_setgroups(cred, ngroups, gidset, change_parent);
@@ -155,7 +235,9 @@ static int
 afs_setgroups(struct cred **cred, int ngroups, gid_t * gidset,
              int change_parent)
 {
+#ifndef AFS_PAG_ONEGROUP_ENV
     gid_t *gp;
+#endif
 
     AFS_STATCNT(afs_setgroups);
 
@@ -165,17 +247,42 @@ afs_setgroups(struct cred **cred, int ngroups, gid_t * gidset,
     }
     if (!change_parent)
        *cred = (struct cred *)crcopy(*cred);
-#if defined(AFS_SUN510_ENV)
+
+#ifdef AFS_PAG_ONEGROUP_ENV
     crsetgroups(*cred, ngroups, gidset);
-    gp = crgetgroups(*cred);
 #else
+# if defined(AFS_SUN510_ENV)
+    crsetgroups(*cred, ngroups, gidset);
+    gp = crgetgroups(*cred);
+# else
     (*cred)->cr_ngroups = ngroups;
     gp = (*cred)->cr_groups;
-#endif
+# endif
     while (ngroups--)
        *gp++ = *gidset++;
+#endif /* !AFS_PAG_ONEGROUP_ENV */
+
     mutex_exit(&curproc->p_crlock);
     if (!change_parent)
        crset(curproc, *cred);  /* broadcast to all threads */
     return (0);
 }
+
+#ifdef AFS_PAG_ONEGROUP_ENV
+afs_int32
+osi_get_group_pag(struct cred *cred) {
+    gid_t *gidset;
+    int ngroups;
+    int i;
+
+    gidset = crgetgroups(cred);
+    ngroups = crgetngroups(cred);
+
+    for (i = 0; i < ngroups; i++) {
+        if (((gidset[i] >> 24) & 0xff) == 'A') {
+            return gidset[i];
+        }
+    }
+    return NOPAG;
+}
+#endif
index f722e62277ec40c2ae97c39f7607f9df0756c9c8..cdb1998595e8bc60dd434d56b6eaff4aafb9a8be 100644 (file)
@@ -535,7 +535,6 @@ afs_DestroyReq(struct vrequest *av)
     }
 }
 
-#ifndef AFS_PAG_ONEGROUP_ENV
 afs_uint32
 afs_get_pag_from_groups(gid_t g0a, gid_t g1a)
 {
@@ -563,6 +562,7 @@ afs_get_pag_from_groups(gid_t g0a, gid_t g1a)
     return NOPAG;
 }
 
+#ifndef AFS_PAG_ONEGROUP_ENV
 void
 afs_get_groups_from_pag(afs_uint32 pag, gid_t * g0p, gid_t * g1p)
 {
@@ -591,7 +591,13 @@ afs_get_groups_from_pag(afs_uint32 pag, gid_t *g0p, gid_t *g1p)
 }
 #endif
 
-#if !defined(AFS_LINUX26_ENV) && !defined(AFS_DARWIN110_ENV)
+#ifdef AFS_LINUX26_ENV
+/* osi_get_group_pag is defined in <ARCH>/osi_groups.c */
+#elif defined(AFS_PAG_ONEGROUP_ENV)
+/* osi_get_group_pag is defined in <ARCH>/osi_groups.c */
+#elif defined(AFS_DARWIN110_ENV)
+/* We don't have pags, so we do not define an osi_get_group_pag */
+#else
 static afs_int32
 osi_get_group_pag(afs_ucred_t *cred)
 {
index 071f7af5cfb59438a2b188019aceed13761c9105..8146af9bc7fab2091d75697ad75532d6962e06bf 100644 (file)
@@ -4573,9 +4573,14 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
     GROUP_AT(afs_cr_group_info(newcred), 1) = g1;
 # endif
 #elif defined(AFS_SUN510_ENV)
+# ifdef AFS_PAG_ONEGROUP_ENV
+    gids[0] = afs_get_pag_from_groups(g0, g1);
+    crsetgroups(newcred, 1, gids);
+# else
     gids[0] = g0;
     gids[1] = g1;
     crsetgroups(newcred, 2, gids);
+# endif /* !AFS_PAG_ONEGROUP_ENV */
 #else
     newcred->cr_groups[0] = g0;
     newcred->cr_groups[1] = g1;
index 9e9f65b1975c504f53affe8e887247f2d65e6c44..2386963599ec8a0d3a4c3c6b49a264e6fe0c8027 100644 (file)
@@ -731,7 +731,7 @@ extern int setpag(afs_proc_t *proc, struct ucred **cred, afs_uint32 pagvalue,
 # endif /* AFS_XBSD_ENV */
 #endif /* UKERNEL */
 
-#if defined(AFS_LINUX26_ENV)
+#if defined(AFS_LINUX26_ENV) || defined(AFS_PAG_ONEGROUP_ENV)
 extern afs_int32 osi_get_group_pag(afs_ucred_t *cred);
 #endif
 
index 464c80d91d485670deacb1dccac6131646948e43..edc2dc48b4e1f68a6af5648b3bc0973506d6bdf3 100644 (file)
@@ -45,6 +45,7 @@
 #define AFS_GLOBAL_SUNLOCK     1       /* For global locking */
 #define RXK_LISTENER_ENV       1
 #define AFS_GCPAGS             1       /* if nonzero, garbage collect PAGs */
+#define AFS_PAG_ONEGROUP_ENV   1       /* Use a single gid to indicate a PAG */
 
 /* File system entry (used if mount.h doesn't define MOUNT_AFS */
 #define AFS_MOUNT_AFS   "afs"
index a756b9b78880ba443ce2732469bf2412f6b79218..9d9acba24ead72066d04137852e875f6e82cc797 100644 (file)
@@ -46,6 +46,7 @@
 #define AFS_GLOBAL_SUNLOCK     1       /* For global locking */
 #define RXK_LISTENER_ENV       1
 #define AFS_GCPAGS             1       /* if nonzero, garbage collect PAGs */
+#define AFS_PAG_ONEGROUP_ENV   1       /* Use a single gid to indicate a PAG */
 
 #ifdef AFS_NAMEI_ENV
 #define AFS_64BIT_IOPS_ENV     1       /* needed for NAMEI... */