mirror of
https://git.openafs.org/openafs.git
synced 2025-01-18 15:00:12 +00:00
OPENAFS-SA-2024-001: afs: Introduce afs_genpag()
CVE-2024-10394 Currently, several areas in the code call genpag() to generate a new PAG id, but the signature of genpag() is very limited. To allow for the code in genpag() to return errors and to examine the calling user's credentials, introduce a new function, afs_genpag(), that does the same thing as genpag(), but accepts creds and allows errors to be returned. Convert all existing callers to use afs_genpag() and to handle any errors, though no errors are ever returned in this commit on its own. To ensure there are no old callers of genpag() left around, change the existing genpag() to be called genpagval(), and declare it static. FIXES 135062 Change-Id: I5c96c0134db901f21ca30c8b3f57aeec1eb67aa5 Reviewed-on: https://gerrit.openafs.org/14090 Reviewed-by: Benjamin Kaduk <kaduk@mit.edu> Tested-by: Benjamin Kaduk <kaduk@mit.edu>
This commit is contained in:
parent
f4dfc2d718
commit
f701f704c7
@ -87,6 +87,14 @@ setpag(cred, pagvalue, newpag, change_parent)
|
||||
int j;
|
||||
|
||||
AFS_STATCNT(setpag);
|
||||
|
||||
if (pagvalue == -1) {
|
||||
code = afs_genpag(*cred, &pagvalue);
|
||||
if (code != 0) {
|
||||
return (setuerror(code), code);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef AFS_AIX51_ENV
|
||||
ngroups = afs_getgroups(*cred, NGROUPS, gidset);
|
||||
if (afs_get_pag_from_groups(gidset[0], gidset[1]) == NOPAG) {
|
||||
@ -100,7 +108,7 @@ setpag(cred, pagvalue, newpag, change_parent)
|
||||
ngroups += 2;
|
||||
}
|
||||
#endif
|
||||
*newpag = (pagvalue == -1 ? genpag() : pagvalue);
|
||||
*newpag = pagvalue;
|
||||
#ifdef AFS_AIX51_ENV
|
||||
if (change_parent) {
|
||||
code = kcred_setpag(*cred, PAG_AFS, *newpag);
|
||||
|
@ -98,6 +98,14 @@ setpag(proc, cred, pagvalue, newpag, change_parent)
|
||||
int j;
|
||||
|
||||
AFS_STATCNT(setpag);
|
||||
|
||||
if (pagvalue == -1) {
|
||||
code = afs_genpag(*cred, &pagvalue);
|
||||
if (code != 0) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
ngroups = afs_getgroups(*cred, NGROUPS, gidset);
|
||||
if (afs_get_pag_from_groups(gidset[1], gidset[2]) == NOPAG) {
|
||||
/* We will have to shift grouplist to make room for pag */
|
||||
@ -109,7 +117,7 @@ setpag(proc, cred, pagvalue, newpag, change_parent)
|
||||
}
|
||||
ngroups += 2;
|
||||
}
|
||||
*newpag = (pagvalue == -1 ? genpag() : pagvalue);
|
||||
*newpag = pagvalue;
|
||||
afs_get_groups_from_pag(*newpag, &gidset[1], &gidset[2]);
|
||||
code = afs_setgroups(proc, cred, ngroups, gidset, change_parent);
|
||||
return code;
|
||||
|
@ -80,6 +80,14 @@ setpag(struct thread *td, struct ucred **cred, afs_uint32 pagvalue,
|
||||
int j;
|
||||
|
||||
AFS_STATCNT(setpag);
|
||||
|
||||
if (pagvalue == -1) {
|
||||
code = afs_genpag(*cred, &pagvalue);
|
||||
if (code != 0) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
gidset = osi_Alloc(gidset_len * sizeof(gid_t));
|
||||
ngroups = afs_getgroups(*cred, gidset_len, gidset);
|
||||
if (afs_get_pag_from_groups(gidset[1], gidset[2]) == NOPAG) {
|
||||
@ -92,7 +100,7 @@ setpag(struct thread *td, struct ucred **cred, afs_uint32 pagvalue,
|
||||
}
|
||||
ngroups += 2;
|
||||
}
|
||||
*newpag = (pagvalue == -1 ? genpag() : pagvalue);
|
||||
*newpag = pagvalue;
|
||||
afs_get_groups_from_pag(*newpag, &gidset[1], &gidset[2]);
|
||||
code = afs_setgroups(td, cred, ngroups, gidset, change_parent);
|
||||
osi_Free(gidset, gidset_len * sizeof(gid_t));
|
||||
|
@ -71,6 +71,14 @@ setpag(cred, pagvalue, newpag, change_parent)
|
||||
int j;
|
||||
|
||||
AFS_STATCNT(setpag);
|
||||
|
||||
if (pagvalue == -1) {
|
||||
code = afs_genpag(*cred, &pagvalue);
|
||||
if (code != 0) {
|
||||
return (setuerror(code), code);
|
||||
}
|
||||
}
|
||||
|
||||
ngroups = afs_getgroups(*cred, NGROUPS, gidset);
|
||||
if (afs_get_pag_from_groups(gidset[0], gidset[1]) == NOPAG) {
|
||||
/* We will have to shift grouplist to make room for pag */
|
||||
@ -82,7 +90,7 @@ setpag(cred, pagvalue, newpag, change_parent)
|
||||
}
|
||||
ngroups += 2;
|
||||
}
|
||||
*newpag = (pagvalue == -1 ? genpag() : pagvalue);
|
||||
*newpag = pagvalue;
|
||||
afs_get_groups_from_pag(*newpag, &gidset[0], &gidset[1]);
|
||||
|
||||
if (code = afs_setgroups(cred, ngroups, gidset, change_parent)) {
|
||||
|
@ -194,6 +194,17 @@ setpag(cred, pagvalue, newpag, change_parent)
|
||||
|
||||
AFS_STATCNT(setpag);
|
||||
|
||||
if (pagvalue == -1) {
|
||||
code = afs_genpag(*cred, &pagvalue);
|
||||
if (code != 0) {
|
||||
#if defined(KERNEL_HAVE_UERROR)
|
||||
return (setuerror(code), code);
|
||||
#else
|
||||
return code;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
ngroups = afs_getgroups(*cred, NGROUPS, gidset);
|
||||
if (afs_get_pag_from_groups(gidset[0], gidset[1]) == NOPAG) {
|
||||
/* We will have to shift grouplist to make room for pag */
|
||||
@ -209,7 +220,7 @@ setpag(cred, pagvalue, newpag, change_parent)
|
||||
}
|
||||
ngroups += 2;
|
||||
}
|
||||
*newpag = (pagvalue == -1 ? genpag() : pagvalue);
|
||||
*newpag = pagvalue;
|
||||
afs_get_groups_from_pag(*newpag, &gidset[0], &gidset[1]);
|
||||
if (code = afs_setgroups(cred, ngroups, gidset, change_parent)) {
|
||||
#if defined(KERNEL_HAVE_UERROR)
|
||||
|
@ -150,11 +150,19 @@ __setpag(cred_t **cr, afs_uint32 pagvalue, afs_uint32 *newpag,
|
||||
{
|
||||
struct group_info *group_info;
|
||||
struct group_info *tmp;
|
||||
int code;
|
||||
|
||||
if (pagvalue == -1) {
|
||||
code = afs_genpag(*cr, &pagvalue);
|
||||
if (code != 0) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
get_group_info(afs_cr_group_info(*cr));
|
||||
group_info = afs_cr_group_info(*cr);
|
||||
|
||||
*newpag = (pagvalue == -1 ? genpag() : pagvalue);
|
||||
*newpag = pagvalue;
|
||||
afs_linux_pag_to_groups(*newpag, group_info, &tmp);
|
||||
|
||||
if (old_groups) {
|
||||
|
@ -84,6 +84,13 @@ setpag(afs_proc_t *proc, afs_ucred_t **cred, afs_uint32 pagvalue,
|
||||
int j;
|
||||
|
||||
AFS_STATCNT(setpag);
|
||||
|
||||
if (pagvalue == -1) {
|
||||
code = afs_genpag(*cred, &pagvalue);
|
||||
if (code != 0) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
ngroups = osi_getgroups(*cred, NGROUPS, gidset);
|
||||
if (afs_get_pag_from_groups(gidset[1], gidset[2]) == NOPAG) {
|
||||
/* We will have to shift grouplist to make room for pag */
|
||||
@ -95,7 +102,7 @@ setpag(afs_proc_t *proc, afs_ucred_t **cred, afs_uint32 pagvalue,
|
||||
}
|
||||
ngroups += 2;
|
||||
}
|
||||
*newpag = (pagvalue == -1 ? genpag() : pagvalue);
|
||||
*newpag = pagvalue;
|
||||
afs_get_groups_from_pag(*newpag, &gidset[1], &gidset[2]);
|
||||
code = osi_setgroups(proc, cred, ngroups, gidset, change_parent);
|
||||
return code;
|
||||
|
@ -81,6 +81,14 @@ setpag(struct proc *proc, struct ucred **cred, afs_uint32 pagvalue,
|
||||
int j;
|
||||
|
||||
AFS_STATCNT(setpag);
|
||||
|
||||
if (pagvalue == -1) {
|
||||
code = afs_genpag(*cred, &pagvalue);
|
||||
if (code != 0) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
ngroups = afs_getgroups(*cred, NGROUPS, gidset);
|
||||
/*
|
||||
* If the group list is empty, use the task's primary group as the group
|
||||
@ -102,7 +110,7 @@ setpag(struct proc *proc, struct ucred **cred, afs_uint32 pagvalue,
|
||||
}
|
||||
ngroups += 2;
|
||||
}
|
||||
*newpag = (pagvalue == -1 ? genpag() : pagvalue);
|
||||
*newpag = pagvalue;
|
||||
afs_get_groups_from_pag(*newpag, &gidset[1], &gidset[2]);
|
||||
code = afs_setgroups(proc, cred, ngroups, gidset, change_parent);
|
||||
return code;
|
||||
|
@ -168,6 +168,13 @@ setpag(cred, pagvalue, newpag, change_parent)
|
||||
|
||||
AFS_STATCNT(setpag);
|
||||
|
||||
if (pagvalue == -1) {
|
||||
code = afs_genpag(*cred, &pagvalue);
|
||||
if (code != 0) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
/* Derive gidset size from running kernel's ngroups_max;
|
||||
* default 16, but configurable up to 32 (Sol10) or
|
||||
* 1024 (Sol11).
|
||||
@ -177,8 +184,6 @@ setpag(cred, pagvalue, newpag, change_parent)
|
||||
/* must use osi_Alloc, osi_AllocSmallSpace may not be enough. */
|
||||
gidset = osi_Alloc(gidset_sz);
|
||||
|
||||
pagvalue = (pagvalue == -1 ? genpag() : pagvalue);
|
||||
|
||||
mutex_enter(&curproc->p_crlock);
|
||||
ngroups = afs_getgroups(*cred, gidset);
|
||||
|
||||
|
@ -74,6 +74,13 @@ usr_setpag(struct usr_ucred **cred, afs_uint32 pagvalue, afs_uint32 * newpag,
|
||||
|
||||
AFS_STATCNT(setpag);
|
||||
|
||||
if (pagvalue == -1) {
|
||||
code = afs_genpag(*cred, &pagvalue);
|
||||
if (code != 0) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
gidset = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
|
||||
ngroups = afs_getgroups(*cred, gidset);
|
||||
|
||||
@ -88,7 +95,7 @@ usr_setpag(struct usr_ucred **cred, afs_uint32 pagvalue, afs_uint32 * newpag,
|
||||
}
|
||||
ngroups += 2;
|
||||
}
|
||||
*newpag = (pagvalue == -1 ? genpag() : pagvalue);
|
||||
*newpag = pagvalue;
|
||||
afs_get_groups_from_pag(*newpag, &gidset[0], &gidset[1]);
|
||||
if ((code = afs_setgroups(cred, ngroups, gidset, change_parent))) {
|
||||
osi_FreeSmallSpace((char *)gidset);
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
/*
|
||||
* Implements:
|
||||
* genpag
|
||||
* genpagval
|
||||
* getpag
|
||||
* afs_setpag
|
||||
* AddPag
|
||||
@ -67,8 +67,8 @@ afs_uint32 pagCounter = 0;
|
||||
* secure (although of course not absolutely secure).
|
||||
*/
|
||||
#if !defined(UKERNEL)
|
||||
afs_uint32
|
||||
genpag(void)
|
||||
static afs_uint32
|
||||
genpagval(void)
|
||||
{
|
||||
AFS_STATCNT(genpag);
|
||||
#ifdef AFS_LINUX_ENV
|
||||
@ -96,8 +96,8 @@ getpag(void)
|
||||
/* Web enhancement: we don't need to restrict pags to 41XXXXXX since
|
||||
* we are not sharing the space with anyone. So we use the full 32 bits. */
|
||||
|
||||
afs_uint32
|
||||
genpag(void)
|
||||
static afs_uint32
|
||||
genpagval(void)
|
||||
{
|
||||
AFS_STATCNT(genpag);
|
||||
#ifdef AFS_LINUX_ENV
|
||||
@ -182,6 +182,13 @@ afs_pag_wait(afs_ucred_t *acred)
|
||||
return code;
|
||||
}
|
||||
|
||||
afs_int32
|
||||
afs_genpag(afs_ucred_t *acred, afs_uint32 *apag)
|
||||
{
|
||||
*apag = genpagval();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
#if defined(AFS_SUN5_ENV)
|
||||
afs_setpag(afs_ucred_t **credpp)
|
||||
@ -205,6 +212,7 @@ afs_setpag(void)
|
||||
#endif
|
||||
|
||||
int code = 0;
|
||||
afs_uint32 pag;
|
||||
|
||||
#if defined(AFS_SGI_ENV) && defined(MP)
|
||||
/* This is our first chance to get the global lock. */
|
||||
@ -218,15 +226,19 @@ afs_setpag(void)
|
||||
goto done;
|
||||
}
|
||||
|
||||
code = afs_genpag(acred, &pag);
|
||||
if (code) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
#if defined(AFS_SUN5_ENV)
|
||||
code = AddPag(genpag(), credpp);
|
||||
code = AddPag(pag, credpp);
|
||||
#elif defined(AFS_FBSD_ENV)
|
||||
code = AddPag(td, genpag(), &td->td_ucred);
|
||||
code = AddPag(td, pag, &td->td_ucred);
|
||||
#elif defined(AFS_NBSD40_ENV)
|
||||
code = AddPag(p, genpag(), &p->l_proc->p_cred);
|
||||
code = AddPag(p, pag, &p->l_proc->p_cred);
|
||||
#elif defined(AFS_XBSD_ENV)
|
||||
code = AddPag(p, genpag(), &p->p_rcred);
|
||||
code = AddPag(p, pag, &p->p_rcred);
|
||||
#elif defined(AFS_AIX41_ENV)
|
||||
{
|
||||
struct ucred *credp;
|
||||
@ -234,7 +246,7 @@ afs_setpag(void)
|
||||
|
||||
credp = crref();
|
||||
credp0 = credp;
|
||||
code = AddPag(genpag(), &credp);
|
||||
code = AddPag(pag, &credp);
|
||||
/* If AddPag() didn't make a new cred, then free our cred ref */
|
||||
if (credp == credp0) {
|
||||
crfree(credp);
|
||||
@ -243,36 +255,36 @@ afs_setpag(void)
|
||||
#elif defined(AFS_HPUX110_ENV)
|
||||
{
|
||||
struct ucred *credp = p_cred(u.u_procp);
|
||||
code = AddPag(genpag(), &credp);
|
||||
code = AddPag(pag, &credp);
|
||||
}
|
||||
#elif defined(AFS_SGI_ENV)
|
||||
{
|
||||
cred_t *credp;
|
||||
credp = OSI_GET_CURRENT_CRED();
|
||||
code = AddPag(genpag(), &credp);
|
||||
code = AddPag(pag, &credp);
|
||||
}
|
||||
#elif defined(AFS_LINUX_ENV)
|
||||
{
|
||||
afs_ucred_t *credp = crref();
|
||||
code = AddPag(genpag(), &credp);
|
||||
code = AddPag(pag, &credp);
|
||||
crfree(credp);
|
||||
}
|
||||
#elif defined(AFS_DARWIN80_ENV)
|
||||
{
|
||||
afs_ucred_t *credp = kauth_cred_proc_ref(p);
|
||||
code = AddPag(p, genpag(), &credp);
|
||||
code = AddPag(p, pag, &credp);
|
||||
crfree(credp);
|
||||
}
|
||||
#elif defined(AFS_DARWIN_ENV)
|
||||
{
|
||||
afs_ucred_t *credp = crdup(p->p_cred->pc_ucred);
|
||||
code = AddPag(p, genpag(), &credp);
|
||||
code = AddPag(p, pag, &credp);
|
||||
crfree(credp);
|
||||
}
|
||||
#elif defined(UKERNEL)
|
||||
code = AddPag(genpag(), &(get_user_struct()->u_cred));
|
||||
code = AddPag(pag, &(get_user_struct()->u_cred));
|
||||
#else
|
||||
code = AddPag(genpag(), &u.u_cred);
|
||||
code = AddPag(pag, &u.u_cred);
|
||||
#endif
|
||||
|
||||
done:
|
||||
@ -294,7 +306,7 @@ afs_setpag(void)
|
||||
/*
|
||||
* afs_setpag_val
|
||||
* This function is like setpag but sets the current thread's pag id to a
|
||||
* caller-provided value instead of calling genpag(). This implements a
|
||||
* caller-provided value instead of calling afs_genpag(). This implements a
|
||||
* form of token caching since the caller can recall a particular pag value
|
||||
* for the thread to restore tokens, rather than reauthenticating.
|
||||
*/
|
||||
|
@ -4721,7 +4721,13 @@ HandleClientContext(struct afs_ioctl *ablob, int *com,
|
||||
*acred = newcred;
|
||||
if (!code && *com == PSETPAG) {
|
||||
/* Special case for 'setpag' */
|
||||
afs_uint32 pagvalue = genpag();
|
||||
afs_uint32 pagvalue;
|
||||
|
||||
code = afs_genpag(*acred, &pagvalue);
|
||||
if (code != 0) {
|
||||
EXP_RELE(outexporter);
|
||||
return code;
|
||||
}
|
||||
|
||||
au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
|
||||
/*
|
||||
|
@ -526,7 +526,7 @@ extern int afs_setpag(afs_proc_t *p, void *args, int *retval);
|
||||
extern int afs_setpag(void);
|
||||
#endif
|
||||
|
||||
extern afs_uint32 genpag(void);
|
||||
extern afs_int32 afs_genpag(afs_ucred_t *acred, afs_uint32 *apag);
|
||||
extern afs_uint32 getpag(void);
|
||||
#if defined(AFS_FBSD_ENV)
|
||||
extern int AddPag(struct thread *td, afs_int32 aval, afs_ucred_t **credpp);
|
||||
|
@ -545,7 +545,7 @@ struct afs_MeanStats {
|
||||
AFS_CS(afs_swapvp) /* afs_vfsops.c */ \
|
||||
AFS_CS(afs_AddMarinerName) /* afs_vnodeops.c */ \
|
||||
AFS_CS(afs_setpag) /* afs_vnodeops.c */ \
|
||||
AFS_CS(genpag) /* afs_vnodeops.c */ \
|
||||
AFS_CS(genpag) /* afs_vnodeops.c, renamed to genpagval() */ \
|
||||
AFS_CS(getpag) /* afs_vnodeops.c */ \
|
||||
AFS_CS(afs_GetMariner) /* afs_vnodeops.c */ \
|
||||
AFS_CS(afs_badop) /* afs_vnodeops.c */ \
|
||||
|
Loading…
Reference in New Issue
Block a user