Skip to contentSkip to conversation

Many groups patch.

PATCH In review Rusty Russell 3 participants 5 messages Sep 29, 2003 – Oct 1, 2003

Subsystems (10)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Many groups patch.

As stated before, SAMBA customers want > 200 groups. Special thanks to Tim Hockin for feedback based on his patch.

This version drops the internal groups array (it's so often shared that it's not worth it, and the logic becomes a bit neater), and does vmalloc fallback in case someone has massive number of groups.

Rusty.
--
Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

Name: Dynamic Allocation of Groups Array When Required: With Refcounting
Author: Rusty Russell
Status: Tested on 2.6.0-test6
Depends: Misc/qemu-page-offset.patch.gz

D: This patch allows the maximum number of groups to be varied using
D: sysctl. Since sharing is so common, we use a refcounted external
D: array for groups.
D:

D: Changes:
D: 1) Remove the NGROUPS define from archs.
D: 2) Fixup the few places which declare [NGROUPS] arrays on the stack.
D: 3) The ia64, s390 and sparc64 ports have their own setgroups/getgroups
D:    implementations: unify them on the ia64 one, which calls the core
D:    functions.
D: 4) Change the task_struct's groups to a pointer to inside a refcounted
D:    external array, fix up fork() to inc refcount.
D: 5) Introduce max_groups and use it instead of NGROUPS.
D: 6) Add a sysctl to vary max_groups.

D:
D: This patch scars nfs: artificially restrict the groups there to
D: SVC_CRED_NGROUPS (32), which is probably wrong, but won't break if
D: they don't change the default.
D:
D: This patch breaks intermezzo: I'm not sure how they want to deal
D: with it.

arch/ia64/ia32/sys_ia32.c +20 -7
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/arch/ia64/ia32/sys_ia32.c .12070-2.6.0-test6-more_groups_refcount/arch/ia64/ia32/sys_ia32.c
@@ -2432,17 +2432,24 @@ asmlinkage long
 sys32_getgroups16 (int gidsetsize, short *grouplist)
 {
 	mm_segment_t old_fs = get_fs();
-	gid_t gl[NGROUPS];
+	gid_t *gl;
 	int ret, i;
 
+	gl = kmalloc(sizeof(gl[0]) * current->ngroups, GFP_KERNEL);
+	if (!gl)
+		return -ENOMEM;
+
 	set_fs(KERNEL_DS);
 	ret = sys_getgroups(gidsetsize, gl);
 	set_fs(old_fs);
 
-	if (gidsetsize && ret > 0 && ret <= NGROUPS)
+	if (gidsetsize && ret > 0)
 		for (i = 0; i < ret; i++, grouplist++)
-			if (put_user(gl[i], grouplist))
-				return -EFAULT;
+			if (put_user(gl[i], grouplist)) {
+				ret = -EFAULT;
+				break;
+			}
+	kfree(gl);
 	return ret;
 }
 
@@ -2452,17 +2459,23 @@ asmlinkage long
 sys32_setgroups16 (int gidsetsize, short *grouplist)
 {
 	mm_segment_t old_fs = get_fs();
-	gid_t gl[NGROUPS];
+	gid_t *gl;
 	int ret, i;
 
-	if ((unsigned) gidsetsize > NGROUPS)
+	if ((unsigned) gidsetsize > max_groups)
 		return -EINVAL;
+	gl = kmalloc(sizeof(gl[0]) * gidsetsize, GFP_KERNEL);
+	if (!gl)
+		return -ENOMEM;
 	for (i = 0; i < gidsetsize; i++, grouplist++)
-		if (get_user(gl[i], grouplist))
+		if (get_user(gl[i], grouplist)) {
+			kfree(gl);
 			return -EFAULT;
+		}
 	set_fs(KERNEL_DS);
 	ret = sys_setgroups(gidsetsize, gl);
 	set_fs(old_fs);
+	kfree(gl);
 	return ret;
 }
 
