From daf63fd2f9a8d0402a05c2f4c7326d96cf7b0a23 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Mon, 16 Mar 2015 00:10:03 +0000 Subject: [PATCH] cred: add proc_set_cred helper The goal here is to provide one place altering process credentials. This eases debugging and opens up posibilities to do additional work when such an action is performed. --- sys/compat/linux/linux_misc.c | 2 +- sys/compat/linux/linux_uid16.c | 2 +- sys/kern/init_main.c | 22 ++++++++------- sys/kern/kern_exec.c | 4 +-- sys/kern/kern_exit.c | 2 +- sys/kern/kern_fork.c | 5 ++-- sys/kern/kern_jail.c | 2 +- sys/kern/kern_loginclass.c | 2 +- sys/kern/kern_prot.c | 43 +++++++++++++++++++++++------ sys/kern/sys_capability.c | 2 +- sys/security/audit/audit_syscalls.c | 8 +++--- sys/security/mac/mac_syscalls.c | 2 +- sys/security/mac_lomac/mac_lomac.c | 2 +- sys/sys/ucred.h | 1 + 14 files changed, 64 insertions(+), 35 deletions(-) diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 93dd80db0640..ec531d39df1c 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -1138,7 +1138,7 @@ linux_setgroups(struct thread *td, struct linux_setgroups_args *args) newcred->cr_ngroups = 1; setsugid(p); - p->p_ucred = newcred; + proc_set_cred(p, newcred); PROC_UNLOCK(p); crfree(oldcred); error = 0; diff --git a/sys/compat/linux/linux_uid16.c b/sys/compat/linux/linux_uid16.c index 61f3030049e6..8c7c7606920a 100644 --- a/sys/compat/linux/linux_uid16.c +++ b/sys/compat/linux/linux_uid16.c @@ -213,7 +213,7 @@ linux_setgroups16(struct thread *td, struct linux_setgroups16_args *args) newcred->cr_ngroups = 1; setsugid(td->td_proc); - p->p_ucred = newcred; + proc_set_cred(p, newcred); PROC_UNLOCK(p); crfree(oldcred); error = 0; diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 57e2ee91caf0..82cf63f5f354 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -432,6 +432,7 @@ proc0_init(void *dummy __unused) { struct proc *p; struct thread *td; + struct ucred *newcred; vm_paddr_t pageablemem; int i; @@ -508,19 +509,20 @@ proc0_init(void *dummy __unused) callout_init(&td->td_slpcallout, CALLOUT_MPSAFE); /* Create credentials. */ - p->p_ucred = crget(); - p->p_ucred->cr_ngroups = 1; /* group 0 */ - p->p_ucred->cr_uidinfo = uifind(0); - p->p_ucred->cr_ruidinfo = uifind(0); - p->p_ucred->cr_prison = &prison0; - p->p_ucred->cr_loginclass = loginclass_find("default"); + newcred = crget(); + newcred->cr_ngroups = 1; /* group 0 */ + newcred->cr_uidinfo = uifind(0); + newcred->cr_ruidinfo = uifind(0); + newcred->cr_prison = &prison0; + newcred->cr_loginclass = loginclass_find("default"); + proc_set_cred(p, newcred); #ifdef AUDIT - audit_cred_kproc0(p->p_ucred); + audit_cred_kproc0(newcred); #endif #ifdef MAC - mac_cred_create_swapper(p->p_ucred); + mac_cred_create_swapper(newcred); #endif - td->td_ucred = crhold(p->p_ucred); + td->td_ucred = crhold(newcred); /* Create sigacts. */ p->p_sigacts = sigacts_alloc(); @@ -836,7 +838,7 @@ create_init(const void *udata __unused) #ifdef AUDIT audit_cred_proc1(newcred); #endif - initproc->p_ucred = newcred; + proc_set_cred(initproc, newcred); PROC_UNLOCK(initproc); sx_xunlock(&proctree_lock); crfree(oldcred); diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 5b80f5c6a147..25335cec5da5 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -725,7 +725,7 @@ do_execve(td, args, mac_p) */ change_svuid(newcred, newcred->cr_uid); change_svgid(newcred, newcred->cr_gid); - p->p_ucred = newcred; + proc_set_cred(p, newcred); } else { if (oldcred->cr_uid == oldcred->cr_ruid && oldcred->cr_gid == oldcred->cr_rgid) @@ -751,7 +751,7 @@ do_execve(td, args, mac_p) PROC_LOCK(p); change_svuid(newcred, newcred->cr_uid); change_svgid(newcred, newcred->cr_gid); - p->p_ucred = newcred; + proc_set_cred(p, newcred); } } diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index ef8dcb2d3802..e988422e13f9 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -916,7 +916,7 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options) * Free credentials, arguments, and sigacts. */ crfree(p->p_ucred); - p->p_ucred = NULL; + proc_set_cred(p, NULL); pargs_drop(p->p_args); p->p_args = NULL; sigacts_free(p->p_sigacts); diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 2c83422008a8..ae86fe17a407 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -410,7 +410,8 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2, bzero(&p2->p_startzero, __rangeof(struct proc, p_startzero, p_endzero)); - p2->p_ucred = crhold(td->td_ucred); + crhold(td->td_ucred); + proc_set_cred(p2, td->td_ucred); /* Tell the prison that we exist. */ prison_proc_hold(p2->p_ucred->cr_prison); @@ -869,7 +870,7 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp, * XXX: This is ugly; when we copy resource usage, we need to bump * per-cred resource counters. */ - newproc->p_ucred = p1->p_ucred; + proc_set_cred(newproc, p1->p_ucred); /* * Initialize resource accounting for the child process. diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index 592c177d01ac..e61bb4789314 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -2445,7 +2445,7 @@ do_jail_attach(struct thread *td, struct prison *pr) setsugid(p); crcopy(newcred, oldcred); newcred->cr_prison = pr; - p->p_ucred = newcred; + proc_set_cred(p, newcred); PROC_UNLOCK(p); #ifdef RACCT racct_proc_ucred_changed(p, oldcred, newcred); diff --git a/sys/kern/kern_loginclass.c b/sys/kern/kern_loginclass.c index c0946efe8392..62e642140c45 100644 --- a/sys/kern/kern_loginclass.c +++ b/sys/kern/kern_loginclass.c @@ -221,7 +221,7 @@ sys_setloginclass(struct thread *td, struct setloginclass_args *uap) PROC_LOCK(p); oldcred = crcopysafe(p, newcred); newcred->cr_loginclass = newlc; - p->p_ucred = newcred; + proc_set_cred(p, newcred); PROC_UNLOCK(p); #ifdef RACCT racct_proc_ucred_changed(p, oldcred, newcred); diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index 1043915658be..72c9f652fed4 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -579,7 +579,7 @@ sys_setuid(struct thread *td, struct setuid_args *uap) change_euid(newcred, uip); setsugid(p); } - p->p_ucred = newcred; + proc_set_cred(p, newcred); PROC_UNLOCK(p); #ifdef RACCT racct_proc_ucred_changed(p, oldcred, newcred); @@ -638,7 +638,7 @@ sys_seteuid(struct thread *td, struct seteuid_args *uap) change_euid(newcred, euip); setsugid(p); } - p->p_ucred = newcred; + proc_set_cred(p, newcred); PROC_UNLOCK(p); uifree(euip); crfree(oldcred); @@ -738,7 +738,7 @@ sys_setgid(struct thread *td, struct setgid_args *uap) change_egid(newcred, gid); setsugid(p); } - p->p_ucred = newcred; + proc_set_cred(p, newcred); PROC_UNLOCK(p); crfree(oldcred); return (0); @@ -784,7 +784,7 @@ sys_setegid(struct thread *td, struct setegid_args *uap) change_egid(newcred, egid); setsugid(p); } - p->p_ucred = newcred; + proc_set_cred(p, newcred); PROC_UNLOCK(p); crfree(oldcred); return (0); @@ -864,7 +864,7 @@ kern_setgroups(struct thread *td, u_int ngrp, gid_t *groups) crsetgroups_locked(newcred, ngrp, groups); } setsugid(p); - p->p_ucred = newcred; + proc_set_cred(p, newcred); PROC_UNLOCK(p); crfree(oldcred); return (0); @@ -927,7 +927,7 @@ sys_setreuid(register struct thread *td, struct setreuid_args *uap) change_svuid(newcred, newcred->cr_uid); setsugid(p); } - p->p_ucred = newcred; + proc_set_cred(p, newcred); PROC_UNLOCK(p); #ifdef RACCT racct_proc_ucred_changed(p, oldcred, newcred); @@ -994,7 +994,7 @@ sys_setregid(register struct thread *td, struct setregid_args *uap) change_svgid(newcred, newcred->cr_groups[0]); setsugid(p); } - p->p_ucred = newcred; + proc_set_cred(p, newcred); PROC_UNLOCK(p); crfree(oldcred); return (0); @@ -1068,7 +1068,7 @@ sys_setresuid(register struct thread *td, struct setresuid_args *uap) change_svuid(newcred, suid); setsugid(p); } - p->p_ucred = newcred; + proc_set_cred(p, newcred); PROC_UNLOCK(p); #ifdef RACCT racct_proc_ucred_changed(p, oldcred, newcred); @@ -1147,7 +1147,7 @@ sys_setresgid(register struct thread *td, struct setresgid_args *uap) change_svgid(newcred, sgid); setsugid(p); } - p->p_ucred = newcred; + proc_set_cred(p, newcred); PROC_UNLOCK(p); crfree(oldcred); return (0); @@ -1953,6 +1953,31 @@ cred_update_thread(struct thread *td) crfree(cred); } +/* + * Change process credentials. + * Callers are responsible for providing the reference for current credentials + * and for freeing old ones. + * + * Process has to be locked except when it does not have credentials (as it + * should not be visible just yet) or when newcred is NULL (as this can be + * only used when the process is about to be freed, at which point it should + * not be visible anymore). + */ +struct ucred * +proc_set_cred(struct proc *p, struct ucred *newcred) +{ + struct ucred *oldcred; + + if (newcred == NULL) + MPASS(p->p_state == PRS_ZOMBIE); + else if (p->p_ucred != NULL) + PROC_LOCK_ASSERT(p, MA_OWNED); + + oldcred = p->p_ucred; + p->p_ucred = newcred; + return (oldcred); +} + struct ucred * crcopysafe(struct proc *p, struct ucred *cr) { diff --git a/sys/kern/sys_capability.c b/sys/kern/sys_capability.c index 79975513a4c7..b0b77fe0a9b3 100644 --- a/sys/kern/sys_capability.c +++ b/sys/kern/sys_capability.c @@ -104,7 +104,7 @@ sys_cap_enter(struct thread *td, struct cap_enter_args *uap) PROC_LOCK(p); oldcred = crcopysafe(p, newcred); newcred->cr_flags |= CRED_FLAG_CAPMODE; - p->p_ucred = newcred; + proc_set_cred(p, newcred); PROC_UNLOCK(p); crfree(oldcred); return (0); diff --git a/sys/security/audit/audit_syscalls.c b/sys/security/audit/audit_syscalls.c index 6ef606b777ac..90d811ddbaf4 100644 --- a/sys/security/audit/audit_syscalls.c +++ b/sys/security/audit/audit_syscalls.c @@ -461,7 +461,7 @@ sys_auditon(struct thread *td, struct auditon_args *uap) udata.au_aupinfo.ap_mask.am_success; newcred->cr_audit.ai_mask.am_failure = udata.au_aupinfo.ap_mask.am_failure; - tp->p_ucred = newcred; + proc_set_cred(tp, newcred); PROC_UNLOCK(tp); crfree(oldcred); break; @@ -600,7 +600,7 @@ sys_setauid(struct thread *td, struct setauid_args *uap) if (error) goto fail; newcred->cr_audit.ai_auid = id; - td->td_proc->p_ucred = newcred; + proc_set_cred(td->td_proc, newcred); PROC_UNLOCK(td->td_proc); crfree(oldcred); return (0); @@ -671,7 +671,7 @@ sys_setaudit(struct thread *td, struct setaudit_args *uap) newcred->cr_audit.ai_termid.at_addr[0] = ai.ai_termid.machine; newcred->cr_audit.ai_termid.at_port = ai.ai_termid.port; newcred->cr_audit.ai_termid.at_type = AU_IPv4; - td->td_proc->p_ucred = newcred; + proc_set_cred(td->td_proc, newcred); PROC_UNLOCK(td->td_proc); crfree(oldcred); return (0); @@ -728,7 +728,7 @@ sys_setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) if (error) goto fail; newcred->cr_audit = aia; - td->td_proc->p_ucred = newcred; + proc_set_cred(td->td_proc, newcred); PROC_UNLOCK(td->td_proc); crfree(oldcred); return (0); diff --git a/sys/security/mac/mac_syscalls.c b/sys/security/mac/mac_syscalls.c index f084ea48a183..304d31359183 100644 --- a/sys/security/mac/mac_syscalls.c +++ b/sys/security/mac/mac_syscalls.c @@ -208,7 +208,7 @@ sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) setsugid(p); crcopy(newcred, oldcred); mac_cred_relabel(newcred, intlabel); - p->p_ucred = newcred; + proc_set_cred(p, newcred); PROC_UNLOCK(p); crfree(oldcred); diff --git a/sys/security/mac_lomac/mac_lomac.c b/sys/security/mac_lomac/mac_lomac.c index 32ae2239a2d3..5607940cbdc0 100644 --- a/sys/security/mac_lomac/mac_lomac.c +++ b/sys/security/mac_lomac/mac_lomac.c @@ -2255,7 +2255,7 @@ lomac_thread_userret(struct thread *td) crcopy(newcred, oldcred); crhold(newcred); lomac_copy(&subj->mac_lomac, SLOT(newcred->cr_label)); - p->p_ucred = newcred; + proc_set_cred(p, newcred); crfree(oldcred); dodrop = 1; out: diff --git a/sys/sys/ucred.h b/sys/sys/ucred.h index a6531c426c4e..2b42b018cd54 100644 --- a/sys/sys/ucred.h +++ b/sys/sys/ucred.h @@ -106,6 +106,7 @@ void crcopy(struct ucred *dest, struct ucred *src); struct ucred *crcopysafe(struct proc *p, struct ucred *cr); struct ucred *crdup(struct ucred *cr); void cred_update_thread(struct thread *td); +struct ucred *proc_set_cred(struct proc *p, struct ucred *cr); void crfree(struct ucred *cr); struct ucred *crget(void); struct ucred *crhold(struct ucred *cr);