Skip to contentSkip to conversation

shared credentials with vfs snapshotting

RFC David C. Hansen 1 participant 2 messages Oct 24, 2002

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

This patch combines the ideas from two others: Dave McCracken's combination of task credentials into a single structure which is shared between threads:
http://marc.theaimsgroup.com/?t=102830918300009&r=1&w=2
And Trond Myklebust's snapshotting of the vfs-specific parts of the cred structure which are passed down into vfs and are strictly copy-on-write.
http://marc.theaimsgroup.com/?t=103081191900001&r=1&w=2
http://marc.theaimsgroup.com/?t=103074984200004&r=1&w=2
http://www.fys.uio.no/~trondmy/src/2.5.32-alpha

Implementing the appearance of shared credentials to userspace requires large amounts of code to be added in the threading libraries. The addition of code here is reasonalbly small.

This patch is by no means complete or correct. It completely ignores the credential sharing flag for now. It is just here to demonstrate the combination of the two ideas. Please don't go applying it to anything ;)

I think that the core of what is needed is in the attached patch. Most of what is left can be accomplished with s/->uid/->cred->uid/ and s/->fsuid/->cred->vfscred->uid/

And, as Trond says:

Quoted 5 lines

Unfortunately there's still a bit more to do. I need to get the file creation ops (i_op->create()/symlink()/mknod()/mkdir()) to take a vfs_cred* argument. If not, you risk having the inode->i_uid/i_gid set to values that differ from the ones checked by the calls to ->permission().

Signature · 2 lines
Dave Hansen
[email protected]
#1 lore raw

Oh yeah, the code!