arch/mips/kernel/sysirix.c +1 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/arch/mips/kernel/sysirix.c .12070-2.6.0-test6-more_groups_refcount/arch/mips/kernel/sysirix.c
@@ -368,7 +368,7 @@ asmlinkage int irix_syssgi(struct pt_reg
 			retval = HZ;
 			goto out;
 		case 4:
-			retval = NGROUPS;
+			retval = max_groups;
 			goto out;
 		case 5:
 			retval = NR_OPEN;
arch/s390/kernel/compat_linux.c +44 -27

84 lines not on this page · raw message

arch/sparc/kernel/sys_sunos.c +1 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/arch/sparc/kernel/sys_sunos.c .12070-2.6.0-test6-more_groups_refcount/arch/sparc/kernel/sys_sunos.c
@@ -896,7 +896,7 @@ extern asmlinkage long sunos_sysconf (in
 		ret = HZ;
 		break;
 	case _SC_NGROUPS_MAX:
-		ret = NGROUPS_MAX;
+		ret = max_groups;
 		break;
 	case _SC_OPEN_MAX:
 		ret = OPEN_MAX;
arch/sparc64/kernel/sys_sparc32.c +44 -27

84 lines not on this page · raw message

arch/sparc64/kernel/sys_sunos32.c +1 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/arch/sparc64/kernel/sys_sunos32.c .12070-2.6.0-test6-more_groups_refcount/arch/sparc64/kernel/sys_sunos32.c
@@ -859,7 +859,7 @@ extern asmlinkage s32 sunos_sysconf (int
 		ret = HZ;
 		break;
 	case _SC_NGROUPS_MAX:
-		ret = NGROUPS_MAX;
+		ret = max_groups;
 		break;
 	case _SC_OPEN_MAX:
 		ret = OPEN_MAX;
fs/nfsd/auth.c +4 -2
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/fs/nfsd/auth.c .12070-2.6.0-test6-more_groups_refcount/fs/nfsd/auth.c
@@ -26,7 +26,7 @@ nfsd_setuser(struct svc_rqst *rqstp, str
 			cred->cr_uid = exp->ex_anon_uid;
 		if (!cred->cr_gid)
 			cred->cr_gid = exp->ex_anon_gid;
-		for (i = 0; i < NGROUPS; i++)
+		for (i = 0; i < SVC_CRED_NGROUPS; i++)
 			if (!cred->cr_groups[i])
 				cred->cr_groups[i] = exp->ex_anon_gid;
 	}
@@ -39,7 +39,9 @@ nfsd_setuser(struct svc_rqst *rqstp, str
 		current->fsgid = cred->cr_gid;
 	else
 		current->fsgid = exp->ex_anon_gid;
-	for (i = 0; i < NGROUPS; i++) {
+
+	/* We can do this because cow_current_groups() was done at birth. */
+	for (i = 0; i < SVC_CRED_NGROUPS; i++) {
 		gid_t group = cred->cr_groups[i];
 		if (group == (gid_t) NOGROUP)
 			break;
fs/nfsd/nfs4state.c +1 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/fs/nfsd/nfs4state.c .12070-2.6.0-test6-more_groups_refcount/fs/nfsd/nfs4state.c
@@ -244,7 +244,7 @@ copy_cred(struct svc_cred *target, struc
 
 	target->cr_uid = source->cr_uid;
 	target->cr_gid = source->cr_gid;
-	for(i = 0; i < NGROUPS; i++)
+	for(i = 0; i < SVC_CREDS_NGROUPS; i++)
 		target->cr_groups[i] = source->cr_groups[i];
 }
 
fs/nfsd/nfssvc.c +5 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/fs/nfsd/nfssvc.c .12070-2.6.0-test6-more_groups_refcount/fs/nfsd/nfssvc.c
@@ -182,6 +182,11 @@ nfsd(struct svc_rqst *rqstp)
 	daemonize("nfsd");
 	current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
 
+	if (cow_current_groups(SVC_CRED_NGROUPS) < 0) {
+		printk("Unable to start nfsd thread: can't set groups\n");
+		goto out;
+	}
+
 	/* After daemonize() this kernel thread shares current->fs
 	 * with the init process. We need to create files with a
 	 * umask of 0 instead of init's umask. */
include/asm-alpha/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-alpha/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-alpha/param.h
@@ -19,10 +19,6 @@
 
 #define EXEC_PAGESIZE	8192
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-arm/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-arm/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-arm/param.h
@@ -26,10 +26,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS         32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP         (-1)
 #endif
include/asm-arm26/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-arm26/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-arm26/param.h
@@ -22,10 +22,6 @@
 # define HZ		100
 #endif
 
-#ifndef NGROUPS
-#define NGROUPS         32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP         (-1)
 #endif
include/asm-cris/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-cris/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-cris/param.h
@@ -14,10 +14,6 @@
 
 #define EXEC_PAGESIZE	8192
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-h8300/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-h8300/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-h8300/param.h
@@ -14,10 +14,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-i386/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-i386/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-i386/param.h
@@ -18,10 +18,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-ia64/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-ia64/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-ia64/param.h
@@ -10,10 +10,6 @@
 
 #define EXEC_PAGESIZE	65536
 
-#ifndef NGROUPS
-# define NGROUPS	32
-#endif
-
 #ifndef NOGROUP
 # define NOGROUP	(-1)
 #endif
include/asm-m68k/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-m68k/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-m68k/param.h
@@ -13,10 +13,6 @@
 
 #define EXEC_PAGESIZE	8192
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-m68knommu/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-m68knommu/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-m68knommu/param.h
@@ -44,10 +44,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-mips/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-mips/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-mips/param.h
@@ -33,10 +33,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-parisc/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-parisc/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-parisc/param.h
@@ -17,10 +17,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-ppc/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-ppc/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-ppc/param.h
@@ -13,10 +13,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-ppc64/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-ppc64/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-ppc64/param.h
@@ -20,10 +20,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-s390/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-s390/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-s390/param.h
@@ -21,10 +21,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-sh/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-sh/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-sh/param.h
@@ -17,10 +17,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-sparc/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-sparc/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-sparc/param.h
@@ -14,10 +14,6 @@
 
 #define EXEC_PAGESIZE	8192    /* Thanks for sun4's we carry baggage... */
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-sparc64/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-sparc64/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-sparc64/param.h
@@ -14,10 +14,6 @@
 
 #define EXEC_PAGESIZE	8192    /* Thanks for sun4's we carry baggage... */
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-um/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-um/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-um/param.h
@@ -3,10 +3,6 @@
 
 #define EXEC_PAGESIZE   4096
 
-#ifndef NGROUPS
-#define NGROUPS         32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP         (-1)
 #endif
include/asm-v850/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-v850/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-v850/param.h
@@ -18,10 +18,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-x86_64/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-x86_64/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-x86_64/param.h
@@ -13,10 +13,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/linux/init_task.h +3 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/linux/init_task.h .12070-2.6.0-test6-more_groups_refcount/include/linux/init_task.h
@@ -56,6 +56,8 @@
 	.siglock	= SPIN_LOCK_UNLOCKED, 		\
 }
 
+extern struct task_groups init_groups;
+
 /*
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -108,6 +110,7 @@
 	.proc_lock	= SPIN_LOCK_UNLOCKED,				\
 	.switch_lock	= SPIN_LOCK_UNLOCKED,				\
 	.journal_info	= NULL,						\
+	.groups		= init_groups.groups,				\
 }
 
 
include/linux/sched.h +21 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/linux/sched.h .12070-2.6.0-test6-more_groups_refcount/include/linux/sched.h
@@ -328,6 +328,16 @@ struct k_itimer {
 struct io_context;			/* See blkdev.h */
 void exit_io_context(void);
 
+/* Size is determined by task_struct's ngroups. */
+struct task_groups
+{
+	atomic_t usage;
+	void (*free)(const void *);
+	gid_t groups[0];
+};
+
+extern int max_groups;
+
 struct task_struct {
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
 	struct thread_info *thread_info;
@@ -403,7 +413,7 @@ struct task_struct {
 	uid_t uid,euid,suid,fsuid;
 	gid_t gid,egid,sgid,fsgid;
 	int ngroups;
-	gid_t	groups[NGROUPS];
+	gid_t *groups; /* task_groups->groups */
 	kernel_cap_t   cap_effective, cap_inheritable, cap_permitted;
 	int keep_capabilities:1;
 	struct user_struct *user;
@@ -602,6 +612,12 @@ extern int send_group_sigqueue(int, stru
 extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *);
 extern int do_sigaltstack(const stack_t __user *, stack_t __user *, unsigned long);
 
+/* container_of doesn't like arrays. */
+static inline struct task_groups *task_groups(gid_t *groups)
+{
+	return (void *)groups - offsetof(struct task_groups, groups);
+}
+
 /* These can be the second arg to send_sig_info/send_group_sig_info.  */
 #define SEND_SIG_NOINFO ((struct siginfo *) 0)
 #define SEND_SIG_PRIV	((struct siginfo *) 1)
@@ -678,6 +694,10 @@ extern int do_execve(char *, char __user
 extern long do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *);
 extern struct task_struct * copy_process(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *);
 
+/* Copy-on-write current groups to this size, if possible.  0 or -err. */
+extern int cow_current_groups(unsigned int ngroups);
+extern void release_groups(gid_t *groups);
+
 #ifdef CONFIG_SMP
 extern void wait_task_inactive(task_t * p);
 #else
include/linux/sunrpc/svcauth.h +3 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/linux/sunrpc/svcauth.h .12070-2.6.0-test6-more_groups_refcount/include/linux/sunrpc/svcauth.h
@@ -16,10 +16,12 @@
 #include <linux/sunrpc/cache.h>
 #include <linux/hash.h>
 
+#define SVC_CRED_NGROUPS	32
+
 struct svc_cred {
 	uid_t			cr_uid;
 	gid_t			cr_gid;
-	gid_t			cr_groups[NGROUPS];
+	gid_t			cr_groups[SVC_CRED_NGROUPS];
 };
 
 struct svc_rqst;		/* forward decl */
include/linux/sysctl.h +1 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/linux/sysctl.h .12070-2.6.0-test6-more_groups_refcount/include/linux/sysctl.h
@@ -127,6 +127,7 @@ enum
 	KERN_PANIC_ON_OOPS=57,  /* int: whether we will panic on an oops */
 	KERN_HPPA_PWRSW=58,	/* int: hppa soft-power enable */
 	KERN_HPPA_UNALIGNED=59,	/* int: hppa unaligned-trap enable */
+	KERN_MAX_GROUPS=60,	/* int: setgroups limit */
 };
 
 
init/main.c +0 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/init/main.c .12070-2.6.0-test6-more_groups_refcount/init/main.c
@@ -594,7 +594,6 @@ static int init(void * unused)
 	 * The Bourne shell can be used instead of init if we are 
 	 * trying to recover a really broken machine.
 	 */
-
 	if (execute_command)
 		run_init_process(execute_command);
 
kernel/fork.c +3 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/kernel/fork.c .12070-2.6.0-test6-more_groups_refcount/kernel/fork.c
@@ -85,6 +85,7 @@ void __put_task_struct(struct task_struc
 
 	security_task_free(tsk);
 	free_uid(tsk->user);
+	release_groups(tsk->groups);
 	free_task(tsk);
 }
 
@@ -817,6 +818,7 @@ struct task_struct *copy_process(unsigne
 
 	atomic_inc(&p->user->__count);
 	atomic_inc(&p->user->processes);
+	atomic_inc(&task_groups(p->groups)->usage);
 
 	/*
 	 * If multiple threads are within copy_process(), then this check
@@ -1063,6 +1065,7 @@ bad_fork_cleanup_put_domain:
 bad_fork_cleanup_count:
 	atomic_dec(&p->user->processes);
 	free_uid(p->user);
+	release_groups(p->groups);
 bad_fork_free:
 	free_task(p);
 	goto fork_out;
kernel/sys.c +74 -8

113 lines not on this page · raw message

kernel/sysctl.c +8 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/kernel/sysctl.c .12070-2.6.0-test6-more_groups_refcount/kernel/sysctl.c
@@ -581,6 +581,14 @@ static ctl_table kern_table[] = {
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec,
 	},
+	{
+		.ctl_name	= KERN_MAX_GROUPS,
+		.procname	= "max_groups",
+		.data		= &max_groups,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
 	{ .ctl_name = 0 }
 };
 
kernel/uid16.c +27 -14

68 lines not on this page · raw message

net/sunrpc/svcauth_unix.c +2 -2
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/net/sunrpc/svcauth_unix.c .12070-2.6.0-test6-more_groups_refcount/net/sunrpc/svcauth_unix.c
@@ -434,11 +434,11 @@ svcauth_unix_accept(struct svc_rqst *rqs
 	if (slen > 16 || (len -= (slen + 2)*4) < 0)
 		goto badcred;
 	for (i = 0; i < slen; i++)
-		if (i < NGROUPS)
+		if (i < SVC_CRED_NGROUPS)
 			cred->cr_groups[i] = ntohl(svc_getu32(argv));
 		else
 			svc_getu32(argv);
-	if (i < NGROUPS)
+	if (i < SVC_CRED_NGROUPS)
 		cred->cr_groups[i] = NOGROUP;
 
 	if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
#1 lore raw
Quoted 4 lines · Rusty Russell

This version drops the internal groups array (it's so often shared that it's not worth it, and the logic becomes a bit neater), and does vmalloc fallback in case someone has massive number of groups.

Why?

kmalloc() works fine. Anybody who needs 200 groups may be sane, but anybody who needs more than fits in a kmalloc() is definitely so far out that there is no point.

The vmalloc space is limited, and the code just gets uglier.

Have you been looking at glibc sources lately, or why do you believe that we should encourage insane usage?

Linus

#2 lore raw

In message <[email protected]> you write:

Quoted 8 lines · Rusty Russell
Quoted 4 lines

This version drops the internal groups array (it's so often shared that it's not worth it, and the logic becomes a bit neater), and does vmalloc fallback in case someone has massive number of groups.

Why?

(Rusty points at Tim).

He has 10,000 groups. Now me, I'm happy with the minimal fix.

Quoted 3 lines

kmalloc() works fine. Anybody who needs 200 groups may be sane, but anybody who needs more than fits in a kmalloc() is definitely so far out that there is no point.

And worse, there are the intermediate kmallocs which would need to be fixed (thanks to Stephen Rothwell for pointing this out). Fixing this would make it even uglier.

Here's an updated one (with David Meybohm's fix, too -- Thanks!), Rusty.
--
Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

Name: Dynamic Allocation of Groups Array When Required: With Refcounting
Author: Rusty Russell
Status: Booted on 2.6.0-test6-bk1
Depends: Misc/qemu-page-offset.patch.gz

D: This patch allows the maximum number of groups to be varied using
D: sysctl. Since sharing is so common, we use a refcounted external
D: array for groups.
D:

D: Changes:
D: 1) Remove the NGROUPS define from archs.
D: 2) Fixup the few places which declare [NGROUPS] arrays on the stack.
D: 3) The ia64, s390 and sparc64 ports have their own setgroups/getgroups
D:    implementations: unify them on the ia64 one, which calls the core
D:    functions.
D: 4) Change the task_struct's groups to a pointer to inside a refcounted
D:    external array, fix up fork() to inc refcount.
D: 5) Introduce max_groups and use it instead of NGROUPS.
D: 6) Add a sysctl to vary max_groups.

D:
D: This patch scars nfs: artificially restrict the groups there to
D: SVC_CRED_NGROUPS (32), which is probably wrong, but won't break if
D: they don't change the default.
D:
D: This patch breaks intermezzo: I'm not sure how they want to deal
D: with it.

arch/ia64/ia32/sys_ia32.c +20 -7
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/arch/ia64/ia32/sys_ia32.c .12070-2.6.0-test6-more_groups_refcount/arch/ia64/ia32/sys_ia32.c
@@ -2432,17 +2432,24 @@ asmlinkage long
 sys32_getgroups16 (int gidsetsize, short *grouplist)
 {
 	mm_segment_t old_fs = get_fs();
-	gid_t gl[NGROUPS];
+	gid_t *gl;
 	int ret, i;
 
+	gl = kmalloc(sizeof(gl[0]) * current->ngroups, GFP_KERNEL);
+	if (!gl)
+		return -ENOMEM;
+
 	set_fs(KERNEL_DS);
 	ret = sys_getgroups(gidsetsize, gl);
 	set_fs(old_fs);
 
-	if (gidsetsize && ret > 0 && ret <= NGROUPS)
+	if (gidsetsize && ret > 0)
 		for (i = 0; i < ret; i++, grouplist++)
-			if (put_user(gl[i], grouplist))
-				return -EFAULT;
+			if (put_user(gl[i], grouplist)) {
+				ret = -EFAULT;
+				break;
+			}
+	kfree(gl);
 	return ret;
 }
 
@@ -2452,17 +2459,23 @@ asmlinkage long
 sys32_setgroups16 (int gidsetsize, short *grouplist)
 {
 	mm_segment_t old_fs = get_fs();
-	gid_t gl[NGROUPS];
+	gid_t *gl;
 	int ret, i;
 
-	if ((unsigned) gidsetsize > NGROUPS)
+	if ((unsigned) gidsetsize > max_groups)
 		return -EINVAL;
+	gl = kmalloc(sizeof(gl[0]) * gidsetsize, GFP_KERNEL);
+	if (!gl)
+		return -ENOMEM;
 	for (i = 0; i < gidsetsize; i++, grouplist++)
-		if (get_user(gl[i], grouplist))
+		if (get_user(gl[i], grouplist)) {
+			kfree(gl);
 			return -EFAULT;
+		}
 	set_fs(KERNEL_DS);
 	ret = sys_setgroups(gidsetsize, gl);
 	set_fs(old_fs);
+	kfree(gl);
 	return ret;
 }
 
arch/mips/kernel/sysirix.c +1 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/arch/mips/kernel/sysirix.c .12070-2.6.0-test6-more_groups_refcount/arch/mips/kernel/sysirix.c
@@ -368,7 +368,7 @@ asmlinkage int irix_syssgi(struct pt_reg
 			retval = HZ;
 			goto out;
 		case 4:
-			retval = NGROUPS;
+			retval = max_groups;
 			goto out;
 		case 5:
 			retval = NR_OPEN;
arch/s390/kernel/compat_linux.c +44 -27

84 lines not on this page · raw message

arch/sparc/kernel/sys_sunos.c +1 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/arch/sparc/kernel/sys_sunos.c .12070-2.6.0-test6-more_groups_refcount/arch/sparc/kernel/sys_sunos.c
@@ -896,7 +896,7 @@ extern asmlinkage long sunos_sysconf (in
 		ret = HZ;
 		break;
 	case _SC_NGROUPS_MAX:
-		ret = NGROUPS_MAX;
+		ret = max_groups;
 		break;
 	case _SC_OPEN_MAX:
 		ret = OPEN_MAX;
arch/sparc64/kernel/sys_sparc32.c +44 -27

84 lines not on this page · raw message

arch/sparc64/kernel/sys_sunos32.c +1 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/arch/sparc64/kernel/sys_sunos32.c .12070-2.6.0-test6-more_groups_refcount/arch/sparc64/kernel/sys_sunos32.c
@@ -859,7 +859,7 @@ extern asmlinkage s32 sunos_sysconf (int
 		ret = HZ;
 		break;
 	case _SC_NGROUPS_MAX:
-		ret = NGROUPS_MAX;
+		ret = max_groups;
 		break;
 	case _SC_OPEN_MAX:
 		ret = OPEN_MAX;
fs/nfsd/auth.c +4 -2
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/fs/nfsd/auth.c .12070-2.6.0-test6-more_groups_refcount/fs/nfsd/auth.c
@@ -26,7 +26,7 @@ nfsd_setuser(struct svc_rqst *rqstp, str
 			cred->cr_uid = exp->ex_anon_uid;
 		if (!cred->cr_gid)
 			cred->cr_gid = exp->ex_anon_gid;
-		for (i = 0; i < NGROUPS; i++)
+		for (i = 0; i < SVC_CRED_NGROUPS; i++)
 			if (!cred->cr_groups[i])
 				cred->cr_groups[i] = exp->ex_anon_gid;
 	}
@@ -39,7 +39,9 @@ nfsd_setuser(struct svc_rqst *rqstp, str
 		current->fsgid = cred->cr_gid;
 	else
 		current->fsgid = exp->ex_anon_gid;
-	for (i = 0; i < NGROUPS; i++) {
+
+	/* We can do this because cow_current_groups() was done at birth. */
+	for (i = 0; i < SVC_CRED_NGROUPS; i++) {
 		gid_t group = cred->cr_groups[i];
 		if (group == (gid_t) NOGROUP)
 			break;
fs/nfsd/nfs4state.c +1 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/fs/nfsd/nfs4state.c .12070-2.6.0-test6-more_groups_refcount/fs/nfsd/nfs4state.c
@@ -244,7 +244,7 @@ copy_cred(struct svc_cred *target, struc
 
 	target->cr_uid = source->cr_uid;
 	target->cr_gid = source->cr_gid;
-	for(i = 0; i < NGROUPS; i++)
+	for(i = 0; i < SVC_CREDS_NGROUPS; i++)
 		target->cr_groups[i] = source->cr_groups[i];
 }
 
fs/nfsd/nfssvc.c +5 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/fs/nfsd/nfssvc.c .12070-2.6.0-test6-more_groups_refcount/fs/nfsd/nfssvc.c
@@ -182,6 +182,11 @@ nfsd(struct svc_rqst *rqstp)
 	daemonize("nfsd");
 	current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
 
+	if (cow_current_groups(SVC_CRED_NGROUPS) < 0) {
+		printk("Unable to start nfsd thread: can't set groups\n");
+		goto out;
+	}
+
 	/* After daemonize() this kernel thread shares current->fs
 	 * with the init process. We need to create files with a
 	 * umask of 0 instead of init's umask. */
include/asm-alpha/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-alpha/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-alpha/param.h
@@ -19,10 +19,6 @@
 
 #define EXEC_PAGESIZE	8192
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-arm/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-arm/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-arm/param.h
@@ -26,10 +26,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS         32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP         (-1)
 #endif
include/asm-arm26/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-arm26/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-arm26/param.h
@@ -22,10 +22,6 @@
 # define HZ		100
 #endif
 
-#ifndef NGROUPS
-#define NGROUPS         32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP         (-1)
 #endif
include/asm-cris/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-cris/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-cris/param.h
@@ -14,10 +14,6 @@
 
 #define EXEC_PAGESIZE	8192
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-h8300/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-h8300/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-h8300/param.h
@@ -14,10 +14,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-i386/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-i386/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-i386/param.h
@@ -18,10 +18,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-ia64/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-ia64/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-ia64/param.h
@@ -10,10 +10,6 @@
 
 #define EXEC_PAGESIZE	65536
 
-#ifndef NGROUPS
-# define NGROUPS	32
-#endif
-
 #ifndef NOGROUP
 # define NOGROUP	(-1)
 #endif
include/asm-m68k/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-m68k/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-m68k/param.h
@@ -13,10 +13,6 @@
 
 #define EXEC_PAGESIZE	8192
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-m68knommu/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-m68knommu/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-m68knommu/param.h
@@ -44,10 +44,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-mips/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-mips/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-mips/param.h
@@ -33,10 +33,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-parisc/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-parisc/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-parisc/param.h
@@ -17,10 +17,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-ppc/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-ppc/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-ppc/param.h
@@ -13,10 +13,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-ppc64/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-ppc64/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-ppc64/param.h
@@ -20,10 +20,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-s390/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-s390/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-s390/param.h
@@ -21,10 +21,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-sh/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-sh/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-sh/param.h
@@ -17,10 +17,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-sparc/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-sparc/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-sparc/param.h
@@ -14,10 +14,6 @@
 
 #define EXEC_PAGESIZE	8192    /* Thanks for sun4's we carry baggage... */
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-sparc64/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-sparc64/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-sparc64/param.h
@@ -14,10 +14,6 @@
 
 #define EXEC_PAGESIZE	8192    /* Thanks for sun4's we carry baggage... */
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-um/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-um/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-um/param.h
@@ -3,10 +3,6 @@
 
 #define EXEC_PAGESIZE   4096
 
-#ifndef NGROUPS
-#define NGROUPS         32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP         (-1)
 #endif
include/asm-v850/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-v850/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-v850/param.h
@@ -18,10 +18,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/asm-x86_64/param.h +0 -4
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/asm-x86_64/param.h .12070-2.6.0-test6-more_groups_refcount/include/asm-x86_64/param.h
@@ -13,10 +13,6 @@
 
 #define EXEC_PAGESIZE	4096
 
-#ifndef NGROUPS
-#define NGROUPS		32
-#endif
-
 #ifndef NOGROUP
 #define NOGROUP		(-1)
 #endif
include/linux/init_task.h +3 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/linux/init_task.h .12070-2.6.0-test6-more_groups_refcount/include/linux/init_task.h
@@ -56,6 +56,8 @@
 	.siglock	= SPIN_LOCK_UNLOCKED, 		\
 }
 
+extern struct task_groups init_groups;
+
 /*
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -108,6 +110,7 @@
 	.proc_lock	= SPIN_LOCK_UNLOCKED,				\
 	.switch_lock	= SPIN_LOCK_UNLOCKED,				\
 	.journal_info	= NULL,						\
+	.groups		= init_groups.groups,				\
 }
 
 
include/linux/sched.h +20 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/linux/sched.h .12070-2.6.0-test6-more_groups_refcount/include/linux/sched.h
@@ -328,6 +328,15 @@ struct k_itimer {
 struct io_context;			/* See blkdev.h */
 void exit_io_context(void);
 
+/* Size is determined by task_struct's ngroups. */
+struct task_groups
+{
+	atomic_t usage;
+	gid_t groups[0];
+};
+
+extern int max_groups;
+
 struct task_struct {
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
 	struct thread_info *thread_info;
@@ -403,7 +413,7 @@ struct task_struct {
 	uid_t uid,euid,suid,fsuid;
 	gid_t gid,egid,sgid,fsgid;
 	int ngroups;
-	gid_t	groups[NGROUPS];
+	gid_t *groups; /* task_groups->groups */
 	kernel_cap_t   cap_effective, cap_inheritable, cap_permitted;
 	int keep_capabilities:1;
 	struct user_struct *user;
@@ -602,6 +612,12 @@ extern int send_group_sigqueue(int, stru
 extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *);
 extern int do_sigaltstack(const stack_t __user *, stack_t __user *, unsigned long);
 
+/* container_of doesn't like arrays. */
+static inline struct task_groups *task_groups(gid_t *groups)
+{
+	return (void *)groups - offsetof(struct task_groups, groups);
+}
+
 /* These can be the second arg to send_sig_info/send_group_sig_info.  */
 #define SEND_SIG_NOINFO ((struct siginfo *) 0)
 #define SEND_SIG_PRIV	((struct siginfo *) 1)
@@ -678,6 +694,10 @@ extern int do_execve(char *, char __user
 extern long do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *);
 extern struct task_struct * copy_process(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *);
 
+/* Copy-on-write current groups to this size, if possible.  0 or -err. */
+extern int cow_current_groups(unsigned int ngroups);
+extern void release_groups(gid_t *groups);
+
 #ifdef CONFIG_SMP
 extern void wait_task_inactive(task_t * p);
 #else
include/linux/sunrpc/svcauth.h +3 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/linux/sunrpc/svcauth.h .12070-2.6.0-test6-more_groups_refcount/include/linux/sunrpc/svcauth.h
@@ -16,10 +16,12 @@
 #include <linux/sunrpc/cache.h>
 #include <linux/hash.h>
 
+#define SVC_CRED_NGROUPS	32
+
 struct svc_cred {
 	uid_t			cr_uid;
 	gid_t			cr_gid;
-	gid_t			cr_groups[NGROUPS];
+	gid_t			cr_groups[SVC_CRED_NGROUPS];
 };
 
 struct svc_rqst;		/* forward decl */
include/linux/sysctl.h +1 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/include/linux/sysctl.h .12070-2.6.0-test6-more_groups_refcount/include/linux/sysctl.h
@@ -127,6 +127,7 @@ enum
 	KERN_PANIC_ON_OOPS=57,  /* int: whether we will panic on an oops */
 	KERN_HPPA_PWRSW=58,	/* int: hppa soft-power enable */
 	KERN_HPPA_UNALIGNED=59,	/* int: hppa unaligned-trap enable */
+	KERN_MAX_GROUPS=60,	/* int: setgroups limit */
 };
 
 
init/main.c +0 -1
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/init/main.c .12070-2.6.0-test6-more_groups_refcount/init/main.c
@@ -594,7 +594,6 @@ static int init(void * unused)
 	 * The Bourne shell can be used instead of init if we are 
 	 * trying to recover a really broken machine.
 	 */
-
 	if (execute_command)
 		run_init_process(execute_command);
 
kernel/fork.c +3 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/kernel/fork.c .12070-2.6.0-test6-more_groups_refcount/kernel/fork.c
@@ -85,6 +85,7 @@ void __put_task_struct(struct task_struc
 
 	security_task_free(tsk);
 	free_uid(tsk->user);
+	release_groups(tsk->groups);
 	free_task(tsk);
 }
 
@@ -817,6 +818,7 @@ struct task_struct *copy_process(unsigne
 
 	atomic_inc(&p->user->__count);
 	atomic_inc(&p->user->processes);
+	atomic_inc(&task_groups(p->groups)->usage);
 
 	/*
 	 * If multiple threads are within copy_process(), then this check
@@ -1063,6 +1065,7 @@ bad_fork_cleanup_put_domain:
 bad_fork_cleanup_count:
 	atomic_dec(&p->user->processes);
 	free_uid(p->user);
+	release_groups(p->groups);
 bad_fork_free:
 	free_task(p);
 	goto fork_out;
kernel/sys.c +68 -8

107 lines not on this page · raw message

kernel/sysctl.c +8 -0
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/kernel/sysctl.c .12070-2.6.0-test6-more_groups_refcount/kernel/sysctl.c
@@ -581,6 +581,14 @@ static ctl_table kern_table[] = {
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec,
 	},
+	{
+		.ctl_name	= KERN_MAX_GROUPS,
+		.procname	= "max_groups",
+		.data		= &max_groups,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
 	{ .ctl_name = 0 }
 };
 
kernel/uid16.c +27 -14

68 lines not on this page · raw message

net/sunrpc/svcauth_unix.c +2 -2
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12070-2.6.0-test6-more_groups_refcount.pre/net/sunrpc/svcauth_unix.c .12070-2.6.0-test6-more_groups_refcount/net/sunrpc/svcauth_unix.c
@@ -434,11 +434,11 @@ svcauth_unix_accept(struct svc_rqst *rqs
 	if (slen > 16 || (len -= (slen + 2)*4) < 0)
 		goto badcred;
 	for (i = 0; i < slen; i++)
-		if (i < NGROUPS)
+		if (i < SVC_CRED_NGROUPS)
 			cred->cr_groups[i] = ntohl(svc_getu32(argv));
 		else
 			svc_getu32(argv);
-	if (i < NGROUPS)
+	if (i < SVC_CRED_NGROUPS)
 		cred->cr_groups[i] = NOGROUP;
 
 	if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
#3 lore raw
Quoted 5 lines · Rusty Russell
Quoted 1 line

Why?

(Rusty points at Tim).

He has 10,000 groups. Now me, I'm happy with the minimal fix.

I'm going to merge your thoughts and mine tomorrow and send it out. Linus suggested the array of pages approah is more sane, so I'm going to try for it. I'm going to comb through the diffs between your patch and mine.

Quoted 3 lines

And worse, there are the intermediate kmallocs which would need to be fixed (thanks to Stephen Rothwell for pointing this out). Fixing this would make it even uglier.

Specifically? I think my patch gets all of those. At least all the ones I found.

Quoted 2 lines

Here's an updated one (with David Meybohm's fix, too -- Thanks!), Rusty.

Can you elaborate on what this extra fix is?

#4 lore raw

In message <[email protected]> you write:

Quoted 10 lines · Rusty Russell
Quoted 5 lines
Quoted 1 line

Why?

(Rusty points at Tim).

He has 10,000 groups. Now me, I'm happy with the minimal fix.

I'm going to merge your thoughts and mine tomorrow and send it out. Linus suggested the array of pages approah is more sane, so I'm going to try for it. I'm going to comb through the diffs between your patch and mine.

Keeping the groups array as an array is a feature. IMHO, if there are too many for a kmalloc, vmalloc fallback makes sense: it's conceptually simple and not that much code.

Introducing an almost-vmalloc because Linus didn't like the vmalloc just doesn't make sense, IMHO.

Quoted 6 lines
Quoted 3 lines

And worse, there are the intermediate kmallocs which would need to be fixed (thanks to Stephen Rothwell for pointing this out). Fixing this would make it even uglier.

Specifically? I think my patch gets all of those. At least all the ones I found.

Yep, you got them, I didn't. I am still hoping Stephen (CC'd) will move the IA64, S390 and Sparc64 code into kernel/compat.c which will shrink out patches.

Quoted 4 lines
Quoted 2 lines

Here's an updated one (with David Meybohm's fix, too -- Thanks!), Rusty.

Can you elaborate on what this extra fix is?

I screwed up a free.

Cheers,
Rusty.
--
Anyone who quotes me in their sig is an idiot. -- Rusty Russell.