diff options
-rw-r--r-- | sys/kern/vfs_syscalls.c | 30 |
1 files changed, 16 insertions, 14 deletions
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 976da4e..c51ae8f 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -2064,7 +2064,7 @@ int kern_accessat(struct thread *td, int fd, char *path, enum uio_seg pathseg, int flag, int amode) { - struct ucred *cred, *tmpcred; + struct ucred *cred, *usecred; struct vnode *vp; struct nameidata nd; cap_rights_t rights; @@ -2075,31 +2075,33 @@ kern_accessat(struct thread *td, int fd, char *path, enum uio_seg pathseg, /* * Create and modify a temporary credential instead of one that - * is potentially shared. + * is potentially shared (if we need one). */ - if (!(flag & AT_EACCESS)) { - cred = td->td_ucred; - tmpcred = crdup(cred); - tmpcred->cr_uid = cred->cr_ruid; - tmpcred->cr_groups[0] = cred->cr_rgid; - td->td_ucred = tmpcred; + cred = td->td_ucred; + if ((flag & AT_EACCESS) == 0 && + ((cred->cr_uid != cred->cr_ruid || + cred->cr_rgid != cred->cr_groups[0]))) { + usecred = crdup(cred); + usecred->cr_uid = cred->cr_ruid; + usecred->cr_groups[0] = cred->cr_rgid; + td->td_ucred = usecred; } else - cred = tmpcred = td->td_ucred; + usecred = cred; AUDIT_ARG_VALUE(amode); NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1, pathseg, path, fd, cap_rights_init(&rights, CAP_FSTAT), td); if ((error = namei(&nd)) != 0) - goto out1; + goto out; vp = nd.ni_vp; - error = vn_access(vp, amode, tmpcred, td); + error = vn_access(vp, amode, usecred, td); NDFREE(&nd, NDF_ONLY_PNBUF); vput(vp); -out1: - if (!(flag & AT_EACCESS)) { +out: + if (usecred != cred) { td->td_ucred = cred; - crfree(tmpcred); + crfree(usecred); } return (error); } |