-/* $OpenBSD: trap.c,v 1.71 2014/03/30 21:54:48 guenther Exp $ */
+/* $OpenBSD: trap.c,v 1.72 2014/04/18 11:51:16 guenther Exp $ */
/* $NetBSD: trap.c,v 1.52 2000/05/24 16:48:33 thorpej Exp $ */
/*-
ucode = 0;
v = 0;
user = (framep->tf_regs[FRAME_PS] & ALPHA_PSL_USERMODE) != 0;
- if (user)
+ if (user) {
p->p_md.md_tf = framep;
+ refreshcreds(p);
+ }
switch (entry) {
case ALPHA_KENTRY_UNA:
-/* $OpenBSD: trap.c,v 1.35 2014/03/30 21:54:48 guenther Exp $ */
+/* $OpenBSD: trap.c,v 1.36 2014/04/18 11:51:16 guenther Exp $ */
/* $NetBSD: trap.c,v 1.2 2003/05/04 23:51:56 fvdl Exp $ */
/*-
if (!KERNELMODE(frame->tf_cs, frame->tf_rflags)) {
type |= T_USER;
p->p_md.md_regs = frame;
- }
+ } else /* if (type != T_NMI) */
+ refreshcreds(p);
switch (type) {
-/* $OpenBSD: fault.c,v 1.15 2014/03/30 21:54:49 guenther Exp $ */
+/* $OpenBSD: fault.c,v 1.16 2014/04/18 11:51:16 guenther Exp $ */
/* $NetBSD: fault.c,v 1.46 2004/01/21 15:39:21 skrll Exp $ */
/*
* the MMU.
*/
- if (user)
+ if (user) {
p->p_addr->u_pcb.pcb_tf = tf;
+ refreshcreds(p);
+ }
/*
* Make sure the Program Counter is sane. We could fall foul of
-/* $OpenBSD: trap.c,v 1.129 2014/04/08 09:34:23 mpi Exp $ */
+/* $OpenBSD: trap.c,v 1.130 2014/04/18 11:51:16 guenther Exp $ */
/*
* Copyright (c) 1998-2004 Michael Shalayeff
mtctl(frame->tf_eiem, CR_EIEM);
}
+ if (type & T_USER)
+ refreshcreds(p);
+
switch (type) {
case T_NONEXIST:
case T_NONEXIST | T_USER:
-/* $OpenBSD: trap.c,v 1.35 2014/04/08 09:34:23 mpi Exp $ */
+/* $OpenBSD: trap.c,v 1.36 2014/04/18 11:51:16 guenther Exp $ */
/*
* Copyright (c) 2005 Michael Shalayeff
ssm(PSL_I, mask);
}
+ if (type & T_USER)
+ refreshcreds(p);
+
switch (type) {
case T_NONEXIST:
case T_NONEXIST | T_USER:
-/* $OpenBSD: trap.c,v 1.113 2014/03/26 05:23:42 guenther Exp $ */
+/* $OpenBSD: trap.c,v 1.114 2014/04/18 11:51:17 guenther Exp $ */
/* $NetBSD: trap.c,v 1.95 1996/05/05 06:50:02 mycroft Exp $ */
/*-
if (!KERNELMODE(frame->tf_cs, frame->tf_eflags)) {
type |= T_USER;
p->p_md.md_regs = frame;
- }
+ } else if (type != T_NMI)
+ refreshcreds(p);
switch (type) {
-/* $OpenBSD: trap.c,v 1.89 2014/03/26 05:23:42 guenther Exp $ */
+/* $OpenBSD: trap.c,v 1.90 2014/04/18 11:51:17 guenther Exp $ */
/*
* Copyright (c) 2004, Miodrag Vallat.
* Copyright (c) 1998 Steve Murphree, Jr.
if (USERMODE(frame->tf_epsr)) {
type += T_USER;
p->p_md.md_tf = frame; /* for ptrace/signals */
+ refreshcreds(p);
}
fault_type = SI_NOINFO;
fault_code = 0;
if (USERMODE(frame->tf_epsr)) {
type += T_USER;
p->p_md.md_tf = frame; /* for ptrace/signals */
+ refreshcreds(p);
}
if (sig != 0)
-/* $OpenBSD: trap.c,v 1.92 2014/04/09 21:10:35 miod Exp $ */
+/* $OpenBSD: trap.c,v 1.93 2014/04/18 11:51:17 guenther Exp $ */
/*
* Copyright (c) 1988 University of Utah.
atomic_add_int(&uvmexp.traps, 1);
if (USERMODE(trapframe->sr)) {
type |= T_USER;
+ refreshcreds(p);
}
/*
-/* $OpenBSD: trap.c,v 1.95 2014/03/26 05:23:42 guenther Exp $ */
+/* $OpenBSD: trap.c,v 1.96 2014/04/18 11:51:17 guenther Exp $ */
/* $NetBSD: trap.c,v 1.3 1996/10/13 03:31:37 christos Exp $ */
/*
if (frame->srr1 & PSL_PR) {
type |= EXC_USER;
+ refreshcreds(p);
}
switch (type) {
-/* $OpenBSD: trap.c,v 1.24 2014/03/30 21:54:49 guenther Exp $ */
+/* $OpenBSD: trap.c,v 1.25 2014/04/18 11:51:17 guenther Exp $ */
/* $NetBSD: exception.c,v 1.32 2006/09/04 23:57:52 uwe Exp $ */
/* $NetBSD: syscall.c,v 1.6 2006/03/07 07:21:50 thorpej Exp $ */
goto do_panic;
KDASSERT(p->p_md.md_regs == tf); /* check exception depth */
expevt |= EXP_USER;
+ refreshcreds(p);
}
switch (expevt) {
usermode = !KERNELMODE(tf->tf_ssr);
if (usermode) {
KDASSERT(p->p_md.md_regs == tf);
+ refreshcreds(p);
} else {
KDASSERT(p == NULL || /* idle */
p == &proc0 || /* kthread */
p->p_md.md_astpending = 0;
uvmexp.softs++;
+ refreshcreds(p);
if (p->p_flag & P_OWEUPC) {
ADDUPROF(p);
}
-/* $OpenBSD: trap.c,v 1.18 2014/03/26 05:23:42 guenther Exp $ */
+/* $OpenBSD: trap.c,v 1.19 2014/04/18 11:51:17 guenther Exp $ */
/* OpenBSD: trap.c,v 1.42 2004/12/06 20:12:25 miod Exp */
/*
p = &proc0;
pcb = &p->p_addr->u_pcb;
p->p_md.md_tf = tf; /* for ptrace/signals */
+ refreshcreds(p);
switch (type) {
-/* $OpenBSD: trap.c,v 1.64 2014/03/26 05:23:42 guenther Exp $ */
+/* $OpenBSD: trap.c,v 1.65 2014/04/18 11:51:17 guenther Exp $ */
/* $NetBSD: trap.c,v 1.58 1997/09/12 08:55:01 pk Exp $ */
/*
p = &proc0;
pcb = &p->p_addr->u_pcb;
p->p_md.md_tf = tf; /* for ptrace/signals */
+ refreshcreds(p);
switch (type) {
-/* $OpenBSD: trap.c,v 1.80 2014/03/30 21:54:49 guenther Exp $ */
+/* $OpenBSD: trap.c,v 1.81 2014/04/18 11:51:17 guenther Exp $ */
/* $NetBSD: trap.c,v 1.73 2001/08/09 01:03:01 eeh Exp $ */
/*
p = &proc0;
pcb = &p->p_addr->u_pcb;
p->p_md.md_tf = tf; /* for ptrace/signals */
+ refreshcreds(p);
switch (type) {
-/* $OpenBSD: trap.c,v 1.50 2014/03/30 21:54:49 guenther Exp $ */
+/* $OpenBSD: trap.c,v 1.51 2014/04/18 11:51:17 guenther Exp $ */
/* $NetBSD: trap.c,v 1.47 1999/08/21 19:26:20 matt Exp $ */
/*
* Copyright (c) 1994 Ludd, University of Lule}, Sweden.
if ((umode = USERMODE(frame))) {
type |= T_USER;
p->p_addr->u_pcb.framep = frame;
+ refreshcreds(p);
}
type&=~(T_WRITE|T_PTEFETCH);
-/* $OpenBSD: systrace.c,v 1.66 2014/03/30 21:54:48 guenther Exp $ */
+/* $OpenBSD: systrace.c,v 1.67 2014/04/18 11:51:17 guenther Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
int systraceclose(dev_t, int, int, struct proc *);
int systraceioctl(dev_t, u_long, caddr_t, int, struct proc *);
-uid_t systrace_seteuid(struct proc *, uid_t);
-gid_t systrace_setegid(struct proc *, gid_t);
int systracef_read(struct file *, off_t *, struct uio *, struct ucred *);
int systracef_write(struct file *, off_t *, struct uio *, struct ucred *);
int systracef_ioctl(struct file *, u_long, caddr_t, struct proc *p);
u_int16_t seqnr; /* expected reply sequence number */
uid_t seteuid;
- uid_t saveuid;
gid_t setegid;
- gid_t savegid;
int isscript;
char scriptname[MAXPATHLEN];
struct str_policy *strpolicy;
struct fsystrace *fst = NULL;
struct emul *oldemul;
- struct ucred *uc;
- uid_t olduid;
- gid_t oldgid;
int policy, error = 0, report = 0, maycontrol = 0, issuser = 0;
+ uid_t old_ruid = p->p_ucred->cr_ruid;
+ gid_t old_rgid = p->p_ucred->cr_rgid;
systrace_lock();
strp = p->p_systrace;
maycontrol = 1;
issuser = 1;
} else if (!ISSET(pr->ps_flags, PS_SUGID | PS_SUGIDEXEC)) {
- maycontrol = fst->p_ruid == p->p_ucred->cr_ruid &&
- fst->p_rgid == p->p_ucred->cr_rgid;
+ maycontrol = fst->p_ruid == old_ruid &&
+ fst->p_rgid == old_rgid;
}
if (!maycontrol) {
goto out_unlock;
oldemul = pr->ps_emul;
- uc = p->p_ucred;
- olduid = uc->cr_ruid;
- oldgid = uc->cr_rgid;
/* Elevate privileges as desired */
- if (issuser) {
- if (ISSET(strp->flags, STR_PROC_SETEUID))
- strp->saveuid = systrace_seteuid(p, strp->seteuid);
- if (ISSET(strp->flags, STR_PROC_SETEGID))
- strp->savegid = systrace_setegid(p, strp->setegid);
- } else
- CLR(strp->flags, STR_PROC_SETEUID|STR_PROC_SETEGID);
+ if (issuser && ISSET(strp->flags, STR_PROC_SETEUID|STR_PROC_SETEGID)) {
+ struct ucred *uc, *newcred;
+
+ uc = p->p_ucred;
+ newcred = NULL;
+ if (ISSET(strp->flags, STR_PROC_SETEUID) &&
+ uc->cr_uid != strp->seteuid) {
+ newcred = crdup(uc);
+ newcred->cr_uid = strp->seteuid;
+ }
+ if (ISSET(strp->flags, STR_PROC_SETEGID) &&
+ uc->cr_gid != strp->setegid) {
+ if (newcred == NULL)
+ newcred = crdup(uc);
+ newcred->cr_gid = strp->setegid;
+ }
+ if (newcred != NULL) {
+ p->p_ucred = newcred;
+ crfree(uc);
+ atomic_setbits_int(&pr->ps_flags, PS_SUGID);
+ }
+ }
rw_exit_write(&fst->lock);
error = (*callp->sy_call)(p, v, retval);
+ /* reset the credentials on the thread */
+ refreshcreds(p);
+
/* Return to old privileges */
systrace_lock();
if ((strp = p->p_systrace) == NULL) {
return (error);
}
- if (issuser) {
- if (ISSET(strp->flags, STR_PROC_SETEUID)) {
- if (uc->cr_uid == strp->seteuid)
- systrace_seteuid(p, strp->saveuid);
- CLR(strp->flags, STR_PROC_SETEUID);
- }
- if (ISSET(strp->flags, STR_PROC_SETEGID)) {
- if (uc->cr_gid == strp->setegid)
- systrace_setegid(p, strp->savegid);
- CLR(strp->flags, STR_PROC_SETEGID);
- }
- }
-
systrace_replacefree(strp);
if (ISSET(pr->ps_flags, PS_SUGID | PS_SUGIDEXEC)) {
}
/* Report if effective uid or gid changed */
- if (olduid != p->p_ucred->cr_ruid ||
- oldgid != p->p_ucred->cr_rgid) {
+ if (old_ruid != pr->ps_ucred->cr_ruid ||
+ old_rgid != pr->ps_ucred->cr_rgid) {
systrace_msg_ugid(fst, strp);
REACQUIRE_LOCK;
return (error);
}
-uid_t
-systrace_seteuid(struct proc *p, uid_t euid)
-{
- struct ucred *uc = p->p_ucred;
- uid_t oeuid = uc->cr_uid;
-
- if (oeuid == euid)
- return (oeuid);
-
- /*
- * Copy credentials so other references do not see our changes.
- */
- p->p_ucred = uc = crcopy(uc);
- uc->cr_uid = euid;
- atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
-
- return (oeuid);
-}
-
-gid_t
-systrace_setegid(struct proc *p, gid_t egid)
-{
- struct ucred *uc = p->p_ucred;
- gid_t oegid = uc->cr_gid;
-
- if (oegid == egid)
- return (oegid);
-
- /*
- * Copy credentials so other references do not see our changes.
- */
- p->p_ucred = uc = crcopy(uc);
- uc->cr_gid = egid;
- atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
-
- return (oegid);
-}
-
/* Called with fst locked */
int
systrace_attach(struct fsystrace *fst, pid_t pid)
{
int error = 0;
- struct proc *proc, *p = curproc;
+ struct proc *p = curproc;
+ struct proc *t; /* target thread */
+ struct process *tr; /* target process */
struct str_process *newstrp;
- if ((proc = pfind(pid)) == NULL || (proc->p_flag & P_THREAD)) {
+ if ((t = pfind(pid)) == NULL || (t->p_flag & P_THREAD)) {
error = ESRCH;
goto out;
}
+ tr = t->p_p;
- if (ISSET(proc->p_p->ps_flags, PS_INEXEC)) {
+ if (ISSET(tr->ps_flags, PS_INEXEC)) {
error = EAGAIN;
goto out;
}
* You can't attach to a process if:
* (1) it's the process that's doing the attaching,
*/
- if (proc->p_p == p->p_p) {
+ if (tr == p->p_p) {
error = EINVAL;
goto out;
}
/*
* (2) it's a system process
*/
- if (ISSET(proc->p_flag, P_SYSTEM)) {
+ if (ISSET(t->p_flag, P_SYSTEM)) {
error = EPERM;
goto out;
}
/*
* (3) it's being traced already
*/
- if (ISSET(proc->p_flag, P_SYSTRACE)) {
+ if (ISSET(t->p_flag, P_SYSTRACE)) {
error = EBUSY;
goto out;
}
* special privileges using setuid() from being
* traced. This is good security.]
*/
- if ((proc->p_ucred->cr_ruid != p->p_ucred->cr_ruid ||
- ISSET(proc->p_p->ps_flags, PS_SUGID | PS_SUGIDEXEC)) &&
+ if ((tr->ps_ucred->cr_ruid != p->p_ucred->cr_ruid ||
+ ISSET(tr->ps_flags, PS_SUGID | PS_SUGIDEXEC)) &&
(error = suser(p, 0)) != 0)
goto out;
* compiled with permanently insecure mode turned
* on.
*/
- if ((proc->p_p->ps_pid == 1) && (securelevel > -1)) {
+ if ((tr->ps_pid == 1) && (securelevel > -1)) {
error = EPERM;
goto out;
}
newstrp = systrace_getproc();
- systrace_insert_process(fst, proc, newstrp);
+ systrace_insert_process(fst, t, newstrp);
out:
return (error);
systrace_msg_ugid(struct fsystrace *fst, struct str_process *strp)
{
struct str_msg_ugid *msg_ugid = &strp->msg.msg_data.msg_ugid;
- struct proc *p = strp->proc;
+ struct ucred *uc = strp->proc->p_p->ps_ucred;
- msg_ugid->uid = p->p_ucred->cr_ruid;
- msg_ugid->gid = p->p_ucred->cr_rgid;
+ msg_ugid->uid = uc->cr_ruid;
+ msg_ugid->gid = uc->cr_rgid;
return (systrace_make_msg(strp, SYSTR_MSG_UGID));
}
-/* $OpenBSD: init_main.c,v 1.210 2014/03/31 19:37:15 kettenis Exp $ */
+/* $OpenBSD: init_main.c,v 1.211 2014/04/18 11:51:17 guenther Exp $ */
/* $NetBSD: init_main.c,v 1.84.4.1 1996/06/02 09:08:06 mrg Exp $ */
/*
pr->ps_ucred = crget();
pr->ps_ucred->cr_ngroups = 1; /* group 0 */
+ p->p_ucred = pr->ps_ucred; /* prime the thread's cache */
+ crhold(p->p_ucred);
+
/* Initialize signal state for process 0. */
signal_init();
pr->ps_sigacts = &sigacts0;
-/* $OpenBSD: kern_exec.c,v 1.140 2014/03/30 21:54:48 guenther Exp $ */
+/* $OpenBSD: kern_exec.c,v 1.141 2014/04/18 11:51:17 guenther Exp $ */
/* $NetBSD: kern_exec.c,v 1.75 1996/02/09 18:59:28 christos Exp $ */
/*-
} else
atomic_clearbits_int(&pr->ps_flags, PS_SUGID);
- /* reset the saved ugids */
+ /*
+ * Reset the saved ugids and update the process's copy of the
+ * creds if the creds have been changed
+ */
if (cred->cr_uid != cred->cr_svuid ||
cred->cr_gid != cred->cr_svgid) {
/* make sure we have unshared ucreds */
cred->cr_svgid = cred->cr_gid;
}
+ if (pr->ps_ucred != cred) {
+ struct ucred *ocred;
+
+ ocred = pr->ps_ucred;
+ crhold(cred);
+ pr->ps_ucred = cred;
+ crfree(ocred);
+ }
+
if (pr->ps_flags & PS_SUGIDEXEC) {
int i, s = splclock();
-/* $OpenBSD: kern_exit.c,v 1.139 2014/04/17 14:52:50 guenther Exp $ */
+/* $OpenBSD: kern_exit.c,v 1.140 2014/04/18 11:51:17 guenther Exp $ */
/* $NetBSD: kern_exit.c,v 1.39 1996/04/22 01:38:25 christos Exp $ */
/*
void
proc_free(struct proc *p)
{
+ crfree(p->p_ucred);
pool_put(&proc_pool, p);
nthreads--;
}
-/* $OpenBSD: kern_fork.c,v 1.162 2014/03/30 21:54:48 guenther Exp $ */
+/* $OpenBSD: kern_fork.c,v 1.163 2014/04/18 11:51:17 guenther Exp $ */
/* $NetBSD: kern_fork.c,v 1.29 1996/02/09 18:59:34 christos Exp $ */
/*
(caddr_t)&pr->ps_endcopy - (caddr_t)&pr->ps_startcopy);
/* post-copy fixups */
- pr->ps_ucred = parent->ps_ucred;
+ pr->ps_ucred = p->p_ucred;
crhold(pr->ps_ucred);
+ KASSERT(p->p_ucred->cr_ref >= 3); /* fork thr, new thr, new process */
pr->ps_limit->p_refcnt++;
/* bump references to the text vnode (for procfs) */
(caddr_t)&p->p_endzero - (caddr_t)&p->p_startzero);
memcpy(&p->p_startcopy, &curp->p_startcopy,
(caddr_t)&p->p_endcopy - (caddr_t)&p->p_startcopy);
+ crhold(p->p_ucred);
/*
* Initialize the timeouts.
-/* $OpenBSD: kern_prot.c,v 1.59 2014/03/30 21:54:48 guenther Exp $ */
+/* $OpenBSD: kern_prot.c,v 1.60 2014/04/18 11:51:17 guenther Exp $ */
/* $NetBSD: kern_prot.c,v 1.33 1996/02/09 18:59:42 christos Exp $ */
/*
# include <machine/tcb.h>
#endif
-/* ARGSUSED */
+inline void
+crset(struct ucred *newcr, const struct ucred *cr)
+{
+ KASSERT(cr->cr_ref > 0);
+ memcpy(
+ (char *)newcr + offsetof(struct ucred, cr_startcopy),
+ (const char *)cr + offsetof(struct ucred, cr_startcopy),
+ sizeof(*cr) - offsetof(struct ucred, cr_startcopy));
+}
+
int
sys_getpid(struct proc *p, void *v, register_t *retval)
{
return (0);
}
-/* ARGSUSED */
int
sys_getthrid(struct proc *p, void *v, register_t *retval)
{
return (0);
}
-/* ARGSUSED */
int
sys_getppid(struct proc *p, void *v, register_t *retval)
{
return (0);
}
-/* ARGSUSED */
int
sys_getuid(struct proc *p, void *v, register_t *retval)
{
return (0);
}
-/* ARGSUSED */
int
sys_geteuid(struct proc *p, void *v, register_t *retval)
{
return (0);
}
-/* ARGSUSED */
int
sys_issetugid(struct proc *p, void *v, register_t *retval)
{
return (0);
}
-/* ARGSUSED */
int
sys_getgid(struct proc *p, void *v, register_t *retval)
{
* via getgroups. This syscall exists because it is somewhat painful to do
* correctly in a library function.
*/
-/* ARGSUSED */
int
sys_getegid(struct proc *p, void *v, register_t *retval)
{
return (0);
}
-/* ARGSUSED */
int
sys_setsid(struct proc *p, void *v, register_t *retval)
{
* there must exist some pid in same session having pgid (EPERM)
* pid must not be session leader (EPERM)
*/
-/* ARGSUSED */
int
sys_setpgid(struct proc *curp, void *v, register_t *retval)
{
return (error);
}
-/* ARGSUSED */
int
sys_getresuid(struct proc *p, void *v, register_t *retval)
{
return (error1 ? error1 : error2 ? error2 : error3);
}
-/* ARGSUSED */
int
sys_setresuid(struct proc *p, void *v, register_t *retval)
{
syscallarg(uid_t) euid;
syscallarg(uid_t) suid;
} */ *uap = v;
- struct ucred *uc = p->p_ucred;
+ struct process *pr = p->p_p;
+ struct ucred *pruc, *newcred, *uc = p->p_ucred;
uid_t ruid, euid, suid;
int error;
euid = SCARG(uap, euid);
suid = SCARG(uap, suid);
- if ((ruid == -1 || ruid == uc->cr_ruid) &&
- (euid == -1 || euid == uc->cr_uid) &&
- (suid == -1 || suid == uc->cr_svuid))
+ /*
+ * make permission checks against the thread's ucred,
+ * but the actual changes will be to the process's ucred
+ */
+ pruc = pr->ps_ucred;
+ if ((ruid == (uid_t)-1 || ruid == pruc->cr_ruid) &&
+ (euid == (uid_t)-1 || euid == pruc->cr_uid) &&
+ (suid == (uid_t)-1 || suid == pruc->cr_svuid))
return (0); /* no change */
/*
/*
* Copy credentials so other references do not see our changes.
+ * ps_ucred may change during the crget().
*/
- p->p_ucred = uc = crcopy(uc);
+ newcred = crget();
+ pruc = pr->ps_ucred;
+ crset(newcred, pruc);
/*
* Note that unlike the other set*uid() calls, each
* uid type is set independently of the others.
*/
- if (ruid != (uid_t)-1 && ruid != uc->cr_ruid) {
- /*
- * Transfer proc count to new user.
- */
- (void)chgproccnt(uc->cr_ruid, -1);
- (void)chgproccnt(ruid, 1);
- uc->cr_ruid = ruid;
- }
+ if (ruid != (uid_t)-1)
+ newcred->cr_ruid = ruid;
if (euid != (uid_t)-1)
- uc->cr_uid = euid;
+ newcred->cr_uid = euid;
if (suid != (uid_t)-1)
- uc->cr_svuid = suid;
-
+ newcred->cr_svuid = suid;
+ pr->ps_ucred = newcred;
atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
+
+ /* now that we can sleep, transfer proc count to new user */
+ if (ruid != (uid_t)-1 && ruid != pruc->cr_ruid) {
+ chgproccnt(pruc->cr_ruid, -1);
+ chgproccnt(ruid, 1);
+ }
+ crfree(pruc);
+
return (0);
}
-/* ARGSUSED */
int
sys_getresgid(struct proc *p, void *v, register_t *retval)
{
return (error1 ? error1 : error2 ? error2 : error3);
}
-/* ARGSUSED */
int
sys_setresgid(struct proc *p, void *v, register_t *retval)
{
syscallarg(gid_t) egid;
syscallarg(gid_t) sgid;
} */ *uap = v;
- struct ucred *uc = p->p_ucred;
+ struct process *pr = p->p_p;
+ struct ucred *pruc, *newcred, *uc = p->p_ucred;
gid_t rgid, egid, sgid;
int error;
egid = SCARG(uap, egid);
sgid = SCARG(uap, sgid);
- if ((rgid == -1 || rgid == uc->cr_rgid) &&
- (egid == -1 || egid == uc->cr_gid) &&
- (sgid == -1 || sgid == uc->cr_svgid))
+ /*
+ * make permission checks against the thread's ucred,
+ * but the actual changes will be to the process's ucred
+ */
+ pruc = pr->ps_ucred;
+ if ((rgid == (gid_t)-1 || rgid == pruc->cr_rgid) &&
+ (egid == (gid_t)-1 || egid == pruc->cr_gid) &&
+ (sgid == (gid_t)-1 || sgid == pruc->cr_svgid))
return (0); /* no change */
/*
/*
* Copy credentials so other references do not see our changes.
+ * ps_ucred may change during the crget().
*/
- p->p_ucred = uc = crcopy(uc);
+ newcred = crget();
+ pruc = pr->ps_ucred;
+ crset(newcred, pruc);
/*
* Note that unlike the other set*gid() calls, each
* gid type is set independently of the others.
*/
if (rgid != (gid_t)-1)
- uc->cr_rgid = rgid;
+ newcred->cr_rgid = rgid;
if (egid != (gid_t)-1)
- uc->cr_gid = egid;
+ newcred->cr_gid = egid;
if (sgid != (gid_t)-1)
- uc->cr_svgid = sgid;
-
+ newcred->cr_svgid = sgid;
+ pr->ps_ucred = newcred;
atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
+ crfree(pruc);
return (0);
}
-/* ARGSUSED */
int
sys_setregid(struct proc *p, void *v, register_t *retval)
{
syscallarg(gid_t) rgid;
syscallarg(gid_t) egid;
} */ *uap = v;
- struct ucred *uc = p->p_ucred;
- struct sys_setresgid_args sresgidargs;
+ struct process *pr = p->p_p;
+ struct ucred *pruc, *newcred, *uc = p->p_ucred;
gid_t rgid, egid;
+ int error;
+
+ rgid = SCARG(uap, rgid);
+ egid = SCARG(uap, egid);
+
+ /*
+ * make permission checks against the thread's ucred,
+ * but the actual changes will be to the process's ucred
+ *
+ * The saved gid check here is complicated: we reset the
+ * saved gid to the real gid if the real gid is specified
+ * *and* either it's changing _or_ the saved gid won't equal
+ * the effective gid. So, the svgid *won't* change when
+ * the rgid isn't specified or when the rgid isn't changing
+ * and the svgid equals the requested egid.
+ */
+ pruc = pr->ps_ucred;
+ if ((rgid == (gid_t)-1 || rgid == pruc->cr_rgid) &&
+ (egid == (gid_t)-1 || egid == pruc->cr_gid) &&
+ (rgid == (gid_t)-1 || (rgid == pruc->cr_rgid &&
+ pruc->cr_svgid == (egid != (gid_t)-1 ? egid : pruc->cr_gid))))
+ return (0); /* no change */
+
+ /*
+ * Any of the real, effective, and saved gids may be changed
+ * to the current value of one of the three (root is not limited).
+ */
+ if (rgid != (gid_t)-1 &&
+ rgid != uc->cr_rgid &&
+ rgid != uc->cr_gid &&
+ rgid != uc->cr_svgid &&
+ (error = suser(p, 0)))
+ return (error);
+
+ if (egid != (gid_t)-1 &&
+ egid != uc->cr_rgid &&
+ egid != uc->cr_gid &&
+ egid != uc->cr_svgid &&
+ (error = suser(p, 0)))
+ return (error);
+
+ /*
+ * Copy credentials so other references do not see our changes.
+ * ps_ucred may change during the crget().
+ */
+ newcred = crget();
+ pruc = pr->ps_ucred;
+ crset(newcred, pruc);
- rgid = SCARG(&sresgidargs, rgid) = SCARG(uap, rgid);
- egid = SCARG(&sresgidargs, egid) = SCARG(uap, egid);
+ if (rgid != (gid_t)-1)
+ newcred->cr_rgid = rgid;
+ if (egid != (gid_t)-1)
+ newcred->cr_gid = egid;
/*
* The saved gid presents a bit of a dilemma, as it did not
* gid when the real gid is specified and either its value would
* change, or where the saved and effective gids are different.
*/
- if (rgid != (gid_t)-1 && (rgid != uc->cr_rgid ||
- uc->cr_svgid != (egid != (gid_t)-1 ? egid : uc->cr_gid)))
- SCARG(&sresgidargs, sgid) = rgid;
- else
- SCARG(&sresgidargs, sgid) = (gid_t)-1;
-
- return (sys_setresgid(p, &sresgidargs, retval));
+ if (rgid != (gid_t)-1 && (rgid != pruc->cr_rgid ||
+ pruc->cr_svgid != (egid != (gid_t)-1 ? egid : pruc->cr_gid)))
+ newcred->cr_svgid = rgid;
+ pr->ps_ucred = newcred;
+ atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
+ crfree(pruc);
+ return (0);
}
-/* ARGSUSED */
int
sys_setreuid(struct proc *p, void *v, register_t *retval)
{
syscallarg(uid_t) ruid;
syscallarg(uid_t) euid;
} */ *uap = v;
- struct ucred *uc = p->p_ucred;
- struct sys_setresuid_args sresuidargs;
+ struct process *pr = p->p_p;
+ struct ucred *pruc, *newcred, *uc = p->p_ucred;
uid_t ruid, euid;
+ int error;
+
+ ruid = SCARG(uap, ruid);
+ euid = SCARG(uap, euid);
- ruid = SCARG(&sresuidargs, ruid) = SCARG(uap, ruid);
- euid = SCARG(&sresuidargs, euid) = SCARG(uap, euid);
+ /*
+ * make permission checks against the thread's ucred,
+ * but the actual changes will be to the process's ucred
+ *
+ * The saved uid check here is complicated: we reset the
+ * saved uid to the real uid if the real uid is specified
+ * *and* either it's changing _or_ the saved uid won't equal
+ * the effective uid. So, the svuid *won't* change when
+ * the ruid isn't specified or when the ruid isn't changing
+ * and the svuid equals the requested euid.
+ */
+ pruc = pr->ps_ucred;
+ if ((ruid == (uid_t)-1 || ruid == pruc->cr_ruid) &&
+ (euid == (uid_t)-1 || euid == pruc->cr_uid) &&
+ (ruid == (uid_t)-1 || (ruid == pruc->cr_ruid &&
+ pruc->cr_svuid == (euid != (uid_t)-1 ? euid : pruc->cr_uid))))
+ return (0); /* no change */
+
+ /*
+ * Any of the real, effective, and saved uids may be changed
+ * to the current value of one of the three (root is not limited).
+ */
+ if (ruid != (uid_t)-1 &&
+ ruid != uc->cr_ruid &&
+ ruid != uc->cr_uid &&
+ ruid != uc->cr_svuid &&
+ (error = suser(p, 0)))
+ return (error);
+
+ if (euid != (uid_t)-1 &&
+ euid != uc->cr_ruid &&
+ euid != uc->cr_uid &&
+ euid != uc->cr_svuid &&
+ (error = suser(p, 0)))
+ return (error);
+
+ /*
+ * Copy credentials so other references do not see our changes.
+ * ps_ucred may change during the crget().
+ */
+ newcred = crget();
+ pruc = pr->ps_ucred;
+ crset(newcred, pruc);
+
+ if (ruid != (uid_t)-1)
+ newcred->cr_ruid = ruid;
+ if (euid != (uid_t)-1)
+ newcred->cr_uid = euid;
/*
* The saved uid presents a bit of a dilemma, as it did not
* uid when the real uid is specified and either its value would
* change, or where the saved and effective uids are different.
*/
- if (ruid != (uid_t)-1 && (ruid != uc->cr_ruid ||
- uc->cr_svuid != (euid != (uid_t)-1 ? euid : uc->cr_uid)))
- SCARG(&sresuidargs, suid) = ruid;
- else
- SCARG(&sresuidargs, suid) = (uid_t)-1;
+ if (ruid != (uid_t)-1 && (ruid != pruc->cr_ruid ||
+ pruc->cr_svuid != (euid != (uid_t)-1 ? euid : pruc->cr_uid)))
+ newcred->cr_svuid = ruid;
+ pr->ps_ucred = newcred;
+ atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
+
+ /* now that we can sleep, transfer proc count to new user */
+ if (ruid != (uid_t)-1 && ruid != pruc->cr_ruid) {
+ chgproccnt(pruc->cr_ruid, -1);
+ chgproccnt(ruid, 1);
+ }
+ crfree(pruc);
- return (sys_setresuid(p, &sresuidargs, retval));
+ return (0);
}
-/* ARGSUSED */
int
sys_setuid(struct proc *p, void *v, register_t *retval)
{
struct sys_setuid_args /* {
syscallarg(uid_t) uid;
} */ *uap = v;
- struct ucred *uc = p->p_ucred;
+ struct process *pr = p->p_p;
+ struct ucred *pruc, *newcred, *uc = p->p_ucred;
uid_t uid;
- int error;
+ int did_real, error;
uid = SCARG(uap, uid);
- if (uc->cr_uid == uid &&
- uc->cr_ruid == uid &&
- uc->cr_svuid == uid)
+ pruc = pr->ps_ucred;
+ if (pruc->cr_uid == uid &&
+ pruc->cr_ruid == uid &&
+ pruc->cr_svuid == uid)
return (0);
if (uid != uc->cr_ruid &&
/*
* Copy credentials so other references do not see our changes.
+ * ps_ucred may change during the crget().
*/
- p->p_ucred = uc = crcopy(uc);
+ newcred = crget();
+ pruc = pr->ps_ucred;
+ crset(newcred, pruc);
/*
* Everything's okay, do it.
*/
- if (uid == uc->cr_uid || suser(p, 0) == 0) {
- /*
- * Transfer proc count to new user.
- */
- if (uid != uc->cr_ruid) {
- (void)chgproccnt(uc->cr_ruid, -1);
- (void)chgproccnt(uid, 1);
- }
- uc->cr_ruid = uid;
- uc->cr_svuid = uid;
+ if (uid == pruc->cr_uid || suser(p, 0) == 0) {
+ did_real = 1;
+ newcred->cr_ruid = uid;
+ newcred->cr_svuid = uid;
+ } else
+ did_real = 0;
+ newcred->cr_uid = uid;
+ pr->ps_ucred = newcred;
+ atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
+
+ /*
+ * Transfer proc count to new user.
+ */
+ if (did_real && uid != pruc->cr_ruid) {
+ chgproccnt(pruc->cr_ruid, -1);
+ chgproccnt(uid, 1);
}
+ crfree(pruc);
- uc->cr_uid = uid;
- atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
return (0);
}
-/* ARGSUSED */
int
sys_seteuid(struct proc *p, void *v, register_t *retval)
{
struct sys_seteuid_args /* {
syscallarg(uid_t) euid;
} */ *uap = v;
- struct ucred *uc = p->p_ucred;
+ struct process *pr = p->p_p;
+ struct ucred *pruc, *newcred, *uc = p->p_ucred;
uid_t euid;
int error;
euid = SCARG(uap, euid);
- if (uc->cr_uid == euid)
+ if (pr->ps_ucred->cr_uid == euid)
return (0);
if (euid != uc->cr_ruid && euid != uc->cr_svuid &&
/*
* Copy credentials so other references do not see our changes.
+ * ps_ucred may change during the crget().
*/
- p->p_ucred = uc = crcopy(uc);
- uc->cr_uid = euid;
+ newcred = crget();
+ pruc = pr->ps_ucred;
+ crset(newcred, pruc);
+ newcred->cr_uid = euid;
+ pr->ps_ucred = newcred;
atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
+ crfree(pruc);
return (0);
}
-/* ARGSUSED */
int
sys_setgid(struct proc *p, void *v, register_t *retval)
{
struct sys_setgid_args /* {
syscallarg(gid_t) gid;
} */ *uap = v;
- struct ucred *uc = p->p_ucred;
+ struct process *pr = p->p_p;
+ struct ucred *pruc, *newcred, *uc = p->p_ucred;
gid_t gid;
int error;
gid = SCARG(uap, gid);
- if (uc->cr_gid == gid &&
- uc->cr_rgid == gid &&
- uc->cr_svgid == gid)
+ pruc = pr->ps_ucred;
+ if (pruc->cr_gid == gid &&
+ pruc->cr_rgid == gid &&
+ pruc->cr_svgid == gid)
return (0);
if (gid != uc->cr_rgid &&
/*
* Copy credentials so other references do not see our changes.
+ * ps_ucred may change during the crget().
*/
- p->p_ucred = uc = crcopy(uc);
+ newcred = crget();
+ pruc = pr->ps_ucred;
+ crset(newcred, pruc);
- if (gid == uc->cr_gid || suser(p, 0) == 0) {
- uc->cr_rgid = gid;
- uc->cr_svgid = gid;
+ if (gid == pruc->cr_gid || suser(p, 0) == 0) {
+ newcred->cr_rgid = gid;
+ newcred->cr_svgid = gid;
}
-
- uc->cr_gid = gid;
+ newcred->cr_gid = gid;
+ pr->ps_ucred = newcred;
atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
+ crfree(pruc);
return (0);
}
-/* ARGSUSED */
int
sys_setegid(struct proc *p, void *v, register_t *retval)
{
struct sys_setegid_args /* {
syscallarg(gid_t) egid;
} */ *uap = v;
- struct ucred *uc = p->p_ucred;
+ struct process *pr = p->p_p;
+ struct ucred *pruc, *newcred, *uc = p->p_ucred;
gid_t egid;
int error;
egid = SCARG(uap, egid);
- if (uc->cr_gid == egid)
+ if (pr->ps_ucred->cr_gid == egid)
return (0);
if (egid != uc->cr_rgid && egid != uc->cr_svgid &&
/*
* Copy credentials so other references do not see our changes.
+ * ps_ucred may change during the crget().
*/
- p->p_ucred = uc = crcopy(uc);
- uc->cr_gid = egid;
+ newcred = crget();
+ pruc = pr->ps_ucred;
+ crset(newcred, pruc);
+ newcred->cr_gid = egid;
+ pr->ps_ucred = newcred;
atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
+ crfree(pruc);
return (0);
}
-/* ARGSUSED */
int
sys_setgroups(struct proc *p, void *v, register_t *retval)
{
syscallarg(int) gidsetsize;
syscallarg(const gid_t *) gidset;
} */ *uap = v;
- struct ucred *uc = p->p_ucred;
+ struct process *pr = p->p_p;
+ struct ucred *pruc, *newcred;
+ gid_t groups[NGROUPS];
u_int ngrp;
int error;
ngrp = SCARG(uap, gidsetsize);
if (ngrp > NGROUPS)
return (EINVAL);
- p->p_ucred = uc = crcopy(uc);
- error = copyin(SCARG(uap, gidset), uc->cr_groups, ngrp * sizeof(gid_t));
- if (error)
- return (error);
- uc->cr_ngroups = ngrp;
- atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
- return (0);
+ error = copyin(SCARG(uap, gidset), groups, ngrp * sizeof(gid_t));
+ if (error == 0) {
+ newcred = crget();
+ pruc = pr->ps_ucred;
+ crset(newcred, pruc);
+ memcpy(newcred->cr_groups, groups, ngrp * sizeof(gid_t));
+ newcred->cr_ngroups = ngrp;
+ pr->ps_ucred = newcred;
+ atomic_setbits_int(&p->p_p->ps_flags, PS_SUGID);
+ crfree(pruc);
+ }
+ return (error);
}
/*
/*
* Get login name, if available.
*/
-/* ARGSUSED */
int
sys_getlogin(struct proc *p, void *v, register_t *retval)
{
/*
* Set login name.
*/
-/* ARGSUSED */
int
sys_setlogin(struct proc *p, void *v, register_t *retval)
{
*retval = (register_t)TCB_GET(p);
return (0);
}
+
+/*
+ * Refresh the thread's reference to the process's credentials
+ */
+void
+dorefreshcreds(struct process *pr, struct proc *p)
+{
+ struct ucred *uc = p->p_ucred;
+
+ KERNEL_LOCK(); /* XXX should be PROCESS_RLOCK(pr) */
+ if (uc != pr->ps_ucred) {
+ p->p_ucred = pr->ps_ucred;
+ crhold(p->p_ucred);
+ crfree(uc);
+ }
+ KERNEL_UNLOCK();
+}
-/* $OpenBSD: kern_sig.c,v 1.163 2014/03/30 21:54:48 guenther Exp $ */
+/* $OpenBSD: kern_sig.c,v 1.164 2014/04/18 11:51:17 guenther Exp $ */
/* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */
/*
void proc_stop_sweep(void *);
struct timeout proc_stop_to;
-int cansignal(struct process *, struct process *, int);
+int cansignal(struct proc *, struct process *, int);
struct pool sigacts_pool; /* memory pool for sigacts structures */
* Can thread p, send the signal signum to process qr?
*/
int
-cansignal(struct process *pr, struct process *qr, int signum)
+cansignal(struct proc *p, struct process *qr, int signum)
{
- struct ucred *uc = pr->ps_ucred;
+ struct process *pr = p->p_p;
+ struct ucred *uc = p->p_ucred;
struct ucred *quc = qr->ps_ucred;
if (uc->cr_uid == 0)
return (ESRCH);
if (p->p_flag & P_THREAD)
return (ESRCH);
- if (!cansignal(cp->p_p, p->p_p, signum))
+ if (!cansignal(cp, p->p_p, signum))
return (EPERM);
}
LIST_FOREACH(pr, &allprocess, ps_list) {
p = pr->ps_mainproc;
if (pr->ps_pid <= 1 || p->p_flag & P_SYSTEM ||
- pr == cp->p_p || !cansignal(cp->p_p, pr, signum))
+ pr == cp->p_p || !cansignal(cp, pr, signum))
continue;
nfound++;
if (signum)
LIST_FOREACH(pr, &pgrp->pg_members, ps_pglist) {
p = pr->ps_mainproc;
if (pr->ps_pid <= 1 || p->p_flag & P_SYSTEM ||
- !cansignal(cp->p_p, pr, signum))
+ !cansignal(cp, pr, signum))
continue;
nfound++;
if (signum && P_ZOMBIE(p) == 0)
-/* $OpenBSD: cdefs.h,v 1.38 2014/03/19 05:11:06 guenther Exp $ */
+/* $OpenBSD: cdefs.h,v 1.39 2014/04/18 11:51:17 guenther Exp $ */
/* $NetBSD: cdefs.h,v 1.16 1996/04/03 20:46:39 christos Exp $ */
/*
#define __END_HIDDEN_DECLS __END_EXTERN_C
#endif
-#define __BEGIN_DECLS __BEGIN_PUBLIC_DECLS
-#define __END_DECLS __END_PUBLIC_DECLS
+#define __BEGIN_DECLS __BEGIN_EXTERN_C
+#define __END_DECLS __END_EXTERN_C
/*
* "The nice thing about standards is that there are so many to choose from."
-/* $OpenBSD: proc.h,v 1.183 2014/03/31 22:20:15 matthew Exp $ */
+/* $OpenBSD: proc.h,v 1.184 2014/04/18 11:51:17 guenther Exp $ */
/* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */
/*-
/* substructures: */
struct filedesc *p_fd; /* Ptr to open files structure. */
struct vmspace *p_vmspace; /* Address space. */
-#define p_ucred p_p->ps_ucred
#define p_rlimit p_p->ps_limit->pl_rlimit
int p_flag; /* P_* flags. */
# define TCB_GET(p) ((p)->p_tcb)
#endif
+ struct ucred *p_ucred; /* cached credentials */
struct sigaltstack p_sigstk; /* sp & on stack state variable */
u_long p_prof_addr; /* tmp storage for profiling addr until AST */
int fork1(struct proc *, int, void *, pid_t *, void (*)(void *),
void *, register_t *, struct proc **);
int groupmember(gid_t, struct ucred *);
+void dorefreshcreds(struct process *, struct proc *);
+
+static inline void
+refreshcreds(struct proc *p)
+{
+ struct process *pr = p->p_p;
+
+ /* this is an unlocked access to ps_ucred, but the result is benign */
+ if (pr->ps_ucred != p->p_ucred)
+ dorefreshcreds(pr, p);
+}
enum single_thread_mode {
SINGLE_SUSPEND, /* other threads to stop wherever they are */
-/* $OpenBSD: syscall_mi.h,v 1.2 2012/08/07 23:22:38 guenther Exp $ */
+/* $OpenBSD: syscall_mi.h,v 1.3 2014/04/18 11:51:17 guenther Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
int lock = !(callp->sy_flags & SY_NOLOCK);
int error;
+ /* refresh the thread's cache of the process's creds */
+ refreshcreds(p);
+
#ifdef SYSCALL_DEBUG
KERNEL_LOCK();
scdebug_call(p, code, argp);
-/* $OpenBSD: ucred.h,v 1.8 2014/03/30 21:54:48 guenther Exp $ */
+/* $OpenBSD: ucred.h,v 1.9 2014/04/18 11:51:17 guenther Exp $ */
/* $NetBSD: ucred.h,v 1.12 1995/06/01 22:44:50 jtc Exp $ */
/*
*/
struct ucred {
u_int cr_ref; /* reference count */
+
+/* The following fields are all copied by crset() */
+#define cr_startcopy cr_uid
uid_t cr_uid; /* effective user id */
uid_t cr_ruid; /* Real user id. */
uid_t cr_svuid; /* Saved effective user id. */
#define SUSER_NOACCT 0x1 /* don't mark accounting flags */
void crfromxucred(struct ucred *, const struct xucred *);
+void crset(struct ucred *, const struct ucred *);
struct ucred *crcopy(struct ucred *cr);
struct ucred *crdup(struct ucred *cr);
void crfree(struct ucred *cr);