From dc85abcaa6e3423452078e36bbfcd281e613c407 Mon Sep 17 00:00:00 2001 From: Marc Dionne Date: Thu, 29 Oct 2009 19:58:00 -0400 Subject: [PATCH] Linux: Use the kernel's credentials structure Recent kernels (2.6.29 and above) have a separate ref-counted structure for holding credentials. Use it directly instead of keeping a separate afs specific structure that shadows the same information. Also adapt Linux for the change from cr_xxx to afs_cr_xxx wrappers. Reference counting is done with the appropriate get/put calls. Change-Id: I1135bb5a66cda51cee4fa9f3f3e63eaa9af28f61 Reviewed-on: http://gerrit.openafs.org/797 Reviewed-by: Derrick Brashear Tested-by: Derrick Brashear --- src/afs/LINUX/osi_cred.c | 71 ++++++++++++++++++++++++---------------- src/afs/LINUX/osi_groups.c | 8 ++--- src/afs/LINUX/osi_machdep.h | 79 ++++++++++++++++++++++++++++++++------------- src/afs/afs.h | 8 ++++- src/afs/afs_osi.c | 2 +- src/afs/afs_osi_pag.c | 8 ++--- 6 files changed, 117 insertions(+), 59 deletions(-) diff --git a/src/afs/LINUX/osi_cred.c b/src/afs/LINUX/osi_cred.c index 76bc98d..69b2614 100644 --- a/src/afs/LINUX/osi_cred.c +++ b/src/afs/LINUX/osi_cred.c @@ -18,6 +18,17 @@ #include "afs/sysincludes.h" #include "afsincludes.h" +/* Copy one credential structure to another, being careful about references */ +static inline void +afs_copy_creds(cred_t *to_cred, const cred_t *from_cred) { + afs_set_cr_uid(to_cred, afs_cr_uid(from_cred)); + afs_set_cr_gid(to_cred, afs_cr_gid(from_cred)); + afs_set_cr_ruid(to_cred, afs_cr_ruid(from_cred)); + afs_set_cr_rgid(to_cred, afs_cr_rgid(from_cred)); + get_group_info(afs_cr_group_info(from_cred)); + afs_set_cr_group_info(to_cred, afs_cr_group_info(from_cred)); +} + cred_t * crget(void) { @@ -27,24 +38,31 @@ crget(void) #define GFP_NOFS GFP_KERNEL #endif tmp = kmalloc(sizeof(cred_t), GFP_NOFS); + memset(tmp, 0, sizeof(cred_t)); if (!tmp) - osi_Panic("crget: No more memory for creds!\n"); - + osi_Panic("crget: No more memory for creds!\n"); + +#if defined(STRUCT_TASK_HAS_CRED) + get_cred(tmp); +#else tmp->cr_ref = 1; +#endif return tmp; } void crfree(cred_t * cr) { +#if defined(STRUCT_TASK_HAS_CRED) + put_cred(cr); +#else if (cr->cr_ref > 1) { cr->cr_ref--; return; } - - put_group_info(cr_group_info(cr)); - + put_group_info(afs_cr_group_info(cr)); kfree(cr); +#endif } @@ -53,21 +71,26 @@ cred_t * crdup(cred_t * cr) { cred_t *tmp = crget(); - +#if defined(STRUCT_TASK_HAS_CRED) + afs_copy_creds(tmp, cr); +#else afs_set_cr_uid(tmp, afs_cr_uid(cr)); afs_set_cr_ruid(tmp, afs_cr_ruid(cr)); afs_set_cr_gid(tmp, afs_cr_gid(cr)); afs_set_cr_rgid(tmp, afs_cr_rgid(cr)); - get_group_info(cr_group_info(cr)); - set_cr_group_info(tmp, cr_group_info(cr)); - + get_group_info(afs_cr_group_info(cr)); + afs_set_cr_group_info(tmp, afs_cr_group_info(cr)); +#endif return tmp; } cred_t * crref(void) { +#if defined(STRUCT_TASK_HAS_CRED) + return (cred_t *)get_current_cred(); +#else cred_t *cr = crget(); afs_set_cr_uid(cr, current_fsuid()); @@ -77,17 +100,17 @@ crref(void) task_lock(current); get_group_info(current_group_info()); - set_cr_group_info(cr, current_group_info()); + afs_set_cr_group_info(cr, current_group_info()); task_unlock(current); return cr; +#endif } /* Set the cred info into the current task */ void crset(cred_t * cr) { - struct group_info *old_info; #if defined(STRUCT_TASK_HAS_CRED) struct cred *new_creds; @@ -98,30 +121,24 @@ crset(cred_t * cr) if (current->cred != current->real_cred) return; new_creds = prepare_creds(); - new_creds->fsuid = afs_cr_uid(cr); - new_creds->uid = afs_cr_ruid(cr); - new_creds->fsgid = afs_cr_gid(cr); - new_creds->gid = afs_cr_rgid(cr); + /* Drop the reference to group_info - we'll overwrite it in afs_copy_creds */ + put_group_info(new_creds->group_info); + afs_copy_creds(new_creds, current_cred()); + + commit_creds(new_creds); #else + struct group_info *old_info; + current->fsuid = afs_cr_uid(cr); current->uid = afs_cr_ruid(cr); current->fsgid = afs_cr_gid(cr); current->gid = afs_cr_rgid(cr); -#endif - - /* using set_current_groups() will sort the groups */ - get_group_info(cr_group_info(cr)); + get_group_info(afs_cr_group_info(cr)); task_lock(current); -#if defined(STRUCT_TASK_HAS_CRED) - old_info = current->cred->group_info; - new_creds->group_info = cr_group_info(cr); - commit_creds(new_creds); -#else old_info = current->group_info; - current->group_info = cr_group_info(cr); -#endif + current->group_info = afs_cr_group_info(cr); task_unlock(current); - put_group_info(old_info); +#endif } diff --git a/src/afs/LINUX/osi_groups.c b/src/afs/LINUX/osi_groups.c index d8dc83f..c9efc75 100644 --- a/src/afs/LINUX/osi_groups.c +++ b/src/afs/LINUX/osi_groups.c @@ -39,9 +39,9 @@ afs_setgroups(cred_t **cr, struct group_info *group_info, int change_parent) AFS_STATCNT(afs_setgroups); - old_info = cr_group_info(*cr); + old_info = afs_cr_group_info(*cr); get_group_info(group_info); - set_cr_group_info(*cr, group_info); + afs_set_cr_group_info(*cr, group_info); put_group_info(old_info); crset(*cr); @@ -65,8 +65,8 @@ afs_getgroups(cred_t * cr) { AFS_STATCNT(afs_getgroups); - get_group_info(cr_group_info(cr)); - return cr_group_info(cr); + get_group_info(afs_cr_group_info(cr)); + return afs_cr_group_info(cr); } int diff --git a/src/afs/LINUX/osi_machdep.h b/src/afs/LINUX/osi_machdep.h index 2ff0896..52d4ea2 100644 --- a/src/afs/LINUX/osi_machdep.h +++ b/src/afs/LINUX/osi_machdep.h @@ -153,38 +153,65 @@ static inline long copyinstr(char *from, char *to, int count, int *length) { #define NGROUPS NGROUPS_SMALL #endif -/* cred struct */ -typedef struct afs_cred { /* maps to task field: */ - int cr_ref; - uid_t cr_uid; /* euid */ - uid_t cr_ruid; /* uid */ - gid_t cr_gid; /* egid */ - gid_t cr_rgid; /* gid */ - struct group_info *cr_group_info; -} cred_t; - -typedef struct afs_cred afs_ucred_t; typedef struct task_struct afs_proc_t; -#define cr_group_info(cred) ((cred)->cr_group_info) +/* Credentials. For newer kernels we use the kernel structure directly. */ +#if defined(STRUCT_TASK_HAS_CRED) + +typedef struct cred afs_ucred_t; +typedef struct cred cred_t; + +#define afs_cr_uid(cred) ((cred)->fsuid) +#define afs_cr_gid(cred) ((cred)->fsgid) +#define afs_cr_ruid(cred) ((cred)->uid) +#define afs_cr_rgid(cred) ((cred)->gid) +#define afs_cr_group_info(cred) ((cred)->group_info) +#define crhold(c) (get_cred(c)) static inline void -set_cr_group_info(afs_ucred_t *cred, struct group_info *group_info) { - cred->cr_group_info = group_info; +afs_set_cr_uid(cred_t *cred, uid_t uid) { + cred->fsuid = uid; +} +static inline void +afs_set_cr_gid(cred_t *cred, gid_t gid) { + cred->fsgid = gid; +} +static inline void +afs_set_cr_ruid(cred_t *cred, uid_t uid) { + cred->uid = uid; +} +static inline void +afs_set_cr_rgid(cred_t *cred, gid_t gid) { + cred->gid = gid; +} +static inline void +afs_set_cr_group_info(cred_t *cred, struct group_info *group_info) { + cred->group_info = group_info; } -#if !defined(current_cred) -#define current_gid() (current->gid) -#define current_uid() (current->uid) -#define current_fsgid() (current->fsgid) -#define current_fsuid() (current->fsuid) -#endif -#if defined(STRUCT_TASK_HAS_CRED) #define current_group_info() (current->cred->group_info) #define task_gid(task) (task->cred->gid) #define task_user(task) (task->cred->user) #define task_session_keyring(task) (task->cred->tgcred->session_keyring) #define current_session_keyring() (current->cred->tgcred->session_keyring) + #else + +typedef struct afs_cred { + int cr_ref; + uid_t cr_uid; + uid_t cr_ruid; + gid_t cr_gid; + gid_t cr_rgid; + struct group_info *cr_group_info; +} cred_t; + +typedef struct afs_cred afs_ucred_t; +#define afs_cr_group_info(cred) ((cred)->cr_group_info) +static inline void +afs_set_cr_group_info(cred_t *cred, struct group_info *group_info) { + cred->cr_group_info = group_info; +} + #define current_group_info() (current->group_info) #if !defined(task_gid) #define task_gid(task) (task->gid) @@ -195,9 +222,17 @@ set_cr_group_info(afs_ucred_t *cred, struct group_info *group_info) { #define task_user(task) (task->user) #define task_session_keyring(task) (task->signal->session_keyring) #define current_session_keyring() (current->signal->session_keyring) -#endif #define crhold(c) (c)->cr_ref++ +#endif /* defined(STRUCT_TASK_HAS_CRED) */ + +#if !defined(current_cred) +#define current_gid() (current->gid) +#define current_uid() (current->uid) +#define current_fsgid() (current->fsgid) +#define current_fsuid() (current->fsuid) +#endif + /* UIO manipulation */ typedef enum { AFS_UIOSYS, AFS_UIOUSER } uio_seg_t; typedef enum { UIO_READ, UIO_WRITE } uio_flag_t; diff --git a/src/afs/afs.h b/src/afs/afs.h index c03c9ca..4f45c38 100644 --- a/src/afs/afs.h +++ b/src/afs/afs.h @@ -1399,7 +1399,12 @@ extern int afsd_dynamic_vcaches; #define afsd_dynamic_vcaches 0 #endif -/* Wrappers for access to credentials structure members */ +/* + * Wrappers for access to credentials structure members + * Linux uses the kernel cred structure if available, with the + * wrappers defined in LINUX/osi_machdep.h + */ +#if !(defined(AFS_LINUX26_ENV) && defined(STRUCT_TASK_HAS_CRED)) #define afs_cr_uid(cred) ((cred)->cr_uid) #define afs_cr_gid(cred) ((cred)->cr_gid) #define afs_cr_ruid(cred) ((cred)->cr_ruid) @@ -1421,4 +1426,5 @@ static_inline void afs_set_cr_rgid(afs_ucred_t *cred, gid_t gid) { cred->cr_rgid = gid; } +#endif #endif /* _AFS_H_ */ diff --git a/src/afs/afs_osi.c b/src/afs/afs_osi.c index f075ef2..1257902 100644 --- a/src/afs/afs_osi.c +++ b/src/afs/afs_osi.c @@ -115,7 +115,7 @@ osi_Init(void) #else memset(&afs_osi_cred, 0, sizeof(afs_ucred_t)); #if defined(AFS_LINUX26_ENV) - set_cr_group_info(&afs_osi_cred, groups_alloc(0)); + afs_set_cr_group_info(&afs_osi_cred, groups_alloc(0)); #endif #if defined(AFS_DARWIN80_ENV) afs_osi_cred.cr_ref = 1; /* kauth_cred_get_ref needs 1 existing ref */ diff --git a/src/afs/afs_osi_pag.c b/src/afs/afs_osi_pag.c index b1d715f..740d460 100644 --- a/src/afs/afs_osi_pag.c +++ b/src/afs/afs_osi_pag.c @@ -571,7 +571,7 @@ PagInCred(afs_ucred_t *cred) return NOPAG; } #elif defined(AFS_LINUX26_ENV) - if (cr_group_info(cred)->ngroups < NUMPAGGROUPS) { + if (afs_cr_group_info(cred)->ngroups < NUMPAGGROUPS) { pag = NOPAG; goto out; } @@ -590,8 +590,8 @@ PagInCred(afs_ucred_t *cred) g1 = cred->cr_groupset.gs_union.un_groups[1]; #elif defined(AFS_LINUX26_ONEGROUP_ENV) #elif defined(AFS_LINUX26_ENV) - g0 = GROUP_AT(cr_group_info(cred), 0); - g1 = GROUP_AT(cr_group_info(cred), 1); + g0 = GROUP_AT(afs_cr_group_info(cred), 0); + g1 = GROUP_AT(afs_cr_group_info(cred), 1); #elif defined(AFS_SUN510_ENV) g0 = gids[0]; g1 = gids[1]; @@ -601,7 +601,7 @@ PagInCred(afs_ucred_t *cred) #endif #endif #if defined(AFS_LINUX26_ONEGROUP_ENV) - pag = (afs_int32) afs_get_pag_from_groups(cr_group_info(cred)); + pag = (afs_int32) afs_get_pag_from_groups(afs_cr_group_info(cred)); #else pag = (afs_int32) afs_get_pag_from_groups(g0, g1); #endif -- 1.9.4