From: guenther Date: Fri, 18 Apr 2014 11:51:16 +0000 (+0000) Subject: Have each thread keeps its own (counted!) reference to the process's ucreds X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=a9ddc28608c80433f03eded670401243dac5208d;p=openbsd Have each thread keeps its own (counted!) reference to the process's ucreds to avoid possible use-after-free references when swapping ids in threaded processes. "Do I have the right creds?" checks are always made with the threads creds. Inspired by FreeBSD and NetBSD "right time" deraadt@ --- diff --git a/sys/arch/alpha/alpha/trap.c b/sys/arch/alpha/alpha/trap.c index e4003e60079..45c44d03cd1 100644 --- a/sys/arch/alpha/alpha/trap.c +++ b/sys/arch/alpha/alpha/trap.c @@ -1,4 +1,4 @@ -/* $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 $ */ /*- @@ -244,8 +244,10 @@ trap(a0, a1, a2, entry, framep) 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: diff --git a/sys/arch/amd64/amd64/trap.c b/sys/arch/amd64/amd64/trap.c index 84985e5a4c2..3987b2c3fc5 100644 --- a/sys/arch/amd64/amd64/trap.c +++ b/sys/arch/amd64/amd64/trap.c @@ -1,4 +1,4 @@ -/* $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 $ */ /*- @@ -175,7 +175,8 @@ trap(struct trapframe *frame) 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) { diff --git a/sys/arch/arm/arm/fault.c b/sys/arch/arm/arm/fault.c index 8143bdb0c5b..79d0d463c87 100644 --- a/sys/arch/arm/arm/fault.c +++ b/sys/arch/arm/arm/fault.c @@ -1,4 +1,4 @@ -/* $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 $ */ /* @@ -255,8 +255,10 @@ data_abort_handler(trapframe_t *tf) * 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 diff --git a/sys/arch/hppa/hppa/trap.c b/sys/arch/hppa/hppa/trap.c index 25968575070..4ff9408e63e 100644 --- a/sys/arch/hppa/hppa/trap.c +++ b/sys/arch/hppa/hppa/trap.c @@ -1,4 +1,4 @@ -/* $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 @@ -219,6 +219,9 @@ trap(int type, struct trapframe *frame) mtctl(frame->tf_eiem, CR_EIEM); } + if (type & T_USER) + refreshcreds(p); + switch (type) { case T_NONEXIST: case T_NONEXIST | T_USER: diff --git a/sys/arch/hppa64/hppa64/trap.c b/sys/arch/hppa64/hppa64/trap.c index 02472f0d158..8310c42db1b 100644 --- a/sys/arch/hppa64/hppa64/trap.c +++ b/sys/arch/hppa64/hppa64/trap.c @@ -1,4 +1,4 @@ -/* $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 @@ -212,6 +212,9 @@ trap(int type, struct trapframe *frame) ssm(PSL_I, mask); } + if (type & T_USER) + refreshcreds(p); + switch (type) { case T_NONEXIST: case T_NONEXIST | T_USER: diff --git a/sys/arch/i386/i386/trap.c b/sys/arch/i386/i386/trap.c index 216d16656fa..31d4c77109c 100644 --- a/sys/arch/i386/i386/trap.c +++ b/sys/arch/i386/i386/trap.c @@ -1,4 +1,4 @@ -/* $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 $ */ /*- @@ -155,7 +155,8 @@ trap(struct trapframe *frame) 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) { diff --git a/sys/arch/m88k/m88k/trap.c b/sys/arch/m88k/m88k/trap.c index e9c90127a41..b60fcff358e 100644 --- a/sys/arch/m88k/m88k/trap.c +++ b/sys/arch/m88k/m88k/trap.c @@ -1,4 +1,4 @@ -/* $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. @@ -245,6 +245,7 @@ m88100_trap(u_int type, struct trapframe *frame) 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; @@ -713,6 +714,7 @@ m88110_trap(u_int type, struct trapframe *frame) if (USERMODE(frame->tf_epsr)) { type += T_USER; p->p_md.md_tf = frame; /* for ptrace/signals */ + refreshcreds(p); } if (sig != 0) diff --git a/sys/arch/mips64/mips64/trap.c b/sys/arch/mips64/mips64/trap.c index 8f20faf0563..5576f84d545 100644 --- a/sys/arch/mips64/mips64/trap.c +++ b/sys/arch/mips64/mips64/trap.c @@ -1,4 +1,4 @@ -/* $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. @@ -189,6 +189,7 @@ trap(struct trap_frame *trapframe) atomic_add_int(&uvmexp.traps, 1); if (USERMODE(trapframe->sr)) { type |= T_USER; + refreshcreds(p); } /* diff --git a/sys/arch/powerpc/powerpc/trap.c b/sys/arch/powerpc/powerpc/trap.c index 7d4e23d7222..bca3dab1277 100644 --- a/sys/arch/powerpc/powerpc/trap.c +++ b/sys/arch/powerpc/powerpc/trap.c @@ -1,4 +1,4 @@ -/* $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 $ */ /* @@ -254,6 +254,7 @@ trap(struct trapframe *frame) if (frame->srr1 & PSL_PR) { type |= EXC_USER; + refreshcreds(p); } switch (type) { diff --git a/sys/arch/sh/sh/trap.c b/sys/arch/sh/sh/trap.c index 4c1b9c1812b..b6f80f953d5 100644 --- a/sys/arch/sh/sh/trap.c +++ b/sys/arch/sh/sh/trap.c @@ -1,4 +1,4 @@ -/* $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 $ */ @@ -173,6 +173,7 @@ general_exception(struct proc *p, struct trapframe *tf, uint32_t va) goto do_panic; KDASSERT(p->p_md.md_regs == tf); /* check exception depth */ expevt |= EXP_USER; + refreshcreds(p); } switch (expevt) { @@ -336,6 +337,7 @@ tlb_exception(struct proc *p, struct trapframe *tf, uint32_t va) usermode = !KERNELMODE(tf->tf_ssr); if (usermode) { KDASSERT(p->p_md.md_regs == tf); + refreshcreds(p); } else { KDASSERT(p == NULL || /* idle */ p == &proc0 || /* kthread */ @@ -479,6 +481,7 @@ ast(struct proc *p, struct trapframe *tf) p->p_md.md_astpending = 0; uvmexp.softs++; + refreshcreds(p); if (p->p_flag & P_OWEUPC) { ADDUPROF(p); } diff --git a/sys/arch/solbourne/solbourne/trap.c b/sys/arch/solbourne/solbourne/trap.c index 1796ae3a74b..dbd30071636 100644 --- a/sys/arch/solbourne/solbourne/trap.c +++ b/sys/arch/solbourne/solbourne/trap.c @@ -1,4 +1,4 @@ -/* $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 */ /* @@ -286,6 +286,7 @@ trap(type, psr, pc, tf) p = &proc0; pcb = &p->p_addr->u_pcb; p->p_md.md_tf = tf; /* for ptrace/signals */ + refreshcreds(p); switch (type) { diff --git a/sys/arch/sparc/sparc/trap.c b/sys/arch/sparc/sparc/trap.c index 8c65ce5f30e..d5dcac3167a 100644 --- a/sys/arch/sparc/sparc/trap.c +++ b/sys/arch/sparc/sparc/trap.c @@ -1,4 +1,4 @@ -/* $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 $ */ /* @@ -279,6 +279,7 @@ trap(type, psr, pc, tf) p = &proc0; pcb = &p->p_addr->u_pcb; p->p_md.md_tf = tf; /* for ptrace/signals */ + refreshcreds(p); switch (type) { diff --git a/sys/arch/sparc64/sparc64/trap.c b/sys/arch/sparc64/sparc64/trap.c index 42734cf7f43..d1605f05207 100644 --- a/sys/arch/sparc64/sparc64/trap.c +++ b/sys/arch/sparc64/sparc64/trap.c @@ -1,4 +1,4 @@ -/* $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 $ */ /* @@ -430,6 +430,7 @@ trap(tf, type, pc, tstate) p = &proc0; pcb = &p->p_addr->u_pcb; p->p_md.md_tf = tf; /* for ptrace/signals */ + refreshcreds(p); switch (type) { diff --git a/sys/arch/vax/vax/trap.c b/sys/arch/vax/vax/trap.c index d7e06b1d49d..bcd9a5a609f 100644 --- a/sys/arch/vax/vax/trap.c +++ b/sys/arch/vax/vax/trap.c @@ -1,4 +1,4 @@ -/* $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. @@ -110,6 +110,7 @@ arithflt(frame) if ((umode = USERMODE(frame))) { type |= T_USER; p->p_addr->u_pcb.framep = frame; + refreshcreds(p); } type&=~(T_WRITE|T_PTEFETCH); diff --git a/sys/dev/systrace.c b/sys/dev/systrace.c index a9c66b455eb..122a885155e 100644 --- a/sys/dev/systrace.c +++ b/sys/dev/systrace.c @@ -1,4 +1,4 @@ -/* $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 * All rights reserved. @@ -59,8 +59,6 @@ int systraceopen(dev_t, int, int, struct proc *); 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); @@ -117,9 +115,7 @@ struct str_process { 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]; @@ -666,10 +662,9 @@ systrace_redirect(int code, struct proc *p, void *v, register_t *retval) 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; @@ -701,8 +696,8 @@ systrace_redirect(int code, struct proc *p, void *v, register_t *retval) 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) { @@ -787,23 +782,38 @@ systrace_redirect(int code, struct proc *p, void *v, register_t *retval) 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) { @@ -811,19 +821,6 @@ systrace_redirect(int code, struct proc *p, void *v, register_t *retval) 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)) { @@ -858,8 +855,8 @@ systrace_redirect(int code, struct proc *p, void *v, register_t *retval) } /* 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; @@ -880,44 +877,6 @@ out: 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 @@ -1201,15 +1160,18 @@ 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; } @@ -1218,7 +1180,7 @@ systrace_attach(struct fsystrace *fst, pid_t pid) * 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; } @@ -1226,7 +1188,7 @@ systrace_attach(struct fsystrace *fst, pid_t pid) /* * (2) it's a system process */ - if (ISSET(proc->p_flag, P_SYSTEM)) { + if (ISSET(t->p_flag, P_SYSTEM)) { error = EPERM; goto out; } @@ -1234,7 +1196,7 @@ systrace_attach(struct fsystrace *fst, pid_t pid) /* * (3) it's being traced already */ - if (ISSET(proc->p_flag, P_SYSTRACE)) { + if (ISSET(t->p_flag, P_SYSTRACE)) { error = EBUSY; goto out; } @@ -1250,8 +1212,8 @@ systrace_attach(struct fsystrace *fst, pid_t pid) * 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; @@ -1261,13 +1223,13 @@ systrace_attach(struct fsystrace *fst, pid_t pid) * 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); @@ -1713,10 +1675,10 @@ int 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)); } diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 420e782188e..eaea6e4d2ab 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -1,4 +1,4 @@ -/* $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 $ */ /* @@ -295,6 +295,9 @@ main(void *framep) 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; diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 2790e48f98f..969ac154091 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -1,4 +1,4 @@ -/* $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 $ */ /*- @@ -595,7 +595,10 @@ sys_execve(struct proc *p, void *v, register_t *retval) } 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 */ @@ -604,6 +607,15 @@ sys_execve(struct proc *p, void *v, register_t *retval) 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(); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 9f16c28216a..37e7c39fbd7 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -1,4 +1,4 @@ -/* $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 $ */ /* @@ -411,6 +411,7 @@ exit2(struct proc *p) void proc_free(struct proc *p) { + crfree(p->p_ucred); pool_put(&proc_pool, p); nthreads--; } diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 3cec607e7bb..bad4221d5d5 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -1,4 +1,4 @@ -/* $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 $ */ /* @@ -175,8 +175,9 @@ process_new(struct proc *p, struct process *parent, int flags) (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) */ @@ -318,6 +319,7 @@ fork1(struct proc *curp, int flags, void *stack, pid_t *tidptr, (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. diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index 71e527ffc78..ce960e1ceda 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -1,4 +1,4 @@ -/* $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 $ */ /* @@ -56,7 +56,16 @@ # include #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) { @@ -65,7 +74,6 @@ sys_getpid(struct proc *p, void *v, register_t *retval) return (0); } -/* ARGSUSED */ int sys_getthrid(struct proc *p, void *v, register_t *retval) { @@ -74,7 +82,6 @@ sys_getthrid(struct proc *p, void *v, register_t *retval) return (0); } -/* ARGSUSED */ int sys_getppid(struct proc *p, void *v, register_t *retval) { @@ -136,7 +143,6 @@ found: return (0); } -/* ARGSUSED */ int sys_getuid(struct proc *p, void *v, register_t *retval) { @@ -145,7 +151,6 @@ sys_getuid(struct proc *p, void *v, register_t *retval) return (0); } -/* ARGSUSED */ int sys_geteuid(struct proc *p, void *v, register_t *retval) { @@ -154,7 +159,6 @@ sys_geteuid(struct proc *p, void *v, register_t *retval) return (0); } -/* ARGSUSED */ int sys_issetugid(struct proc *p, void *v, register_t *retval) { @@ -165,7 +169,6 @@ sys_issetugid(struct proc *p, void *v, register_t *retval) return (0); } -/* ARGSUSED */ int sys_getgid(struct proc *p, void *v, register_t *retval) { @@ -179,7 +182,6 @@ 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) { @@ -214,7 +216,6 @@ sys_getgroups(struct proc *p, void *v, register_t *retval) return (0); } -/* ARGSUSED */ int sys_setsid(struct proc *p, void *v, register_t *retval) { @@ -250,7 +251,6 @@ 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) { @@ -305,7 +305,6 @@ out: return (error); } -/* ARGSUSED */ int sys_getresuid(struct proc *p, void *v, register_t *retval) { @@ -332,7 +331,6 @@ 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) { @@ -341,7 +339,8 @@ 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; @@ -349,9 +348,14 @@ sys_setresuid(struct proc *p, void *v, register_t *retval) 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 */ /* @@ -381,31 +385,35 @@ sys_setresuid(struct proc *p, void *v, register_t *retval) /* * 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) { @@ -432,7 +440,6 @@ 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) { @@ -441,7 +448,8 @@ 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; @@ -449,9 +457,14 @@ sys_setresgid(struct proc *p, void *v, register_t *retval) 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 */ /* @@ -481,25 +494,28 @@ sys_setresgid(struct proc *p, void *v, register_t *retval) /* * 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) { @@ -507,12 +523,62 @@ 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 @@ -520,16 +586,15 @@ sys_setregid(struct proc *p, void *v, register_t *retval) * 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) { @@ -537,12 +602,62 @@ 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 @@ -550,31 +665,39 @@ sys_setreuid(struct proc *p, void *v, register_t *retval) * 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 && @@ -585,43 +708,51 @@ sys_setuid(struct proc *p, void *v, register_t *retval) /* * 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 && @@ -630,29 +761,35 @@ sys_seteuid(struct proc *p, void *v, register_t *retval) /* * 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 && @@ -663,33 +800,37 @@ sys_setgid(struct proc *p, void *v, register_t *retval) /* * 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 && @@ -698,14 +839,18 @@ sys_setegid(struct proc *p, void *v, register_t *retval) /* * 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) { @@ -713,7 +858,9 @@ 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; @@ -722,13 +869,18 @@ sys_setgroups(struct proc *p, void *v, register_t *retval) 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); } /* @@ -850,7 +1002,6 @@ crfromxucred(struct ucred *cr, const struct xucred *xcr) /* * Get login name, if available. */ -/* ARGSUSED */ int sys_getlogin(struct proc *p, void *v, register_t *retval) { @@ -869,7 +1020,6 @@ 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) { @@ -929,3 +1079,20 @@ sys___get_tcb(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(); +} diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 0b39125ce26..5356365dc7b 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,4 @@ -/* $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 $ */ /* @@ -79,7 +79,7 @@ void proc_stop(struct proc *p, int); 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 */ @@ -87,9 +87,10 @@ 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) @@ -589,7 +590,7 @@ sys_kill(struct proc *cp, void *v, register_t *retval) 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); } @@ -628,7 +629,7 @@ killpg1(struct proc *cp, int signum, int pgid, int all) 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) @@ -648,7 +649,7 @@ killpg1(struct proc *cp, int signum, int pgid, int all) 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) diff --git a/sys/sys/cdefs.h b/sys/sys/cdefs.h index b7d7efef13c..98fe8f6d03f 100644 --- a/sys/sys/cdefs.h +++ b/sys/sys/cdefs.h @@ -1,4 +1,4 @@ -/* $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 $ */ /* @@ -261,8 +261,8 @@ #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." diff --git a/sys/sys/proc.h b/sys/sys/proc.h index a65f1f258ca..33ec6d82e2b 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -1,4 +1,4 @@ -/* $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 $ */ /*- @@ -260,7 +260,6 @@ struct proc { /* 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. */ @@ -321,6 +320,7 @@ struct proc { # 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 */ @@ -488,6 +488,17 @@ void cpu_exit(struct proc *); 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 */ diff --git a/sys/sys/syscall_mi.h b/sys/sys/syscall_mi.h index bb12b9b25be..20293f025db 100644 --- a/sys/sys/syscall_mi.h +++ b/sys/sys/syscall_mi.h @@ -1,4 +1,4 @@ -/* $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 @@ -55,6 +55,9 @@ mi_syscall(struct proc *p, register_t code, const struct sysent *callp, 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); diff --git a/sys/sys/ucred.h b/sys/sys/ucred.h index 5bb37e5b1db..dd22f5ae4d9 100644 --- a/sys/sys/ucred.h +++ b/sys/sys/ucred.h @@ -1,4 +1,4 @@ -/* $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 $ */ /* @@ -40,6 +40,9 @@ */ 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. */ @@ -68,6 +71,7 @@ struct xucred { #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);