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

Reply via email to