summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/init_main.c5
-rw-r--r--sys/kern/kern_exec.c16
-rw-r--r--sys/kern/kern_exit.c3
-rw-r--r--sys/kern/kern_fork.c6
-rw-r--r--sys/kern/kern_prot.c395
-rw-r--r--sys/kern/kern_sig.c15
6 files changed, 313 insertions, 127 deletions
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 <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)
{
@@ -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)