diff --git a/sys/compat/netbsd32/netbsd32_execve.c b/sys/compat/netbsd32/netbsd32_execve.c index 7e80764a899d..fcd350f0096a 100644 --- a/sys/compat/netbsd32/netbsd32_execve.c +++ b/sys/compat/netbsd32/netbsd32_execve.c @@ -242,7 +242,9 @@ netbsd32_posix_spawn(struct lwp *l, error_exit: if (!child_ok) { - (void)chgproccnt(kauth_cred_getuid(l->l_cred), -1); + mutex_enter(p->p_lock); + (void)chgproccnt(kauth_cred_getuid(p->p_cred), -1); + mutex_exit(p->p_lock); atomic_dec_uint(&nprocs); if (sa) diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 56bc05204d32..5cdf39358182 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -430,7 +430,9 @@ main(void) uid_init(); /* Charge root for one process. */ + mutex_enter(proc0.p_lock); (void)chgproccnt(0, 1); + mutex_exit(proc0.p_lock); /* Initialize the run queues, turnstiles and sleep queues. */ sched_rqinit(); diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index e9907ba6872c..e4fccb83fc61 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -778,13 +778,20 @@ execve_loadvm(struct lwp *l, bool has_path, const char *path, int fd, */ retry: if (p->p_flag & PK_SUGID) { - if (kauth_authorize_process(l->l_cred, KAUTH_PROCESS_RLIMIT, - p, KAUTH_ARG(KAUTH_REQ_PROCESS_RLIMIT_BYPASS), - &p->p_rlimit[RLIMIT_NPROC], - KAUTH_ARG(RLIMIT_NPROC)) != 0 && - chgproccnt(kauth_cred_getuid(l->l_cred), 0) > - p->p_rlimit[RLIMIT_NPROC].rlim_cur) - return EAGAIN; + kauth_cred_t cred; + + mutex_enter(l->l_proc->p_lock); + cred = l->l_proc->p_cred; + if ((kauth_authorize_process(cred, KAUTH_PROCESS_RLIMIT, + p, KAUTH_ARG(KAUTH_REQ_PROCESS_RLIMIT_BYPASS), + &p->p_rlimit[RLIMIT_NPROC], + KAUTH_ARG(RLIMIT_NPROC)) != 0) && + (chgproccnt(kauth_cred_getuid(cred), 0) > + p->p_rlimit[RLIMIT_NPROC].rlim_cur)) { + mutex_exit(l->l_proc->p_lock); + return EAGAIN; + } + mutex_exit(l->l_proc->p_lock); } /* @@ -2268,11 +2275,18 @@ handle_posix_spawn_attrs(struct posix_spawnattr *attrs, struct proc *parent) /* Reset user ID's */ if (attrs->sa_flags & POSIX_SPAWN_RESETIDS) { - error = do_setresgid(l, -1, kauth_cred_getgid(l->l_cred), -1, + kauth_cred_t cred, ncred; + + setresgid_begin(l, &cred, &ncred); + error = setresgid_commit(l, cred, ncred, + -1, kauth_cred_getgid(cred), -1, ID_E_EQ_R | ID_E_EQ_S); if (error) return error; - error = do_setresuid(l, -1, kauth_cred_getuid(l->l_cred), -1, + + setresuid_begin(l, &cred, &ncred); + error = setresuid_commit(l, cred, ncred, + -1, kauth_cred_getuid(cred), -1, ID_E_EQ_R | ID_E_EQ_S); if (error) goto out; @@ -2519,11 +2533,11 @@ int check_posix_spawn(struct lwp *l1) { int error, tnprocs, count; + kauth_cred_t cred; uid_t uid; struct proc *p1; p1 = l1->l_proc; - uid = kauth_cred_getuid(l1->l_cred); tnprocs = atomic_inc_uint_nv(&nprocs); /* @@ -2544,15 +2558,21 @@ check_posix_spawn(struct lwp *l1) /* * Enforce limits. */ + mutex_enter(p1->p_lock); + cred = p1->p_cred; + uid = kauth_cred_getuid(cred); count = chgproccnt(uid, 1); - if (kauth_authorize_process(l1->l_cred, KAUTH_PROCESS_RLIMIT, - p1, KAUTH_ARG(KAUTH_REQ_PROCESS_RLIMIT_BYPASS), - &p1->p_rlimit[RLIMIT_NPROC], KAUTH_ARG(RLIMIT_NPROC)) != 0 && + if ((kauth_authorize_process(cred, KAUTH_PROCESS_RLIMIT, + p1, KAUTH_ARG(KAUTH_REQ_PROCESS_RLIMIT_BYPASS), + &p1->p_rlimit[RLIMIT_NPROC], KAUTH_ARG(RLIMIT_NPROC)) + != 0) && __predict_false(count > p1->p_rlimit[RLIMIT_NPROC].rlim_cur)) { (void)chgproccnt(uid, -1); + mutex_exit(p1->p_lock); atomic_dec_uint(&nprocs); return EAGAIN; } + mutex_exit(p1->p_lock); return 0; } @@ -2919,7 +2939,9 @@ sys_posix_spawn(struct lwp *l1, const struct sys_posix_spawn_args *uap, error_exit: if (!child_ok) { - (void)chgproccnt(kauth_cred_getuid(l1->l_cred), -1); + mutex_enter(l1->l_proc->p_lock); + (void)chgproccnt(kauth_cred_getuid(l1->l_proc->p_cred), -1); + mutex_exit(l1->l_proc->p_lock); atomic_dec_uint(&nprocs); if (sa) diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 8a52cb12586f..9a4538f72f1e 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -1249,9 +1249,11 @@ proc_free(struct proc *p, struct wrusage *wru) /* * Decrement the count of procs running with this uid. */ + mutex_enter(p->p_lock); cred1 = p->p_cred; uid = kauth_cred_getuid(cred1); (void)chgproccnt(uid, -1); + mutex_exit(p->p_lock); /* * Release substructures. diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index c8f9297e50cb..c9b13b3f20e6 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -246,6 +246,7 @@ fork1(struct lwp *l1, int flags, int exitsig, void *stack, size_t stacksize, { struct proc *p1, *p2, *parent; struct plimit *p1_lim; + kauth_cred_t cred; uid_t uid; struct lwp *l2; int count; @@ -254,7 +255,6 @@ fork1(struct lwp *l1, int flags, int exitsig, void *stack, size_t stacksize, int error = 0; p1 = l1->l_proc; - uid = kauth_cred_getuid(l1->l_cred); tnprocs = atomic_inc_uint_nv(&nprocs); /* @@ -280,18 +280,24 @@ fork1(struct lwp *l1, int flags, int exitsig, void *stack, size_t stacksize, /* * Enforce limits. */ + mutex_enter(p1->p_lock); + cred = p1->p_cred; + uid = kauth_cred_getuid(cred); count = chgproccnt(uid, 1); if (__predict_false(count > p1->p_rlimit[RLIMIT_NPROC].rlim_cur)) { - if (kauth_authorize_process(l1->l_cred, KAUTH_PROCESS_RLIMIT, - p1, KAUTH_ARG(KAUTH_REQ_PROCESS_RLIMIT_BYPASS), - &p1->p_rlimit[RLIMIT_NPROC], KAUTH_ARG(RLIMIT_NPROC)) != 0) { + if (kauth_authorize_process(cred, KAUTH_PROCESS_RLIMIT, + p1, KAUTH_ARG(KAUTH_REQ_PROCESS_RLIMIT_BYPASS), + &p1->p_rlimit[RLIMIT_NPROC], KAUTH_ARG(RLIMIT_NPROC)) + != 0) { (void)chgproccnt(uid, -1); atomic_dec_uint(&nprocs); + mutex_exit(p1->p_lock); if (forkfsleep) kpause("forkulim", false, forkfsleep, NULL); return EAGAIN; } } + mutex_exit(p1->p_lock); /* * Allocate virtual address space for the U-area now, while it @@ -300,7 +306,11 @@ fork1(struct lwp *l1, int flags, int exitsig, void *stack, size_t stacksize, */ uaddr = uvm_uarea_alloc(); if (__predict_false(uaddr == 0)) { + mutex_enter(p1->p_lock); + cred = p1->p_cred; + uid = kauth_cred_getuid(cred); (void)chgproccnt(uid, -1); + mutex_exit(p1->p_lock); atomic_dec_uint(&nprocs); return ENOMEM; } diff --git a/sys/kern/kern_lwp.c b/sys/kern/kern_lwp.c index 2e7668bd0db3..30d577e85187 100644 --- a/sys/kern/kern_lwp.c +++ b/sys/kern/kern_lwp.c @@ -779,11 +779,12 @@ lwp_create(lwp_t *l1, proc_t *p2, vaddr_t uaddr, int flags, uid_t uid = kauth_cred_getuid(p2->p_cred); int count = chglwpcnt(uid, 1); if (__predict_false(count > - p2->p_rlimit[RLIMIT_NTHR].rlim_cur)) { + p2->p_rlimit[RLIMIT_NTHR].rlim_cur)) { if (kauth_authorize_process(l1->l_cred, - KAUTH_PROCESS_RLIMIT, p2, - KAUTH_ARG(KAUTH_REQ_PROCESS_RLIMIT_BYPASS), - &p2->p_rlimit[RLIMIT_NTHR], KAUTH_ARG(RLIMIT_NTHR)) + KAUTH_PROCESS_RLIMIT, p2, + KAUTH_ARG(KAUTH_REQ_PROCESS_RLIMIT_BYPASS), + &p2->p_rlimit[RLIMIT_NTHR], + KAUTH_ARG(RLIMIT_NTHR)) != 0) { (void)chglwpcnt(uid, -1); mutex_exit(p2->p_lock); @@ -1245,8 +1246,9 @@ lwp_free(struct lwp *l, bool recycle, bool last) * and we don't want pay for syncing, since the lwp is going away * anyway */ - if (p != &proc0 && p->p_nlwps != 1) + if (p != &proc0 && p->p_nlwps != 1) { (void)chglwpcnt(kauth_cred_getuid(p->p_cred), -1); + } /* * In the unlikely event that the LWP is still on the CPU, diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index 095c1becbb1c..840ac3792a49 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -299,14 +299,34 @@ sys_setpgid(struct lwp *l, const struct sys_setpgid_args *uap, int do_setresuid(struct lwp *l, uid_t r, uid_t e, uid_t sv, u_int flags) { - struct proc *p = l->l_proc; kauth_cred_t cred, ncred; - ncred = kauth_cred_alloc(); + setresuid_begin(l, &cred, &ncred); + return setresuid_commit(l, cred, ncred, r, e, sv, flags); +} + +void +setresuid_begin(struct lwp *l, kauth_cred_t *credp, kauth_cred_t *ncredp) +{ + + *ncredp = kauth_cred_alloc(); /* Get a write lock on the process credential. */ proc_crmod_enter(); - cred = p->p_cred; + KASSERT(l->l_cred == l->l_proc->p_cred); + *credp = l->l_proc->p_cred; +} + +int +setresuid_commit(struct lwp *l, kauth_cred_t cred, kauth_cred_t ncred, + uid_t r, uid_t e, uid_t sv, u_int flags) +{ + struct proc *p = l->l_proc; + + KASSERT(mutex_owned(p->p_lock)); + KASSERT(cred == p->p_cred); + KASSERT(l == curlwp); + KASSERT(cred == l->l_cred); /* * Check that the new value is one of the allowed existing values, @@ -380,14 +400,34 @@ do_setresuid(struct lwp *l, uid_t r, uid_t e, uid_t sv, u_int flags) int do_setresgid(struct lwp *l, gid_t r, gid_t e, gid_t sv, u_int flags) { - struct proc *p = l->l_proc; kauth_cred_t cred, ncred; - ncred = kauth_cred_alloc(); + setresgid_begin(l, &cred, &ncred); + return setresgid_commit(l, cred, ncred, r, e, sv, flags); +} + +void +setresgid_begin(struct lwp *l, kauth_cred_t *credp, kauth_cred_t *ncredp) +{ + + *ncredp = kauth_cred_alloc(); /* Get a write lock on the process credential. */ proc_crmod_enter(); - cred = p->p_cred; + KASSERT(l->l_cred == l->l_proc->p_cred); + *credp = l->l_proc->p_cred; +} + +int +setresgid_commit(struct lwp *l, kauth_cred_t cred, kauth_cred_t ncred, + gid_t r, gid_t e, gid_t sv, u_int flags) +{ + struct proc *p = l->l_proc; + + KASSERT(mutex_owned(p->p_lock)); + KASSERT(cred == p->p_cred); + KASSERT(l == curlwp); + KASSERT(cred == l->l_cred); /* * check new value is one of the allowed existing values. @@ -469,12 +509,14 @@ sys_setreuid(struct lwp *l, const struct sys_setreuid_args *uap, register_t *ret syscallarg(uid_t) ruid; syscallarg(uid_t) euid; } */ - kauth_cred_t cred = l->l_cred; + kauth_cred_t cred, ncred; uid_t ruid, euid, svuid; ruid = SCARG(uap, ruid); euid = SCARG(uap, euid); + setresuid_begin(l, &cred, &ncred); + if (ruid == -1) ruid = kauth_cred_getuid(cred); if (euid == -1) @@ -483,10 +525,10 @@ sys_setreuid(struct lwp *l, const struct sys_setreuid_args *uap, register_t *ret /* Saved uid is set to the new euid if the ruid changed */ svuid = (ruid == kauth_cred_getuid(cred)) ? -1 : euid; - return do_setresuid(l, ruid, euid, svuid, - ID_R_EQ_R | ID_R_EQ_E | - ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S | - ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S); + return setresuid_commit(l, cred, ncred, ruid, euid, svuid, + ID_R_EQ_R | ID_R_EQ_E | + ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S | + ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S); } /* ARGSUSED */ @@ -520,12 +562,14 @@ sys_setregid(struct lwp *l, const struct sys_setregid_args *uap, register_t *ret syscallarg(gid_t) rgid; syscallarg(gid_t) egid; } */ - kauth_cred_t cred = l->l_cred; + kauth_cred_t cred, ncred; gid_t rgid, egid, svgid; rgid = SCARG(uap, rgid); egid = SCARG(uap, egid); + setresgid_begin(l, &cred, &ncred); + if (rgid == -1) rgid = kauth_cred_getgid(cred); if (egid == -1) @@ -534,10 +578,10 @@ sys_setregid(struct lwp *l, const struct sys_setregid_args *uap, register_t *ret /* Saved gid is set to the new egid if the rgid changed */ svgid = rgid == kauth_cred_getgid(cred) ? -1 : egid; - return do_setresgid(l, rgid, egid, svgid, - ID_R_EQ_R | ID_R_EQ_E | - ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S | - ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S); + return setresgid_commit(l, cred, ncred, rgid, egid, svgid, + ID_R_EQ_R | ID_R_EQ_E | + ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S | + ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S); } int diff --git a/sys/kern/kern_uidinfo.c b/sys/kern/kern_uidinfo.c index 02f85c2ff8d3..47f62befe024 100644 --- a/sys/kern/kern_uidinfo.c +++ b/sys/kern/kern_uidinfo.c @@ -253,6 +253,8 @@ chglwpcnt(uid_t uid, int diff) struct uidinfo *uip; long lwpcnt; + KASSERT(mutex_owned(curproc->p_lock)); + uip = uid_find(uid); lwpcnt = atomic_add_long_nv(&uip->ui_lwpcnt, diff); KASSERTMSG(lwpcnt >= 0, "uid=%d diff=%d lwpcnt=%ld", diff --git a/sys/rump/librump/rumpkern/lwproc.c b/sys/rump/librump/rumpkern/lwproc.c index f72aeca6ac34..45dcdbfcdb6f 100644 --- a/sys/rump/librump/rumpkern/lwproc.c +++ b/sys/rump/librump/rumpkern/lwproc.c @@ -182,8 +182,10 @@ lwproc_proc_free(struct proc *p) atomic_dec_uint(&nprocs); proc_leavepgrp(p); /* releases proc_lock */ + mutex_enter(p->p_lock); cred = p->p_cred; chgproccnt(kauth_cred_getuid(cred), -1); + mutex_exit(p->p_lock); rump_proc_vfs_release(p); doexithooks(p); @@ -219,7 +221,7 @@ lwproc_proc_free(struct proc *p) static struct proc * lwproc_newproc(struct proc *parent, struct vmspace *vm, int flags) { - uid_t uid = kauth_cred_getuid(parent->p_cred); + uid_t uid; struct proc *p; /* maxproc not enforced */ @@ -287,7 +289,10 @@ lwproc_newproc(struct proc *parent, struct vmspace *vm, int flags) /* initialize cwd in rump kernels with vfs */ rump_proc_vfs_init(p); + mutex_enter(parent->p_lock); + uid = kauth_cred_getuid(parent->p_cred); chgproccnt(uid, 1); /* not enforced */ + mutex_exit(parent->p_lock); /* publish proc various proc lists */ mutex_enter(&proc_lock); diff --git a/sys/rump/librump/rumpkern/rump.c b/sys/rump/librump/rumpkern/rump.c index 5e3961e989a1..adf4f4eeb4a8 100644 --- a/sys/rump/librump/rumpkern/rump.c +++ b/sys/rump/librump/rumpkern/rump.c @@ -326,7 +326,9 @@ rump_init_callback(void (*cpuinit_callback) (void)) procinit(); proc0_init(); uid_init(); + mutex_enter(proc0.p_lock); chgproccnt(0, 1); + mutex_exit(proc0.p_lock); l->l_proc = &proc0; lwp_update_creds(l); diff --git a/sys/sys/prot.h b/sys/sys/prot.h index ccb82d557e50..27e91a418608 100644 --- a/sys/sys/prot.h +++ b/sys/sys/prot.h @@ -32,6 +32,8 @@ #ifndef _SYS_PROT_H_ #define _SYS_PROT_H_ +#include + /* * flags that control when do_setres{u,g}id will do anything * @@ -53,4 +55,12 @@ int do_setresuid(struct lwp *, uid_t, uid_t, uid_t, u_int); int do_setresgid(struct lwp *, gid_t, gid_t, gid_t, u_int); +void setresuid_begin(struct lwp *, kauth_cred_t *, kauth_cred_t *); +void setresgid_begin(struct lwp *, kauth_cred_t *, kauth_cred_t *); + +int setresuid_commit(struct lwp *, kauth_cred_t, kauth_cred_t, + uid_t, uid_t, uid_t, u_int); +int setresgid_commit(struct lwp *, kauth_cred_t, kauth_cred_t, + gid_t, gid_t, gid_t, u_int); + #endif /* !_SYS_PROT_H_ */