exec: Add credential change information into imgp for process_exec hook.

This allows an EVENTHANDLER(process_exec) hook to see if the new image
will cause credentials to change whether due to setgid/setuid or because
of POSIX saved-id semantics.

This adds 3 new fields into image_params:
  struct ucred *newcred		Non-null if the credentials will change.
  bool credential_setid		True if the new image is setuid or setgid.

This will pre-determine the new credentials before invoking the image
activators, where the process_exec hook is called.  The new credentials
will be installed into the process in the same place as before, after
image activators are done handling the image.

MFC after:	2 weeks
Reviewed by:	kib
Sponsored by:	EMC / Isilon Storage Division
Differential Revision:	https://reviews.freebsd.org/D6544
This commit is contained in:
Bryan Drewery 2016-05-26 23:18:54 +00:00
parent 8f7ada2196
commit 881010f05d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=300792
2 changed files with 106 additions and 86 deletions

View File

@ -356,7 +356,7 @@ do_execve(td, args, mac_p)
{
struct proc *p = td->td_proc;
struct nameidata nd;
struct ucred *newcred = NULL, *oldcred;
struct ucred *oldcred;
struct uidinfo *euip = NULL;
register_t *stack_base;
int error, i;
@ -404,6 +404,7 @@ do_execve(td, args, mac_p)
imgp->proc = p;
imgp->attr = &attr;
imgp->args = args;
oldcred = p->p_ucred;
#ifdef MAC
error = mac_execve_enter(imgp, mac_p);
@ -485,6 +486,87 @@ do_execve(td, args, mac_p)
goto exec_fail_dealloc;
imgp->proc->p_osrel = 0;
/*
* Implement image setuid/setgid.
*
* Determine new credentials before attempting image activators
* so that it can be used by process_exec handlers to determine
* credential/setid changes.
*
* Don't honor setuid/setgid if the filesystem prohibits it or if
* the process is being traced.
*
* We disable setuid/setgid/etc in capability mode on the basis
* that most setugid applications are not written with that
* environment in mind, and will therefore almost certainly operate
* incorrectly. In principle there's no reason that setugid
* applications might not be useful in capability mode, so we may want
* to reconsider this conservative design choice in the future.
*
* XXXMAC: For the time being, use NOSUID to also prohibit
* transitions on the file system.
*/
credential_changing = 0;
credential_changing |= (attr.va_mode & S_ISUID) &&
oldcred->cr_uid != attr.va_uid;
credential_changing |= (attr.va_mode & S_ISGID) &&
oldcred->cr_gid != attr.va_gid;
#ifdef MAC
will_transition = mac_vnode_execve_will_transition(oldcred, imgp->vp,
interpvplabel, imgp);
credential_changing |= will_transition;
#endif
if (credential_changing &&
#ifdef CAPABILITY_MODE
((oldcred->cr_flags & CRED_FLAG_CAPMODE) == 0) &&
#endif
(imgp->vp->v_mount->mnt_flag & MNT_NOSUID) == 0 &&
(p->p_flag & P_TRACED) == 0) {
imgp->credential_setid = true;
VOP_UNLOCK(imgp->vp, 0);
imgp->newcred = crdup(oldcred);
if (attr.va_mode & S_ISUID) {
euip = uifind(attr.va_uid);
change_euid(imgp->newcred, euip);
}
vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY);
if (attr.va_mode & S_ISGID)
change_egid(imgp->newcred, attr.va_gid);
/*
* Implement correct POSIX saved-id behavior.
*
* XXXMAC: Note that the current logic will save the
* uid and gid if a MAC domain transition occurs, even
* though maybe it shouldn't.
*/
change_svuid(imgp->newcred, imgp->newcred->cr_uid);
change_svgid(imgp->newcred, imgp->newcred->cr_gid);
} else {
/*
* Implement correct POSIX saved-id behavior.
*
* XXX: It's not clear that the existing behavior is
* POSIX-compliant. A number of sources indicate that the
* saved uid/gid should only be updated if the new ruid is
* not equal to the old ruid, or the new euid is not equal
* to the old euid and the new euid is not equal to the old
* ruid. The FreeBSD code always updates the saved uid/gid.
* Also, this code uses the new (replaced) euid and egid as
* the source, which may or may not be the right ones to use.
*/
if (oldcred->cr_svuid != oldcred->cr_uid ||
oldcred->cr_svgid != oldcred->cr_gid) {
VOP_UNLOCK(imgp->vp, 0);
imgp->newcred = crdup(oldcred);
vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY);
change_svuid(imgp->newcred, imgp->newcred->cr_uid);
change_svgid(imgp->newcred, imgp->newcred->cr_gid);
}
}
/* The new credentials are installed into the process later. */
/*
* If the current process has a special image activator it
* wants to try first, call it. For example, emulating shell
@ -542,6 +624,11 @@ do_execve(td, args, mac_p)
vput(newtextvp);
vm_object_deallocate(imgp->object);
imgp->object = NULL;
imgp->credential_setid = false;
if (imgp->newcred != NULL) {
crfree(imgp->newcred);
imgp->newcred = NULL;
}
/* set new name to that of the interpreter */
NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME,
UIO_SYSSPACE, imgp->interpreter_name, td);
@ -639,7 +726,6 @@ do_execve(td, args, mac_p)
PROC_LOCK(p);
if (oldsigacts)
p->p_sigacts = newsigacts;
oldcred = p->p_ucred;
/* Stop profiling */
stopprofclock(p);
@ -671,38 +757,9 @@ do_execve(td, args, mac_p)
}
/*
* Implement image setuid/setgid.
*
* Don't honor setuid/setgid if the filesystem prohibits it or if
* the process is being traced.
*
* We disable setuid/setgid/etc in capability mode on the basis
* that most setugid applications are not written with that
* environment in mind, and will therefore almost certainly operate
* incorrectly. In principle there's no reason that setugid
* applications might not be useful in capability mode, so we may want
* to reconsider this conservative design choice in the future.
*
* XXXMAC: For the time being, use NOSUID to also prohibit
* transitions on the file system.
* Implement image setuid/setgid installation.
*/
credential_changing = 0;
credential_changing |= (attr.va_mode & S_ISUID) && oldcred->cr_uid !=
attr.va_uid;
credential_changing |= (attr.va_mode & S_ISGID) && oldcred->cr_gid !=
attr.va_gid;
#ifdef MAC
will_transition = mac_vnode_execve_will_transition(oldcred, imgp->vp,
interpvplabel, imgp);
credential_changing |= will_transition;
#endif
if (credential_changing &&
#ifdef CAPABILITY_MODE
((oldcred->cr_flags & CRED_FLAG_CAPMODE) == 0) &&
#endif
(imgp->vp->v_mount->mnt_flag & MNT_NOSUID) == 0 &&
(p->p_flag & P_TRACED) == 0) {
if (imgp->credential_setid) {
/*
* Turn off syscall tracing for set-id programs, except for
* root. Record any set-id flags first to make sure that
@ -728,61 +785,24 @@ do_execve(td, args, mac_p)
error = fdcheckstd(td);
if (error != 0)
goto done1;
newcred = crdup(oldcred);
euip = uifind(attr.va_uid);
vn_lock(imgp->vp, LK_SHARED | LK_RETRY);
PROC_LOCK(p);
/*
* Set the new credentials.
*/
if (attr.va_mode & S_ISUID)
change_euid(newcred, euip);
if (attr.va_mode & S_ISGID)
change_egid(newcred, attr.va_gid);
#ifdef MAC
if (will_transition) {
mac_vnode_execve_transition(oldcred, newcred, imgp->vp,
interpvplabel, imgp);
mac_vnode_execve_transition(oldcred, imgp->newcred,
imgp->vp, interpvplabel, imgp);
}
#endif
/*
* Implement correct POSIX saved-id behavior.
*
* XXXMAC: Note that the current logic will save the
* uid and gid if a MAC domain transition occurs, even
* though maybe it shouldn't.
*/
change_svuid(newcred, newcred->cr_uid);
change_svgid(newcred, newcred->cr_gid);
proc_set_cred(p, newcred);
} else {
if (oldcred->cr_uid == oldcred->cr_ruid &&
oldcred->cr_gid == oldcred->cr_rgid)
p->p_flag &= ~P_SUGID;
/*
* Implement correct POSIX saved-id behavior.
*
* XXX: It's not clear that the existing behavior is
* POSIX-compliant. A number of sources indicate that the
* saved uid/gid should only be updated if the new ruid is
* not equal to the old ruid, or the new euid is not equal
* to the old euid and the new euid is not equal to the old
* ruid. The FreeBSD code always updates the saved uid/gid.
* Also, this code uses the new (replaced) euid and egid as
* the source, which may or may not be the right ones to use.
*/
if (oldcred->cr_svuid != oldcred->cr_uid ||
oldcred->cr_svgid != oldcred->cr_gid) {
PROC_UNLOCK(p);
VOP_UNLOCK(imgp->vp, 0);
newcred = crdup(oldcred);
vn_lock(imgp->vp, LK_SHARED | LK_RETRY);
PROC_LOCK(p);
change_svuid(newcred, newcred->cr_uid);
change_svgid(newcred, newcred->cr_gid);
proc_set_cred(p, newcred);
}
}
/*
* Set the new credentials.
*/
if (imgp->newcred != NULL)
proc_set_cred(p, imgp->newcred);
/*
* Store the vp for use in procfs. This vnode was referenced by namei
@ -855,14 +875,6 @@ do_execve(td, args, mac_p)
VOP_UNLOCK(imgp->vp, 0);
done1:
/*
* Free any resources malloc'd earlier that we didn't use.
*/
if (euip != NULL)
uifree(euip);
if (newcred != NULL)
crfree(oldcred);
/*
* Handle deferred decrement of ref counts.
*/
@ -881,10 +893,12 @@ do_execve(td, args, mac_p)
sigacts_free(oldsigacts);
exec_fail_dealloc:
/*
* free various allocated resources
*/
if (euip != NULL)
uifree(euip);
if (imgp->firstpage != NULL)
exec_unmap_first_page(imgp);
@ -926,6 +940,8 @@ do_execve(td, args, mac_p)
SDT_PROBE1(proc, , , exec__failure, error);
done2:
if (imgp->newcred != NULL)
crfree(oldcred);
#ifdef MAC
mac_execve_exit(imgp);
mac_execve_interpreter_exit(interpvplabel);

View File

@ -38,6 +38,8 @@
#define MAXSHELLCMDLEN PAGE_SIZE
struct ucred;
struct image_args {
char *buf; /* pointer to string buffer */
char *begin_argv; /* beginning of argv in buf */
@ -82,6 +84,8 @@ struct image_params {
int pagesizeslen;
vm_prot_t stack_prot;
u_long stack_sz;
struct ucred *newcred; /* new credentials if changing */
bool credential_setid; /* true if becoming setid */
};
#ifdef _KERNEL