Package: spl-dkms Severity: important Tags: patch since the 4.9 kernel is now available in unstable, the following upstream patches need to be cherry-picked for compatibility:
aa70231f096dff572cfb1307d8f4e63dbf2b60f1 587ceae110e900da1203192336e3a14d4161b777 please find conflict-resolved versions attached (seem to work for me, but more eyes can't hurt). Thanks for your work on ZFS/SPL in Debian!
From aa70231f096dff572cfb1307d8f4e63dbf2b60f1 Mon Sep 17 00:00:00 2001 From: Chunwei Chen <[email protected]> Date: Tue, 18 Oct 2016 15:52:30 -0700 Subject: [PATCH 1/2] 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 --- module/spl/spl-cred.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/module/spl/spl-cred.c b/module/spl/spl-cred.c index a03f459..d046f95 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; } -- 2.11.0
From 587ceae110e900da1203192336e3a14d4161b777 Mon Sep 17 00:00:00 2001 From: Chunwei Chen <[email protected]> Date: Tue, 18 Oct 2016 17:30:41 -0700 Subject: [PATCH 2/2] Linux 4.9 compat: group_info changes In Linux 4.9, torvalds/linux@81243ea, group_info changed from 2d array via ->blocks to 1d array via ->gid. We change the spl cred functions accordingly. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Chunwei Chen <[email protected]> Closes #581 --- config/spl-build.m4 | 23 +++++++++++++++++++++++ include/sys/cred.h | 5 +++++ module/spl/spl-cred.c | 10 ++++++++++ module/splat/splat-cred.c | 5 +++-- 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/config/spl-build.m4 b/config/spl-build.m4 index c401fd8..5a2f1de 100644 --- a/config/spl-build.m4 +++ b/config/spl-build.m4 @@ -49,6 +49,7 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [ SPL_AC_WAIT_ON_BIT SPL_AC_INODE_LOCK SPL_AC_MUTEX_OWNER + SPL_AC_GROUP_INFO_GID ]) AC_DEFUN([SPL_AC_MODULE_SYMVERS], [ @@ -1574,3 +1575,25 @@ AC_DEFUN([SPL_AC_MUTEX_OWNER], [ ]) EXTRA_KCFLAGS="$tmp_flags" ]) + +dnl # +dnl # 4.9 API change +dnl # group_info changed from 2d array via >blocks to 1d array via ->gid +dnl # +AC_DEFUN([SPL_AC_GROUP_INFO_GID], [ + AC_MSG_CHECKING([whether group_info->gid exists]) + tmp_flags="$EXTRA_KCFLAGS" + EXTRA_KCFLAGS="-Werror" + SPL_LINUX_TRY_COMPILE([ + #include <linux/cred.h> + ],[ + struct group_info *gi = groups_alloc(1); + gi->gid[0] = KGIDT_INIT(0); + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_GROUP_INFO_GID, 1, [group_info->gid exists]) + ],[ + AC_MSG_RESULT(no) + ]) + EXTRA_KCFLAGS="$tmp_flags" +]) diff --git a/include/sys/cred.h b/include/sys/cred.h index 4f62b00..480e268 100644 --- a/include/sys/cred.h +++ b/include/sys/cred.h @@ -34,6 +34,11 @@ typedef struct cred cred_t; #define kcred ((cred_t *)(init_task.cred)) #define CRED() ((cred_t *)current_cred()) +/* Linux 4.9 API change, GROUP_AT was removed */ +#ifndef GROUP_AT +#define GROUP_AT(gi, i) ((gi)->gid[i]) +#endif + #ifdef HAVE_KUIDGID_T /* diff --git a/module/spl/spl-cred.c b/module/spl/spl-cred.c index d046f95..1d486c1 100644 --- a/module/spl/spl-cred.c +++ b/module/spl/spl-cred.c @@ -85,7 +85,9 @@ crgetngroups(const cred_t *cr) gi = cr->group_info; rc = gi->ngroups; +#ifndef HAVE_GROUP_INFO_GID /* + * For Linux <= 4.8, * crgetgroups will only returns gi->blocks[0], which contains only * the first NGROUPS_PER_BLOCK groups. */ @@ -93,12 +95,16 @@ crgetngroups(const cred_t *cr) WARN_ON_ONCE(1); rc = NGROUPS_PER_BLOCK; } +#endif 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(). + * + * Linux 4.9 API change, group_info changed from 2d array via ->blocks to 1d + * array via ->gid. */ gid_t * crgetgroups(const cred_t *cr) @@ -107,8 +113,12 @@ crgetgroups(const cred_t *cr) gid_t *gids = NULL; gi = cr->group_info; +#ifdef HAVE_GROUP_INFO_GID + gids = KGIDP_TO_SGIDP(gi->gid); +#else if (gi->nblocks > 0) gids = KGIDP_TO_SGIDP(gi->blocks[0]); +#endif return gids; } diff --git a/module/splat/splat-cred.c b/module/splat/splat-cred.c index fadf9bc..224a8e4 100644 --- a/module/splat/splat-cred.c +++ b/module/splat/splat-cred.c @@ -166,6 +166,7 @@ splat_cred_test2(struct file *file, void *arg) return 0; } /* splat_cred_test2() */ +#define SPLAT_NGROUPS 32 /* * Verify the groupmember() works correctly by constructing an interesting * CRED() and checking that the expected gids are part of it. @@ -188,7 +189,7 @@ splat_cred_test3(struct file *file, void *arg) * 1:(NGROUPS_MAX-1). Gid 0 is explicitly avoided so we can reliably * test for its absence in the test cases. */ - gi = groups_alloc(NGROUPS_SMALL); + gi = groups_alloc(SPLAT_NGROUPS); if (gi == NULL) { splat_vprint(file, SPLAT_CRED_TEST3_NAME, "Failed create " "group_info for known gids: %d\n", -ENOMEM); @@ -196,7 +197,7 @@ splat_cred_test3(struct file *file, void *arg) goto show_groups; } - for (i = 0, tmp_gid = known_gid; i < NGROUPS_SMALL; i++) { + for (i = 0, tmp_gid = known_gid; i < SPLAT_NGROUPS; i++) { splat_vprint(file, SPLAT_CRED_TEST3_NAME, "Adding gid %d " "to current CRED() (%d/%d)\n", tmp_gid, i, gi->ngroups); #ifdef HAVE_KUIDGID_T -- 2.11.0

