summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_resource.c
diff options
context:
space:
mode:
authorvisa <visa@openbsd.org>2019-01-06 12:59:45 +0000
committervisa <visa@openbsd.org>2019-01-06 12:59:45 +0000
commitec412da11be49c25266553c64da7e06a018ba909 (patch)
tree448321fd2d08343c136e4be46e6c0fcbf75db7c3 /sys/kern/kern_resource.c
parentRewrite ip_pcbopts() to fill a fresh mbuf with the ip options instead (diff)
downloadwireguard-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.c40
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;
/*