Signature · 2 lines
Dave Hansen
[email protected]
arch/i386/kernel/init_task.c +1 -0
diff -X exclude -urN linux-2.5.44/arch/i386/kernel/init_task.c linux-2.5.44-cred/arch/i386/kernel/init_task.c
@@ -11,6 +11,7 @@
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct cred_struct init_cred = INIT_CRED;
 struct mm_struct init_mm = INIT_MM(init_mm);
 
 /*
arch/s390x/kernel/linux32.c +2 -7
diff -X exclude -urN linux-2.5.44/arch/s390x/kernel/linux32.c linux-2.5.44-cred/arch/s390x/kernel/linux32.c
@@ -194,12 +194,10 @@
 
 	if (gidsetsize < 0)
 		return -EINVAL;
-	i = current->ngroups;
+	i = getgroups16(NGROUPS, groups);
 	if (gidsetsize) {
 		if (i > gidsetsize)
 			return -EINVAL;
-		for(j=0;j<i;j++)
-			groups[j] = current->groups[j];
 		if (copy_to_user(grouplist, groups, sizeof(u16)*i))
 			return -EFAULT;
 	}
@@ -217,10 +215,7 @@
 		return -EINVAL;
 	if (copy_from_user(groups, grouplist, gidsetsize * sizeof(u16)))
 		return -EFAULT;
-	for (i = 0 ; i < gidsetsize ; i++)
-		current->groups[i] = (gid_t)groups[i];
-	current->ngroups = gidsetsize;
-	return 0;
+	return setgroups16(gidgetsize, grouplist);
 }
 
 asmlinkage long sys32_getuid16(void)

Binary files linux-2.5.44/arch/sparc64/kernel/.sys_sparc32.c.swp and linux-2.5.44-cred/arch/sparc64/kernel/.sys_sparc32.c.swp differ

arch/sparc64/kernel/sys_sparc32.c +2 -7
diff -X exclude -urN linux-2.5.44/arch/sparc64/kernel/sys_sparc32.c linux-2.5.44-cred/arch/sparc64/kernel/sys_sparc32.c
@@ -211,12 +211,10 @@
 
 	if (gidsetsize < 0)
 		return -EINVAL;
-	i = current->ngroups;
+	i = getgroups16(NGROUPS, groups);
 	if (gidsetsize) {
 		if (i > gidsetsize)
 			return -EINVAL;
-		for(j=0;j<i;j++)
-			groups[j] = current->groups[j];
 		if (copy_to_user(grouplist, groups, sizeof(u16)*i))
 			return -EFAULT;
 	}
@@ -234,10 +232,7 @@
 		return -EINVAL;
 	if (copy_from_user(groups, grouplist, gidsetsize * sizeof(u16)))
 		return -EFAULT;
-	for (i = 0 ; i < gidsetsize ; i++)
-		current->groups[i] = (gid_t)groups[i];
-	current->ngroups = gidsetsize;
-	return 0;
+	return setgroups16(gidsetsize, groups);
 }
 
 asmlinkage long sys32_getuid16(void)
fs/exec.c +5 -0
diff -X exclude -urN linux-2.5.44/fs/exec.c linux-2.5.44-cred/fs/exec.c
@@ -864,6 +864,11 @@
         current->suid = current->euid = current->fsuid = bprm->e_uid;
         current->sgid = current->egid = current->fsgid = bprm->e_gid;
 
+	current->cred->suid = current->cred->euid = bprm->e_uid;
+	setfsuid(bprm->e_uid);
+	current->cred->sgid = current->cred->egid = bprm->e_gid;
+	setfsgid(bprm->e_gid);
+	
 	if(do_unlock)
 		unlock_kernel();
 
include/linux/cred.h +101 -0

101 lines not on this page · raw message

include/linux/init_task.h +19 -5
diff -X exclude -urN linux-2.5.44/include/linux/init_task.h linux-2.5.44-cred/include/linux/init_task.h
@@ -50,6 +50,24 @@
 	.shared_pending	= { NULL, &sig.shared_pending.head, {{0}}}, \
 }
 
+ 
+#define	INIT_CRED					\
+{							\
+	.count			= ATOMIC_INIT(1), 	\
+	.uid			= 0,			\
+	.euid			= 0,			\
+	.suid			= 0,			\
+	.gid			= 0,			\
+	.egid			= 0,			\
+	.sgid			= 0,			\
+	.vfscred		= &init_vfcred		\
+	.cap_effective		= CAP_INIT_EFF_SET,	\
+	.cap_inheritable	= CAP_INIT_INH_SET,	\
+	.cap_permitted		= CAP_FULL_SET,		\
+	.keep_capabilities	= 0,			\
+	.user			= INIT_USER		\
+}
+
 /*
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -80,17 +98,13 @@
 	.real_timer	= {						\
 		.function	= it_real_fn				\
 	},								\
-	.cap_effective	= CAP_INIT_EFF_SET,				\
-	.cap_inheritable = CAP_INIT_INH_SET,				\
-	.cap_permitted	= CAP_FULL_SET,					\
-	.keep_capabilities = 0,						\
 	.rlim		= INIT_RLIMITS,					\
-	.user		= INIT_USER,					\
 	.comm		= "swapper",					\
 	.thread		= INIT_THREAD,					\
 	.fs		= &init_fs,					\
 	.files		= &init_files,					\
 	.sig		= &init_signals,				\
+	.cred		= &init_cred					\
 	.pending	= { NULL, &tsk.pending.head, {{0}}},		\
 	.blocked	= {{0}},					\
 	.alloc_lock	= SPIN_LOCK_UNLOCKED,				\
include/linux/sched.h +3 -8
diff -X exclude -urN linux-2.5.44/include/linux/sched.h linux-2.5.44-cred/include/linux/sched.h
@@ -29,6 +29,7 @@
 #include <linux/compiler.h>
 #include <linux/completion.h>
 #include <linux/pid.h>
+#include <linux/cred.h>
 
 struct exec_domain;
 
@@ -51,7 +52,7 @@
 #define CLONE_SETTID	0x00100000	/* write the TID back to userspace */
 #define CLONE_CLEARTID	0x00200000	/* clear the userspace TID */
 #define CLONE_DETACHED	0x00400000	/* parent wants no child-exit signal */
