From dde2baa239e09b7e5cb541c14be4cdefd823eacd Mon Sep 17 00:00:00 2001 From: Chas Williams Date: Mon, 14 Aug 2006 23:09:30 +0000 Subject: [PATCH] STABLE14-linux-keyring-pags-20060804 ok, well, first try (cherry picked from commit 43f1bcf65ae1f75694510524d9cb2d8fffcc5992) --- acinclude.m4 | 2 + src/afs/LINUX/osi_groups.c | 151 ++++++++++++++++++++++++++++++++- src/afs/LINUX/osi_module.c | 6 ++ src/afs/LINUX/osi_prototypes.h | 10 +++ src/afs/afs_osi_pag.c | 34 ++++++-- src/afs/sysincludes.h | 4 + 6 files changed, 196 insertions(+), 11 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index 60dcafc8a..116224613 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -602,6 +602,8 @@ case $AFS_SYSNAME in *_linux* | *_umlinux*) LINUX_SCHED_STRUCT_TASK_STRUCT_HAS_SIGNAL_RLIM LINUX_SCHED_STRUCT_TASK_STRUCT_HAS_EXIT_STATE LINUX_REFRIGERATOR + LINUX_LINUX_KEYRING_SUPPORT + LINUX_KEY_ALLOC_NEEDS_STRUCT_TASK LINUX_WHICH_MODULES if test "x$ac_cv_linux_config_modversions" = "xno" -o $AFS_SYSKVERS -ge 26; then AC_MSG_WARN([Cannot determine sys_call_table status. assuming it isn't exported]) diff --git a/src/afs/LINUX/osi_groups.c b/src/afs/LINUX/osi_groups.c index 8a4e2d2e1..bf2117296 100644 --- a/src/afs/LINUX/osi_groups.c +++ b/src/afs/LINUX/osi_groups.c @@ -15,6 +15,9 @@ */ #include #include "afs/param.h" +#ifdef LINUX_KEYRING_SUPPORT +#include +#endif RCSID ("$Header$"); @@ -148,11 +151,11 @@ set_pag_in_parent(int pag, int g0, int g1) } #endif +#if defined(AFS_LINUX26_ENV) int -setpag(cred_t ** cr, afs_uint32 pagvalue, afs_uint32 * newpag, - int change_parent) +__setpag(cred_t ** cr, afs_uint32 pagvalue, afs_uint32 * newpag, + int change_parent) { -#if defined(AFS_LINUX26_ENV) struct group_info *group_info; gid_t g0, g1; struct group_info *tmp; @@ -185,7 +188,64 @@ setpag(cred_t ** cr, afs_uint32 pagvalue, afs_uint32 * newpag, put_group_info(group_info); return 0; +} + +#ifdef LINUX_KEYRING_SUPPORT +#include +#include + +static int errno; +static inline _syscall2(long, keyctl, int, option, void*, arg2); + +static long +__join_session_keyring(char *name) +{ + return keyctl(KEYCTL_JOIN_SESSION_KEYRING, name); +} +#endif /* LINUX_KEYRING_SUPPORT */ + +int +setpag(cred_t ** cr, afs_uint32 pagvalue, afs_uint32 * newpag, + int change_parent) +{ + int code; + + code = __setpag(cr, pagvalue, newpag, change_parent); + +#ifdef LINUX_KEYRING_SUPPORT + if (code == 0) { + + (void) __join_session_keyring(NULL); + + if (current->signal->session_keyring) { + struct key *key; + key_perm_t perm; + + perm = KEY_POS_VIEW | KEY_POS_SEARCH; + perm |= KEY_USR_VIEW | KEY_USR_SEARCH; + +#ifdef KEY_ALLOC_NEEDS_STRUCT_TASK + key = key_alloc(&key_type_afs_pag, "_pag", 0, 0, current, perm, 1); +#else + key = key_alloc(&key_type_afs_pag, "_pag", 0, 0, perm, 1); +#endif + + if (!IS_ERR(key)) { + key_instantiate_and_link(key, (void *) newpag, sizeof(afs_uint32), + current->signal->session_keyring, NULL); + key_put(key); + } + } + } +#endif /* LINUX_KEYRING_SUPPORT */ + + return code; +} #else +int +setpag(cred_t ** cr, afs_uint32 pagvalue, afs_uint32 * newpag, + int change_parent) +{ gid_t *gidset; afs_int32 ngroups, code = 0; int j; @@ -219,8 +279,8 @@ setpag(cred_t ** cr, afs_uint32 pagvalue, afs_uint32 * newpag, osi_Free((char *)gidset, NGROUPS * sizeof(int)); return code; -#endif } +#endif /* Intercept the standard system call. */ @@ -396,3 +456,86 @@ afs32_xsetgroups32(int gidsetsize, gid_t * grouplist) #endif #endif + +#ifdef LINUX_KEYRING_SUPPORT +static void afs_pag_describe(const struct key *key, struct seq_file *m) +{ + seq_puts(m, key->description); + + seq_printf(m, ": %u", key->datalen); +} + +static int afs_pag_instantiate(struct key *key, const void *data, size_t datalen) +{ + int code; + afs_uint32 *userpag, pag = NOPAG; + int g0, g1; + + if (key->uid != 0 || key->gid != 0) + return -EPERM; + + code = -EINVAL; + get_group_info(current->group_info); + + if (datalen != sizeof(afs_uint32) || !data) + goto error; + + if (current->group_info->ngroups < 2) + goto error; + + /* ensure key being set matches current pag */ + + g0 = GROUP_AT(current->group_info, 0); + g1 = GROUP_AT(current->group_info, 1); + + pag = afs_get_pag_from_groups(g0, g1); + if (pag == NOPAG) + goto error; + + userpag = (afs_uint32 *) data; + if (*userpag != pag) + goto error; + + key->payload.value = (unsigned long) *userpag; + key->datalen = sizeof(afs_uint32); + code = 0; + +error: + put_group_info(current->group_info); + return code; +} + +static int afs_pag_match(const struct key *key, const void *description) +{ + return strcmp(key->description, description) == 0; +} + +struct key_type key_type_afs_pag = +{ + .name = "afs_pag", + .describe = afs_pag_describe, + .instantiate = afs_pag_instantiate, + .match = afs_pag_match, +}; + +void osi_keyring_init(void) +{ + register_key_type(&key_type_afs_pag); +} + +void osi_keyring_shutdown(void) +{ + unregister_key_type(&key_type_afs_pag); +} + +#else +void osi_keyring_init(void) +{ + return; +} + +void osi_keyring_shutdown(void) +{ + return; +} +#endif diff --git a/src/afs/LINUX/osi_module.c b/src/afs/LINUX/osi_module.c index 1e79a8af2..067a5bb32 100644 --- a/src/afs/LINUX/osi_module.c +++ b/src/afs/LINUX/osi_module.c @@ -366,14 +366,19 @@ init_module(void) osi_Init(); +#ifndef LINUX_KEYRING_SUPPORT err = osi_syscall_init(); if (err) return err; +#endif err = afs_init_inodecache(); if (err) return err; register_filesystem(&afs_fs_type); osi_sysctl_init(); +#ifdef LINUX_KEYRING_SUPPORT + osi_keyring_init(); +#endif #ifdef AFS_LINUX24_ENV afsproc_init(); #endif @@ -389,6 +394,7 @@ void cleanup_module(void) #endif { + osi_keyring_shutdown(); osi_sysctl_clean(); osi_syscall_clean(); unregister_filesystem(&afs_fs_type); diff --git a/src/afs/LINUX/osi_prototypes.h b/src/afs/LINUX/osi_prototypes.h index bf8b88ca6..c86bab6a4 100644 --- a/src/afs/LINUX/osi_prototypes.h +++ b/src/afs/LINUX/osi_prototypes.h @@ -67,4 +67,14 @@ extern void afs_destroy_inodecache(void); /* osi_vnodeops.c */ extern void afs_fill_inode(struct inode *ip, struct vattr *vattr); +/* osi_groups.c */ +extern void osi_keyring_init(void); +extern void osi_keyring_shutdown(void); +extern int __setpag(cred_t **cr, afs_uint32 pagvalue, afs_uint32 *newpag, + int change_parent); +#ifdef LINUX_KEYRING_SUPPORT +extern struct key_type key_type_afs_pag; +#endif /* LINUX_KEYRING_SUPPORT */ + + #endif /* _OSI_PROTO_H_ */ diff --git a/src/afs/afs_osi_pag.c b/src/afs/afs_osi_pag.c index 8d49baf53..00d6f0dbe 100644 --- a/src/afs/afs_osi_pag.c +++ b/src/afs/afs_osi_pag.c @@ -453,8 +453,6 @@ afs_get_pag_from_groups(gid_t g0a, gid_t g1a) /* Additional testing */ if (((ret >> 24) & 0xff) == 'A') return ret; - else - return NOPAG; #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */ } return NOPAG; @@ -487,7 +485,7 @@ PagInCred(const struct AFS_UCRED *cred) gid_t g0, g1; AFS_STATCNT(PagInCred); - if (cred == NULL) { + if (cred == NULL || cred == afs_osi_credp) { return NOPAG; } #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV) @@ -509,11 +507,15 @@ PagInCred(const struct AFS_UCRED *cred) return NOPAG; } #elif defined(AFS_LINUX26_ENV) - if (cred->cr_group_info->ngroups < 2) - return NOPAG; + if (cred->cr_group_info->ngroups < 2) { + pag = NOPAG; + goto out; + } #elif defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DUX40_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_XBSD_ENV) - if (cred->cr_ngroups < 2) - return NOPAG; + if (cred->cr_ngroups < 2) { + pag = NOPAG; + goto out; + } #endif #if defined(AFS_AIX51_ENV) g0 = cred->cr_groupset.gs_union.un_groups[0]; @@ -527,5 +529,23 @@ PagInCred(const struct AFS_UCRED *cred) #endif #endif pag = (afs_int32) afs_get_pag_from_groups(g0, g1); +out: +#ifdef LINUX_KEYRING_SUPPORT + if (pag == NOPAG) { + struct key *key; + afs_uint32 pag, newpag; + + key = request_key(&key_type_afs_pag, "_pag", NULL); + if (!IS_ERR(key)) { + if (key_validate(key) == 0 && key->uid == 0) { /* also verify in the session keyring? */ + + pag = (afs_uint32) key->payload.value; + if (((pag >> 24) & 0xff) == 'A') + __setpag(&cred, pag, &newpag, 0); + } + key_put(key); + } + } +#endif return pag; } diff --git a/src/afs/sysincludes.h b/src/afs/sysincludes.h index e67c7bc33..22fe7a684 100644 --- a/src/afs/sysincludes.h +++ b/src/afs/sysincludes.h @@ -70,6 +70,10 @@ #include #endif #include +#if defined(LINUX_KEYRING_SUPPORT) +#include +#include +#endif #endif /* Avoid conflicts with coda overloading AFS type namespace. Must precede * inclusion of uaccess.h. -- 2.39.5