diff options
author | 2019-01-06 12:59:45 +0000 | |
---|---|---|
committer | 2019-01-06 12:59:45 +0000 | |
commit | ec412da11be49c25266553c64da7e06a018ba909 (patch) | |
tree | 448321fd2d08343c136e4be46e6c0fcbf75db7c3 /sys/kern/kern_resource.c | |
parent | Rewrite ip_pcbopts() to fill a fresh mbuf with the ip options instead (diff) | |
download | wireguard-openbsd-ec412da11be49c25266553c64da7e06a018ba909.tar.xz wireguard-openbsd-ec412da11be49c25266553c64da7e06a018ba909.zip |
Fix unsafe use of ptsignal() in mi_switch().
ptsignal() has to be called with the kernel lock held. As ensuring the
locking in mi_switch() is not easy, and deferring the signaling using
the task API is not possible because of lock order issues in
mi_switch(), move the CPU time checking into a periodic timer where
the kernel can be locked without issues.
With this change, each process has a dedicated resource check timer.
The timer gets activated only when a CPU time limit is set. Because the
checking is not done as frequently as before, some precision is lost.
Use of timers adapted from FreeBSD.
OK tedu@
Reported-by: syzbot+2f5d62256e3280634623@syzkaller.appspotmail.com
Diffstat (limited to 'sys/kern/kern_resource.c')
-rw-r--r-- | sys/kern/kern_resource.c | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index 184c538d2ef..e80439fdb6b 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_resource.c,v 1.58 2018/02/19 08:59:52 mpi Exp $ */ +/* $OpenBSD: kern_resource.c,v 1.59 2019/01/06 12:59:45 visa Exp $ */ /* $NetBSD: kern_resource.c,v 1.38 1996/10/23 07:19:38 matthias Exp $ */ /*- @@ -46,6 +46,7 @@ #include <sys/proc.h> #include <sys/ktrace.h> #include <sys/sched.h> +#include <sys/signalvar.h> #include <sys/mount.h> #include <sys/syscallargs.h> @@ -267,6 +268,10 @@ dosetrlimit(struct proc *p, u_int which, struct rlimit *limp) if (limp->rlim_cur > limp->rlim_max) limp->rlim_cur = limp->rlim_max; + if (which == RLIMIT_CPU && limp->rlim_cur != RLIM_INFINITY && + alimp->rlim_cur == RLIM_INFINITY) + timeout_add_msec(&p->p_p->ps_rucheck_to, RUCHECK_INTERVAL); + if (which == RLIMIT_STACK) { /* * Stack is allocated to the max at exec time with only @@ -492,6 +497,39 @@ ruadd(struct rusage *ru, struct rusage *ru2) *ip++ += *ip2++; } +/* + * Check if the process exceeds its cpu resource allocation. + * If over max, kill it. + */ +void +rucheck(void *arg) +{ + struct process *pr = arg; + struct rlimit *rlim; + rlim_t runtime; + int s; + + KERNEL_ASSERT_LOCKED(); + + SCHED_LOCK(s); + runtime = pr->ps_tu.tu_runtime.tv_sec; + SCHED_UNLOCK(s); + + rlim = &pr->ps_limit->pl_rlimit[RLIMIT_CPU]; + if (runtime >= rlim->rlim_cur) { + if (runtime >= rlim->rlim_max) { + prsignal(pr, SIGKILL); + } else { + prsignal(pr, SIGXCPU); + if (rlim->rlim_cur < rlim->rlim_max) + rlim->rlim_cur = MIN(rlim->rlim_cur + 5, + rlim->rlim_max); + } + } + + timeout_add_msec(&pr->ps_rucheck_to, RUCHECK_INTERVAL); +} + struct pool plimit_pool; /* |