aboutsummaryrefslogtreecommitdiffstats
path: root/module/spl
diff options
context:
space:
mode:
authorChunwei Chen <[email protected]>2016-10-18 15:52:30 -0700
committerBrian Behlendorf <[email protected]>2016-10-20 09:33:01 -0700
commit9ba3c01923d45a19003641ceab311150752ed491 (patch)
tree945091a7ec3807474bde360a4d878dce4eb8e932 /module/spl
parent0d267566650d89bde8bd5ec4665749810d5bafc7 (diff)
Fix crgetgroups out-of-bound and misc cred fix
init_groups has 0 nblocks, therefore calling the current crgetgroups with init_groups would result in out-of-bound access. We fix this by returning NULL when nblocks is 0. Cap crgetngroups to NGROUPS_PER_BLOCK, since crgetgroups will only return blocks[0]. Also, remove all get_group_info. The cred already holds reference on the group_info, and cred is not mutable. So there's no reason to hold extra reference, if we hold cred. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Chunwei Chen <[email protected]> Closes #556
Diffstat (limited to 'module/spl')
-rw-r--r--module/spl/spl-cred.c31
1 files changed, 16 insertions, 15 deletions
diff --git a/module/spl/spl-cred.c b/module/spl/spl-cred.c
index a03f459e0..d046f9513 100644
--- a/module/spl/spl-cred.c
+++ b/module/spl/spl-cred.c
@@ -62,19 +62,17 @@ cr_groups_search(const struct group_info *group_info, gid_t grp)
return 0;
}
-/* Hold a reference on the credential and group info */
+/* Hold a reference on the credential */
void
crhold(cred_t *cr)
{
(void)get_cred((const cred_t *)cr);
- (void)get_group_info(cr->group_info);
}
-/* Free a reference on the credential and group info */
+/* Free a reference on the credential */
void
crfree(cred_t *cr)
{
- put_group_info(cr->group_info);
put_cred((const cred_t *)cr);
}
@@ -85,28 +83,32 @@ crgetngroups(const cred_t *cr)
struct group_info *gi;
int rc;
- gi = get_group_info(cr->group_info);
+ gi = cr->group_info;
rc = gi->ngroups;
- put_group_info(gi);
-
+ /*
+ * crgetgroups will only returns gi->blocks[0], which contains only
+ * the first NGROUPS_PER_BLOCK groups.
+ */
+ if (rc > NGROUPS_PER_BLOCK) {
+ WARN_ON_ONCE(1);
+ rc = NGROUPS_PER_BLOCK;
+ }
return rc;
}
/*
* Return an array of supplemental gids. The returned address is safe
* to use as long as the caller has taken a reference with crhold().
- * The caller is responsible for releasing the reference with crfree().
*/
gid_t *
crgetgroups(const cred_t *cr)
{
struct group_info *gi;
- gid_t *gids;
-
- gi = get_group_info(cr->group_info);
- gids = KGIDP_TO_SGIDP(gi->blocks[0]);
- put_group_info(gi);
+ gid_t *gids = NULL;
+ gi = cr->group_info;
+ if (gi->nblocks > 0)
+ gids = KGIDP_TO_SGIDP(gi->blocks[0]);
return gids;
}
@@ -117,9 +119,8 @@ groupmember(gid_t gid, const cred_t *cr)
struct group_info *gi;
int rc;
- gi = get_group_info(cr->group_info);
+ gi = cr->group_info;
rc = cr_groups_search(gi, SGID_TO_KGID(gid));
- put_group_info(gi);
return rc;
}