diff options
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_event.c | 2 | ||||
-rw-r--r-- | sys/kern/kern_ktrace.c | 2 | ||||
-rw-r--r-- | sys/kern/kern_proc.c | 12 | ||||
-rw-r--r-- | sys/kern/kern_prot.c | 152 | ||||
-rw-r--r-- | sys/kern/kern_resource.c | 21 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 2 | ||||
-rw-r--r-- | sys/kern/sys_process.c | 14 |
7 files changed, 167 insertions, 38 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index 74d5fa7..0444d7e 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -200,7 +200,7 @@ filt_procattach(struct knote *kn) p = pfind(kn->kn_id); if (p == NULL) return (ESRCH); - if (! PRISON_CHECK(curproc, p)) + if (p_can(curproc, p, P_CAN_SEE, NULL)) return (EACCES); kn->kn_ptr.p_proc = p; diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c index b0530f9..ef82c6c 100644 --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -513,6 +513,8 @@ ktrwrite(vp, kth, uio) * root previously set the tracing status on the target process, and * so, only root may further change it. * + * XXX: These checks are stronger than for ptrace() + * * TODO: check groups. use caller effective gid. */ static int diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 4a4282a..ebff074 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -55,7 +55,7 @@ MALLOC_DEFINE(M_SESSION, "session", "session header"); static MALLOC_DEFINE(M_PROC, "proc", "Proc structures"); MALLOC_DEFINE(M_SUBPROC, "subproc", "Proc sub-structures"); -static int ps_showallprocs = 1; +int ps_showallprocs = 1; SYSCTL_INT(_kern, OID_AUTO, ps_showallprocs, CTLFLAG_RW, &ps_showallprocs, 0, ""); @@ -586,7 +586,7 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS) p = pfind((pid_t)name[0]); if (!p) return (0); - if (!PRISON_CHECK(curproc, p)) + if (p_can(curproc, p, P_CAN_SEE, NULL)) return (0); error = sysctl_out_proc(p, req, 0); return (error); @@ -611,9 +611,9 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS) p = LIST_FIRST(&zombproc); for (; p != 0; p = LIST_NEXT(p, p_list)) { /* - * Show a user only their processes. + * Show a user only appropriate processes. */ - if ((!ps_showallprocs) && p_trespass(curproc, p)) + if (p_can(curproc, p, P_CAN_SEE, NULL)) continue; /* * Skip embryonic processes. @@ -655,7 +655,7 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS) break; } - if (!PRISON_CHECK(curproc, p)) + if (p_can(curproc, p, P_CAN_SEE, NULL)) continue; error = sysctl_out_proc(p, req, doingzomb); @@ -688,7 +688,7 @@ sysctl_kern_proc_args(SYSCTL_HANDLER_ARGS) if (!p) return (0); - if ((!ps_argsopen) && p_trespass(curproc, p)) + if ((!ps_argsopen) && p_can(curproc, p, P_CAN_SEE, NULL)) return (0); if (req->newptr && curproc != p) diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index 33007e7..0750466 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -945,15 +945,15 @@ SYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0, */ int suser(p) - struct proc *p; + const struct proc *p; { return suser_xxx(0, p, 0); } int suser_xxx(cred, proc, flag) - struct ucred *cred; - struct proc *proc; + const struct ucred *cred; + const struct proc *proc; int flag; { if (!suser_permitted) @@ -971,31 +971,165 @@ suser_xxx(cred, proc, flag) return (0); } -/* - * Return zero if p1 can fondle p2, return errno (EPERM/ESRCH) otherwise. - */ +static int +p_cansee(const struct proc *p1, const struct proc *p2, int *privused) +{ -int -p_trespass(struct proc *p1, struct proc *p2) + if (privused != NULL) + *privused = 0; + + if (!PRISON_CHECK(p1, p2)) + return (ESRCH); + + if (!ps_showallprocs && (p1->p_ucred->cr_uid != p2->p_ucred->cr_uid) && + suser_xxx(NULL, p1, PRISON_ROOT)) + return (ESRCH); + + return (0); +} + +static int +p_cankill(const struct proc *p1, const struct proc *p2, int *privused) +{ + + if (privused != NULL) + *privused = 0; + + if (p1 == p2) + return (0); + + if (!PRISON_CHECK(p1, p2)) + return (ESRCH); + + if (p1->p_cred->p_ruid == p2->p_cred->p_ruid) + return (0); + if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid) + return (0); + /* + * XXX should a process be able to affect another process + * acting as the same uid (i.e., a userland nfsd or the like?) + */ + if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid) + return (0); + if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid) + return (0); + + if (!suser_xxx(0, p1, PRISON_ROOT)) { + if (privused != NULL) + *privused = 1; + return (0); + } + +#ifdef CAPABILITIES + if (!cap_check_xxx(0, p1, CAP_KILL, PRISON_ROOT)) { + if (privused != NULL) + *privused = 1; + return (0); + } +#endif + + return (EPERM); +} + +static int +p_cansched(const struct proc *p1, const struct proc *p2, int *privused) { + if (privused != NULL) + *privused = 0; + if (p1 == p2) return (0); + if (!PRISON_CHECK(p1, p2)) return (ESRCH); + if (p1->p_cred->p_ruid == p2->p_cred->p_ruid) return (0); if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid) return (0); + /* + * XXX should a process be able to affect another process + * acting as the same uid (i.e., a userland nfsd or the like?) + */ if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid) return (0); if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid) return (0); - if (!suser_xxx(0, p1, PRISON_ROOT)) + + if (!suser_xxx(0, p1, PRISON_ROOT)) { + if (privused != NULL) + *privused = 1; + return (0); + } + +#ifdef CAPABILITIES + if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT)) { + if (privused != NULL) + *privused = 1; return (0); + } +#endif + return (EPERM); } +static int +p_candebug(const struct proc *p1, const struct proc *p2, int *privused) +{ + int error; + + if (privused != NULL) + *privused = 0; + + /* XXX it is authorized, but semantics don't permit it */ + if (p1 == p2) + return (0); + + if (!PRISON_CHECK(p1, p2)) + return (ESRCH); + + /* not owned by you, has done setuid (unless you're root) */ + /* add a CAP_SYS_PTRACE here? */ + if ((p1->p_cred->p_ruid != p2->p_cred->p_ruid) || + (p2->p_flag & P_SUGID)) { + if ((error = suser_xxx(0, p1, PRISON_ROOT))) + return (error); + if (privused != NULL) + *privused = 1; + } + + /* can't trace init when securelevel > 0 */ + if (securelevel > 0 && p2->p_pid == 1) + return (EPERM); + + return (0); +} + +int +p_can(const struct proc *p1, const struct proc *p2, int operation, + int *privused) +{ + + switch(operation) { + case P_CAN_SEE: + return (p_cansee(p1, p2, privused)); + + case P_CAN_KILL: + return (p_cankill(p1, p2, privused)); + + case P_CAN_SCHED: + return (p_cansched(p1, p2, privused)); + + case P_CAN_DEBUG: + return (p_candebug(p1, p2, privused)); + + default: + panic("p_can: invalid operation"); + } +} + + /* * Allocate a zeroed cred structure. */ diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index 5af09c9..b3c2ec6 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -88,7 +88,7 @@ getpriority(curp, uap) p = pfind(uap->who); if (p == 0) break; - if (!PRISON_CHECK(curp, p)) + if (p_can(curp, p, P_CAN_SEE, NULL)) break; low = p->p_nice; break; @@ -101,7 +101,7 @@ getpriority(curp, uap) else if ((pg = pgfind(uap->who)) == NULL) break; LIST_FOREACH(p, &pg->pg_members, p_pglist) { - if ((PRISON_CHECK(curp, p) && p->p_nice < low)) + if (!p_can(curp, p, P_CAN_SEE, NULL) && p->p_nice < low) low = p->p_nice; } break; @@ -111,7 +111,7 @@ getpriority(curp, uap) if (uap->who == 0) uap->who = curp->p_ucred->cr_uid; LIST_FOREACH(p, &allproc, p_list) - if (PRISON_CHECK(curp, p) && + if (!p_can(curp, p, P_CAN_SEE, NULL) && p->p_ucred->cr_uid == uap->who && p->p_nice < low) low = p->p_nice; @@ -151,7 +151,7 @@ setpriority(curp, uap) p = pfind(uap->who); if (p == 0) break; - if (!PRISON_CHECK(curp, p)) + if (p_can(curp, p, P_CAN_SEE, NULL)) break; error = donice(curp, p, uap->prio); found++; @@ -165,7 +165,7 @@ setpriority(curp, uap) else if ((pg = pgfind(uap->who)) == NULL) break; LIST_FOREACH(p, &pg->pg_members, p_pglist) { - if (PRISON_CHECK(curp, p)) { + if (!p_can(curp, p, P_CAN_SEE, NULL)) { error = donice(curp, p, uap->prio); found++; } @@ -178,7 +178,7 @@ setpriority(curp, uap) uap->who = curp->p_ucred->cr_uid; LIST_FOREACH(p, &allproc, p_list) if (p->p_ucred->cr_uid == uap->who && - PRISON_CHECK(curp, p)) { + !p_can(curp, p, P_CAN_SEE, NULL)) { error = donice(curp, p, uap->prio); found++; } @@ -197,9 +197,10 @@ donice(curp, chgp, n) register struct proc *curp, *chgp; register int n; { + int error; - if (p_trespass(curp, chgp) != 0) - return (EPERM); + if ((error = p_can(curp, chgp, P_CAN_SCHED, NULL))) + return (error); if (n > PRIO_MAX) n = PRIO_MAX; if (n < PRIO_MIN) @@ -250,8 +251,8 @@ rtprio(curp, uap) case RTP_LOOKUP: return (copyout(&p->p_rtprio, uap->rtp, sizeof(struct rtprio))); case RTP_SET: - if (p_trespass(curp, p) != 0) - return (EPERM); + if ((error = p_can(curp, p, P_CAN_SCHED, NULL))) + return (error); /* disallow setting rtprio in most cases if not superuser */ if (suser(curp) != 0) { /* can't set someone else's */ diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index db3f46f..a2ff2ef 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -97,7 +97,7 @@ SYSCTL_INT(_kern, KERN_LOGSIGEXIT, logsigexit, CTLFLAG_RW, * Can process p, with pcred pc, send the signal sig to process q? */ #define CANSIGNAL(p, q, sig) \ - (!p_trespass(p, q) || \ + (!p_can(p, q, P_CAN_KILL, NULL) || \ ((sig) == SIGCONT && (q)->p_session == (p)->p_session)) /* diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 4740476..0292961 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -217,7 +217,7 @@ ptrace(curp, uap) if ((p = pfind(uap->pid)) == NULL) return ESRCH; } - if (!PRISON_CHECK(curp, p)) + if (p_can(curp, p, P_CAN_SEE, NULL)) return (ESRCH); /* @@ -237,16 +237,8 @@ ptrace(curp, uap) if (p->p_flag & P_TRACED) return EBUSY; - /* not owned by you, has done setuid (unless you're root) */ - if ((p->p_cred->p_ruid != curp->p_cred->p_ruid) || - (p->p_flag & P_SUGID)) { - if ((error = suser(curp)) != 0) - return error; - } - - /* can't trace init when securelevel > 0 */ - if (securelevel > 0 && p->p_pid == 1) - return EPERM; + if ((error = p_can(curp, p, P_CAN_DEBUG, NULL))) + return error; /* OK */ break; |