-
+#define	CLONE_CRED	0x00800000	/* Share credentials between tasks */
 /*
  * List of flags we want to share for kernel threads,
  * if only because they are not used by them anyway.
@@ -340,13 +341,7 @@
 	unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
 	int swappable:1;
 /* process credentials */
-	uid_t uid,euid,suid,fsuid;
-	gid_t gid,egid,sgid,fsgid;
-	int ngroups;
-	gid_t	groups[NGROUPS];
-	kernel_cap_t   cap_effective, cap_inheritable, cap_permitted;
-	int keep_capabilities:1;
-	struct user_struct *user;
+	struct cred_struct* cred;
 /* limits */
 	struct rlimit rlim[RLIM_NLIMITS];
 	unsigned short used_math;
include/linux/slab.h +2 -0
diff -X exclude -urN linux-2.5.44/include/linux/slab.h linux-2.5.44-cred/include/linux/slab.h
@@ -73,6 +73,8 @@
 extern kmem_cache_t	*fs_cachep;
 extern kmem_cache_t	*sigact_cachep;
 extern kmem_cache_t	*bio_cachep;
+extern kmem_cache_t	*cred_cachep;
+extern kmem_cache_t	*vfscred_cachep;
 
 #endif	/* __KERNEL__ */
 
init/main.c +1 -0
diff -X exclude -urN linux-2.5.44/init/main.c linux-2.5.44-cred/init/main.c
@@ -424,6 +424,7 @@
 	pidhash_init();
 	pgtable_cache_init();
 	pte_chain_init();
+	credentials_init();
 	fork_init(num_physpages);
 	proc_caches_init();
 	security_scaffolding_startup();
kernel/cred.c +468 -0

468 lines not on this page · raw message

kernel/exit.c +18 -0
diff -X exclude -urN linux-2.5.44/kernel/exit.c linux-2.5.44-cred/kernel/exit.c
@@ -384,6 +384,23 @@
 	__exit_fs(tsk);
 }
 
+static inline void __exit_cred(struct task_struct *tsk)
+{
+	struct cred_struct	*cred = tsk->cred;
+
+	if (atomic_dec_and_test(&cred->count)) {
+		put_vfscred(cred->vfscred);
+		atomic_dec(&cred->user->processes);
+		free_uid(cred->user);
+		kmem_cache_free(cred_cachep, cred);
+	}
+}
+
+void exit_cred(struct task_struct *tsk)
+{
+	__exit_cred(tsk);
+}
+
 /*
  * We can use these to temporarily drop into
  * "lazy TLB" mode and back.
@@ -646,6 +663,7 @@
 	sem_exit();
 	__exit_files(tsk);
 	__exit_fs(tsk);
+	__exit_cred(tsk);
 	exit_namespace(tsk);
 	exit_thread();
 
kernel/fork.c +43 -6

91 lines not on this page · raw message

kernel/sched.c +3 -2
diff -X exclude -urN linux-2.5.44/kernel/sched.c linux-2.5.44-cred/kernel/sched.c
@@ -1447,7 +1447,7 @@
 	if ((policy == SCHED_FIFO || policy == SCHED_RR) &&
 	    !capable(CAP_SYS_NICE))
 		goto out_unlock;
-	if ((current->euid != p->euid) && (current->euid != p->uid) &&
+	if ((current->cred->euid != p->cred->euid) && (current->cred->euid != p->cred->uid) &&
 	    !capable(CAP_SYS_NICE))
 		goto out_unlock;
 
@@ -1605,7 +1605,8 @@
 	read_unlock(&tasklist_lock);
 
 	retval = -EPERM;
-	if ((current->euid != p->euid) && (current->euid != p->uid) &&
+	if ((current->cred->euid != p->cred->euid) && 
+	    (current->cred->euid != p->cred->uid) &&
 			!capable(CAP_SYS_NICE))
 		goto out_unlock;