shared credentials with vfs snapshotting
Subsystems (6)
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]
Oh yeah, the code!
Signature · 2 lines
Dave Hansen [email protected]
arch/i386/kernel/init_task.c +1 -0
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;