summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man9/Makefile4
-rw-r--r--share/man/man9/lim_cur.9119
-rw-r--r--share/man/man9/uvm.98
-rw-r--r--sys/kern/exec_subr.c4
-rw-r--r--sys/kern/init_main.c4
-rw-r--r--sys/kern/kern_descrip.c8
-rw-r--r--sys/kern/kern_exec.c4
-rw-r--r--sys/kern/kern_exit.c13
-rw-r--r--sys/kern/kern_fork.c11
-rw-r--r--sys/kern/kern_resource.c190
-rw-r--r--sys/kern/kern_sig.c5
-rw-r--r--sys/kern/sys_generic.c4
-rw-r--r--sys/kern/vfs_vnops.c4
-rw-r--r--sys/sys/proc.h13
-rw-r--r--sys/sys/resourcevar.h39
-rw-r--r--sys/sys/sysctl.h12
-rw-r--r--sys/uvm/uvm_extern.h6
-rw-r--r--sys/uvm/uvm_glue.c15
-rw-r--r--sys/uvm/uvm_mmap.c26
-rw-r--r--sys/uvm/uvm_unix.c6
20 files changed, 409 insertions, 86 deletions
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
index 8829966881c..e92d1f3e2e1 100644
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.294 2019/06/03 01:27:30 cheloha Exp $
+# $OpenBSD: Makefile,v 1.295 2019/06/21 09:39:48 visa Exp $
# $NetBSD: Makefile,v 1.4 1996/01/09 03:23:01 thorpej Exp $
# Makefile for section 9 (kernel function and variable) manual pages.
@@ -21,7 +21,7 @@ MAN= aml_evalnode.9 atomic_add_int.9 atomic_cas_uint.9 \
ieee80211_radiotap.9 if_get.9 if_rxr_init.9 ifq_enqueue.9 \
ifq_deq_begin.9 imax.9 iic.9 intro.9 inittodr.9 intr_barrier.9 \
KASSERT.9 km_alloc.9 knote.9 kthread.9 ktrace.9 \
- loadfirmware.9 log.9 \
+ lim_cur.9 loadfirmware.9 log.9 \
malloc.9 membar_sync.9 memcmp.9 mbuf.9 mbuf_tags.9 md5.9 mi_switch.9 \
microtime.9 ml_init.9 mq_init.9 mutex.9 \
namei.9 \
diff --git a/share/man/man9/lim_cur.9 b/share/man/man9/lim_cur.9
new file mode 100644
index 00000000000..c05133f760e
--- /dev/null
+++ b/share/man/man9/lim_cur.9
@@ -0,0 +1,119 @@
+.\" $OpenBSD: lim_cur.9,v 1.1 2019/06/21 09:39:48 visa Exp $
+.\"
+.\" Copyright (c) 2019 Visa Hankala
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: June 21 2019 $
+.Dt LIM_CUR 9
+.Os
+.Sh NAME
+.Nm lim_cur ,
+.Nm lim_cur_proc ,
+.Nm lim_fork ,
+.Nm lim_free ,
+.Nm lim_read_enter ,
+.Nm lim_read_leave
+.Nd Resource limit interface
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/resourcevar.h
+.Ft rlim_t
+.Fn "lim_cur" "int which"
+.Ft rlim_t
+.Fn "lim_cur_proc" "struct proc *p" "int which"
+.Ft struct plimit *
+.Fn "lim_fork" "struct process *parent" "struct process *child"
+.Ft void
+.Fn "lim_free" "struct plimit *limit"
+.Ft struct plimit *
+.Fn "lim_read_enter"
+.Ft void
+.Fn "lim_read_leave" "struct plimit *limit"
+.Sh DESCRIPTION
+The resource limit interface provides read access to the resource limits
+of the process.
+.Pp
+.Fn lim_cur
+returns the value of limit
+.Fa which
+of the current process.
+The
+.Fa which
+can take one of the following values:
+.Bd -literal
+#define RLIMIT_CPU 0 /* cpu time in milliseconds */
+#define RLIMIT_FSIZE 1 /* maximum file size */
+#define RLIMIT_DATA 2 /* data size */
+#define RLIMIT_STACK 3 /* stack size */
+#define RLIMIT_CORE 4 /* core file size */
+#define RLIMIT_RSS 5 /* resident set size */
+#define RLIMIT_MEMLOCK 6 /* locked-in-memory address space */
+#define RLIMIT_NPROC 7 /* number of processes */
+#define RLIMIT_NOFILE 8 /* number of open files */
+.Ed
+.Pp
+.Fn lim_cur_proc
+is like
+.Fn lim_cur
+but returns the value of limit
+.Fa which
+of thread
+.Fa p .
+.Pp
+.Fn lim_read_enter
+begins read access to the current process' resource limit structure.
+.Pp
+.Fn lim_read_leave
+finishes read access to the resource limit structure.
+.Pp
+Sections denoted by
+.Fn lim_read_enter
+and
+.Fn lim_read_leave
+cannot nest.
+It is not allowed to use
+.Fn lim_cur
+inside the read section
+because the function uses
+.Fn lim_read_enter
+and
+.Fn lim_read_leave
+internally.
+.Pp
+.Fn lim_free
+releases the reference
+.Fa limit .
+.Pp
+.Fn lim_fork
+makes the process
+.Fa child
+share the resource limits of process
+.Fa parent .
+.Sh CONTEXT
+.Fn lim_cur ,
+.Fn lim_cur_proc ,
+.Fn lim_fork ,
+.Fn lim_free ,
+.Fn lim_read_enter
+and
+.Fn lim_read_leave
+can be called during autoconf, or from process context.
+.Sh RETURN VALUES
+.Fn lim_cur
+and
+.Fn lim_cur_proc
+return the value of the given resource limit.
+.Pp
+.Fn lim_read_enter
+returns a read reference to the current process' resource limits.
diff --git a/share/man/man9/uvm.9 b/share/man/man9/uvm.9
index af1d5d01b34..7a2dd78c20d 100644
--- a/share/man/man9/uvm.9
+++ b/share/man/man9/uvm.9
@@ -1,4 +1,4 @@
-.\" $OpenBSD: uvm.9,v 1.69 2018/06/19 22:35:07 krw Exp $
+.\" $OpenBSD: uvm.9,v 1.70 2019/06/21 09:39:48 visa Exp $
.\" $NetBSD: uvm.9,v 1.14 2000/06/29 06:08:44 mrg Exp $
.\"
.\" Copyright (c) 1998 Matthew R. Green
@@ -30,7 +30,7 @@
.\" XXX this manual sets nS to 1 or 0 in the description, to obtain
.\" synopsis-like function prototypes. any better way?
.\"
-.Dd $Mdocdate: June 19 2018 $
+.Dd $Mdocdate: June 21 2019 $
.Dt UVM_INIT 9
.Os
.Sh NAME
@@ -132,7 +132,7 @@ for the machine dependent layer.
.Ft void
.Fn uvm_init "void"
.Ft void
-.Fn uvm_init_limits "struct proc *p"
+.Fn uvm_init_limits "struct plimit *limit0"
.Ft void
.Fn uvm_setpagesize "void"
.Ft void
@@ -155,7 +155,7 @@ function.
.Pp
The
.Fn uvm_init_limits
-function initialises process limits for the named process.
+function initialises process limits in the given limit structure.
This is for use by the system startup for process zero, before any other
processes are created.
.Pp
diff --git a/sys/kern/exec_subr.c b/sys/kern/exec_subr.c
index f2282a4a357..f32be4bddf4 100644
--- a/sys/kern/exec_subr.c
+++ b/sys/kern/exec_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: exec_subr.c,v 1.55 2018/04/12 17:13:44 deraadt Exp $ */
+/* $OpenBSD: exec_subr.c,v 1.56 2019/06/21 09:39:48 visa Exp $ */
/* $NetBSD: exec_subr.c,v 1.9 1994/12/04 03:10:42 mycroft Exp $ */
/*
@@ -351,7 +351,7 @@ exec_setup_stack(struct proc *p, struct exec_package *epp)
epp->ep_maxsaddr = USRSTACK - MAXSSIZ - MAXSSIZ_GUARD;
epp->ep_minsaddr = USRSTACK;
#endif
- epp->ep_ssize = round_page(p->p_rlimit[RLIMIT_STACK].rlim_cur);
+ epp->ep_ssize = round_page(lim_cur(RLIMIT_STACK));
if (stackgap_random != 0) {
sgap = arc4random() & (stackgap_random - 1);
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index b4bacaae1b7..a6a2b6da51e 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: init_main.c,v 1.289 2019/06/20 14:55:22 anton Exp $ */
+/* $OpenBSD: init_main.c,v 1.290 2019/06/21 09:39:48 visa Exp $ */
/* $NetBSD: init_main.c,v 1.84.4.1 1996/06/02 09:08:06 mrg Exp $ */
/*
@@ -373,7 +373,7 @@ main(void *framep)
cpu_configure();
/* Configure virtual memory system, set vm rlimits. */
- uvm_init_limits(p);
+ uvm_init_limits(&limit0);
/* Per CPU memory allocation */
percpu_init();
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 7da5dadb4ee..45fae009691 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_descrip.c,v 1.184 2019/05/13 17:31:51 deraadt Exp $ */
+/* $OpenBSD: kern_descrip.c,v 1.185 2019/06/21 09:39:48 visa Exp $ */
/* $NetBSD: kern_descrip.c,v 1.42 1996/03/30 22:24:38 christos Exp $ */
/*
@@ -353,7 +353,7 @@ restart:
FRELE(fp, p);
return (0);
}
- if ((u_int)new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
+ if ((u_int)new >= lim_cur(RLIMIT_NOFILE) ||
(u_int)new >= maxfiles) {
FRELE(fp, p);
return (EBADF);
@@ -414,7 +414,7 @@ restart:
case F_DUPFD:
case F_DUPFD_CLOEXEC:
newmin = (long)SCARG(uap, arg);
- if ((u_int)newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
+ if ((u_int)newmin >= lim_cur(RLIMIT_NOFILE) ||
(u_int)newmin >= maxfiles) {
error = EINVAL;
break;
@@ -864,7 +864,7 @@ fdalloc(struct proc *p, int want, int *result)
* expanding the ofile array.
*/
restart:
- lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
+ lim = min((int)lim_cur(RLIMIT_NOFILE), maxfiles);
last = min(fdp->fd_nfiles, lim);
if ((i = want) < fdp->fd_freefile)
i = fdp->fd_freefile;
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 3019366cb1c..301d847f1c8 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_exec.c,v 1.205 2019/06/01 14:11:17 mpi Exp $ */
+/* $OpenBSD: kern_exec.c,v 1.206 2019/06/21 09:39:48 visa Exp $ */
/* $NetBSD: kern_exec.c,v 1.75 1996/02/09 18:59:28 christos Exp $ */
/*-
@@ -201,7 +201,7 @@ check_exec(struct proc *p, struct exec_package *epp)
/* check limits */
if ((epp->ep_tsize > MAXTSIZ) ||
- (epp->ep_dsize > p->p_rlimit[RLIMIT_DATA].rlim_cur))
+ (epp->ep_dsize > lim_cur(RLIMIT_DATA)))
error = ENOMEM;
if (!error)
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 74ac47d02f8..ab2f0de086d 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_exit.c,v 1.177 2019/06/13 21:19:28 mpi Exp $ */
+/* $OpenBSD: kern_exit.c,v 1.178 2019/06/21 09:39:48 visa Exp $ */
/* $NetBSD: kern_exit.c,v 1.39 1996/04/22 01:38:25 christos Exp $ */
/*
@@ -328,6 +328,15 @@ exit1(struct proc *p, int rv, int flags)
KASSERT(pr->ps_refcnt > 0);
}
+ /* Release the thread's read reference of resource limit structure. */
+ if (p->p_limit != NULL) {
+ struct plimit *limit;
+
+ limit = p->p_limit;
+ p->p_limit = NULL;
+ lim_free(limit);
+ }
+
/*
* Other substructures are freed from reaper and wait().
*/
@@ -636,7 +645,7 @@ process_zap(struct process *pr)
free(pr->ps_ptstat, M_SUBPROC, sizeof(*pr->ps_ptstat));
pool_put(&rusage_pool, pr->ps_ru);
KASSERT(TAILQ_EMPTY(&pr->ps_threads));
- limfree(pr->ps_limit);
+ lim_free(pr->ps_limit);
crfree(pr->ps_ucred);
pool_put(&process_pool, pr);
nprocesses--;
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 190c749720e..95180d9de31 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_fork.c,v 1.212 2019/06/01 14:11:17 mpi Exp $ */
+/* $OpenBSD: kern_fork.c,v 1.213 2019/06/21 09:39:48 visa Exp $ */
/* $NetBSD: kern_fork.c,v 1.29 1996/02/09 18:59:34 christos Exp $ */
/*
@@ -151,6 +151,7 @@ thread_new(struct proc *parent, vaddr_t uaddr)
p = pool_get(&proc_pool, PR_WAITOK);
p->p_stat = SIDL; /* protect against others */
p->p_flag = 0;
+ p->p_limit = NULL;
/*
* Make a proc table entry for the new process.
@@ -210,6 +211,8 @@ process_initialize(struct process *pr, struct proc *p)
LIST_INIT(&pr->ps_kqlist);
LIST_INIT(&pr->ps_sigiolst);
+ mtx_init(&pr->ps_mtx, IPL_MPFLOOR);
+
timeout_set(&pr->ps_realit_to, realitexpire, pr);
timeout_set(&pr->ps_rucheck_to, rucheck, pr);
}
@@ -237,12 +240,10 @@ process_new(struct proc *p, struct process *parent, int flags)
process_initialize(pr, p);
pr->ps_pid = allocpid();
+ lim_fork(parent, pr);
/* post-copy fixups */
pr->ps_pptr = parent;
- pr->ps_limit->pl_refcnt++;
- if (pr->ps_limit->pl_rlimit[RLIMIT_CPU].rlim_cur != RLIM_INFINITY)
- timeout_add_msec(&pr->ps_rucheck_to, RUCHECK_INTERVAL);
/* bump references to the text vnode (for sysctl) */
pr->ps_textvp = parent->ps_textvp;
@@ -373,7 +374,7 @@ fork1(struct proc *curp, int flags, void (*func)(void *), void *arg,
* Don't allow a nonprivileged user to exceed their current limit.
*/
count = chgproccnt(uid, 1);
- if (uid != 0 && count > curp->p_rlimit[RLIMIT_NPROC].rlim_cur) {
+ if (uid != 0 && count > lim_cur(RLIMIT_NPROC)) {
(void)chgproccnt(uid, -1);
nprocesses--;
nthreads--;
diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c
index 3bc9425020a..050326ab6fd 100644
--- a/sys/kern/kern_resource.c
+++ b/sys/kern/kern_resource.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_resource.c,v 1.64 2019/06/10 03:15:53 visa Exp $ */
+/* $OpenBSD: kern_resource.c,v 1.65 2019/06/21 09:39:48 visa Exp $ */
/* $NetBSD: kern_resource.c,v 1.38 1996/10/23 07:19:38 matthias Exp $ */
/*-
@@ -53,9 +53,16 @@
#include <uvm/uvm_extern.h>
+/* Resource usage check interval in msec */
+#define RUCHECK_INTERVAL 1000
+
/* SIGXCPU interval in seconds of process runtime */
#define SIGXCPU_INTERVAL 5
+struct plimit *lim_copy(struct plimit *);
+struct plimit *lim_write_begin(void);
+void lim_write_commit(struct plimit *);
+
void tuagg_sub(struct tusage *, struct proc *);
/*
@@ -65,6 +72,13 @@ rlim_t maxdmap = MAXDSIZ;
rlim_t maxsmap = MAXSSIZ;
/*
+ * Serializes resource limit updates.
+ * This lock has to be held together with ps_mtx when updating
+ * the process' ps_limit.
+ */
+struct rwlock rlimit_lock = RWLOCK_INITIALIZER("rlimitlk");
+
+/*
* Resource controls and accounting.
*/
@@ -229,25 +243,27 @@ int
dosetrlimit(struct proc *p, u_int which, struct rlimit *limp)
{
struct rlimit *alimp;
+ struct plimit *limit;
rlim_t maxlim;
int error;
if (which >= RLIM_NLIMITS || limp->rlim_cur > limp->rlim_max)
return (EINVAL);
- alimp = &p->p_rlimit[which];
- if (limp->rlim_max > alimp->rlim_max)
- if ((error = suser(p)) != 0)
- return (error);
- if (p->p_p->ps_limit->pl_refcnt > 1) {
- struct plimit *l = p->p_p->ps_limit;
+ rw_enter_write(&rlimit_lock);
- /* limcopy() can sleep, so copy before decrementing refcnt */
- p->p_p->ps_limit = limcopy(l);
- limfree(l);
- alimp = &p->p_rlimit[which];
+ alimp = &p->p_p->ps_limit->pl_rlimit[which];
+ if (limp->rlim_max > alimp->rlim_max) {
+ if ((error = suser(p)) != 0) {
+ rw_exit_write(&rlimit_lock);
+ return (error);
+ }
}
+ /* Get exclusive write access to the limit structure. */
+ limit = lim_write_begin();
+ alimp = &limit->pl_rlimit[which];
+
switch (which) {
case RLIMIT_DATA:
maxlim = maxdmap;
@@ -316,6 +332,10 @@ dosetrlimit(struct proc *p, u_int which, struct rlimit *limp)
}
*alimp = *limp;
+
+ lim_write_commit(limit);
+ rw_exit_write(&rlimit_lock);
+
return (0);
}
@@ -326,16 +346,19 @@ sys_getrlimit(struct proc *p, void *v, register_t *retval)
syscallarg(int) which;
syscallarg(struct rlimit *) rlp;
} */ *uap = v;
- struct rlimit *alimp;
+ struct plimit *limit;
+ struct rlimit alimp;
int error;
if (SCARG(uap, which) < 0 || SCARG(uap, which) >= RLIM_NLIMITS)
return (EINVAL);
- alimp = &p->p_rlimit[SCARG(uap, which)];
- error = copyout(alimp, SCARG(uap, rlp), sizeof(struct rlimit));
+ limit = lim_read_enter();
+ alimp = limit->pl_rlimit[SCARG(uap, which)];
+ lim_read_leave(limit);
+ error = copyout(&alimp, SCARG(uap, rlp), sizeof(struct rlimit));
#ifdef KTRACE
if (error == 0 && KTRPOINT(p, KTR_STRUCT))
- ktrrlimit(p, alimp);
+ ktrrlimit(p, &alimp);
#endif
return (error);
}
@@ -507,8 +530,8 @@ ruadd(struct rusage *ru, struct rusage *ru2)
void
rucheck(void *arg)
{
+ struct rlimit rlim;
struct process *pr = arg;
- struct rlimit *rlim;
time_t runtime;
int s;
@@ -518,9 +541,12 @@ rucheck(void *arg)
runtime = pr->ps_tu.tu_runtime.tv_sec;
SCHED_UNLOCK(s);
- rlim = &pr->ps_limit->pl_rlimit[RLIMIT_CPU];
- if ((rlim_t)runtime >= rlim->rlim_cur) {
- if ((rlim_t)runtime >= rlim->rlim_max) {
+ mtx_enter(&pr->ps_mtx);
+ rlim = pr->ps_limit->pl_rlimit[RLIMIT_CPU];
+ mtx_leave(&pr->ps_mtx);
+
+ if ((rlim_t)runtime >= rlim.rlim_cur) {
+ if ((rlim_t)runtime >= rlim.rlim_max) {
prsignal(pr, SIGKILL);
} else if (runtime >= pr->ps_nextxcpu) {
prsignal(pr, SIGXCPU);
@@ -562,7 +588,7 @@ lim_startup(struct plimit *limit0)
* and copy when a limit is changed.
*/
struct plimit *
-limcopy(struct plimit *lim)
+lim_copy(struct plimit *lim)
{
struct plimit *newlim;
@@ -574,9 +600,129 @@ limcopy(struct plimit *lim)
}
void
-limfree(struct plimit *lim)
+lim_free(struct plimit *lim)
{
- if (--lim->pl_refcnt > 0)
+ if (atomic_dec_int_nv(&lim->pl_refcnt) > 0)
return;
pool_put(&plimit_pool, lim);
}
+
+void
+lim_fork(struct process *parent, struct process *child)
+{
+ struct plimit *limit;
+
+ mtx_enter(&parent->ps_mtx);
+ limit = parent->ps_limit;
+ atomic_inc_int(&limit->pl_refcnt);
+ mtx_leave(&parent->ps_mtx);
+
+ child->ps_limit = limit;
+
+ if (limit->pl_rlimit[RLIMIT_CPU].rlim_cur != RLIM_INFINITY)
+ timeout_add_msec(&child->ps_rucheck_to, RUCHECK_INTERVAL);
+}
+
+/*
+ * Return an exclusive write reference to the process' resource limit structure.
+ * The caller has to release the structure by calling lim_write_commit().
+ *
+ * This invalidates any plimit read reference held by the calling thread.
+ */
+struct plimit *
+lim_write_begin(void)
+{
+ struct plimit *limit;
+ struct proc *p = curproc;
+
+ rw_assert_wrlock(&rlimit_lock);
+
+ if (p->p_limit != NULL)
+ lim_free(p->p_limit);
+ p->p_limit = NULL;
+
+ /*
+ * It is safe to access ps_limit here without holding ps_mtx
+ * because rlimit_lock excludes other writers.
+ */
+
+ limit = p->p_p->ps_limit;
+ if (P_HASSIBLING(p) || limit->pl_refcnt > 1)
+ limit = lim_copy(limit);
+
+ return (limit);
+}
+
+/*
+ * Finish exclusive write access to the plimit structure.
+ * This makes the structure visible to other threads in the process.
+ */
+void
+lim_write_commit(struct plimit *limit)
+{
+ struct plimit *olimit;
+ struct proc *p = curproc;
+
+ rw_assert_wrlock(&rlimit_lock);
+
+ if (limit != p->p_p->ps_limit) {
+ mtx_enter(&p->p_p->ps_mtx);
+ olimit = p->p_p->ps_limit;
+ p->p_p->ps_limit = limit;
+ mtx_leave(&p->p_p->ps_mtx);
+
+ lim_free(olimit);
+ }
+}
+
+/*
+ * Begin read access to the process' resource limit structure.
+ * The access has to be finished by calling lim_read_leave().
+ *
+ * Sections denoted by lim_read_enter() and lim_read_leave() cannot nest.
+ */
+struct plimit *
+lim_read_enter(void)
+{
+ struct plimit *limit;
+ struct proc *p = curproc;
+ struct process *pr = p->p_p;
+
+ /*
+ * This thread might not observe the latest value of ps_limit
+ * if another thread updated the limits very recently on another CPU.
+ * However, the anomaly should disappear quickly, especially if
+ * there is any synchronization activity between the threads (or
+ * the CPUs).
+ */
+
+ limit = p->p_limit;
+ if (limit != pr->ps_limit) {
+ mtx_enter(&pr->ps_mtx);
+ limit = pr->ps_limit;
+ atomic_inc_int(&limit->pl_refcnt);
+ mtx_leave(&pr->ps_mtx);
+ if (p->p_limit != NULL)
+ lim_free(p->p_limit);
+ p->p_limit = limit;
+ }
+ KASSERT(limit != NULL);
+ return (limit);
+}
+
+/*
+ * Get the value of the resource limit in given process.
+ */
+rlim_t
+lim_cur_proc(struct proc *p, int which)
+{
+ struct process *pr = p->p_p;
+ rlim_t val;
+
+ KASSERT(which >= 0 && which < RLIM_NLIMITS);
+
+ mtx_enter(&pr->ps_mtx);
+ val = pr->ps_limit->pl_rlimit[which].rlim_cur;
+ mtx_leave(&pr->ps_mtx);
+ return (val);
+}
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 4e3efa9c736..5738cd71af1 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_sig.c,v 1.230 2019/05/13 19:21:31 bluhm Exp $ */
+/* $OpenBSD: kern_sig.c,v 1.231 2019/06/21 09:39:48 visa Exp $ */
/* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */
/*
@@ -1548,8 +1548,7 @@ coredump(struct proc *p)
}
/* Don't dump if will exceed file size limit. */
- if (USPACE + ptoa(vm->vm_dsize + vm->vm_ssize) >=
- p->p_rlimit[RLIMIT_CORE].rlim_cur)
+ if (USPACE + ptoa(vm->vm_dsize + vm->vm_ssize) >= lim_cur(RLIMIT_CORE))
return (EFBIG);
if (incrash && nosuidcoredump == 3) {
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index ccb8502ed21..5fb4cf04258 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sys_generic.c,v 1.123 2019/01/21 23:41:26 cheloha Exp $ */
+/* $OpenBSD: sys_generic.c,v 1.124 2019/06/21 09:39:48 visa Exp $ */
/* $NetBSD: sys_generic.c,v 1.24 1996/03/29 00:25:32 cgd Exp $ */
/*
@@ -935,7 +935,7 @@ doppoll(struct proc *p, struct pollfd *fds, u_int nfds,
int timo, ncoll, i, s, error;
/* Standards say no more than MAX_OPEN; this is possibly better. */
- if (nfds > min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles))
+ if (nfds > min((int)lim_cur(RLIMIT_NOFILE), maxfiles))
return (EINVAL);
/* optimize for the default case, of a small nfds value */
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index 2d5d00e5eff..c02f8f0cba1 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_vnops.c,v 1.97 2018/08/20 16:00:22 mpi Exp $ */
+/* $OpenBSD: vfs_vnops.c,v 1.98 2019/06/21 09:39:48 visa Exp $ */
/* $NetBSD: vfs_vnops.c,v 1.20 1996/02/04 02:18:41 christos Exp $ */
/*
@@ -247,7 +247,7 @@ vn_fsizechk(struct vnode *vp, struct uio *uio, int ioflag, ssize_t *overrun)
*overrun = 0;
if (vp->v_type == VREG && p != NULL && !(ioflag & IO_NOLIMIT)) {
- rlim_t limit = p->p_rlimit[RLIMIT_FSIZE].rlim_cur;
+ rlim_t limit = lim_cur_proc(p, RLIMIT_FSIZE);
/* if already at or over the limit, send the signal and fail */
if (uio->uio_offset >= limit) {
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 76aac28ddef..cae61ce0d0c 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proc.h,v 1.269 2019/06/10 03:15:53 visa Exp $ */
+/* $OpenBSD: proc.h,v 1.270 2019/06/21 09:39:48 visa Exp $ */
/* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */
/*-
@@ -154,6 +154,12 @@ RBT_HEAD(unvname_rbt, unvname);
struct futex;
LIST_HEAD(futex_list, futex);
struct unveil;
+
+/*
+ * Locks used to protect struct members in this file:
+ * m this process' `ps_mtx'
+ * r rlimit_lock
+ */
struct process {
/*
* ps_mainproc is the original thread in the process.
@@ -181,6 +187,7 @@ struct process {
struct futex_list ps_ftlist; /* futexes attached to this process */
LIST_HEAD(, kqueue) ps_kqlist; /* kqueues attached to this process */
+ struct mutex ps_mtx; /* per-process mutex */
/* The following fields are all zeroed upon creation in process_new. */
#define ps_startzero ps_klist
@@ -221,7 +228,7 @@ struct process {
/* The following fields are all copied upon creation in process_new. */
#define ps_startcopy ps_limit
- struct plimit *ps_limit; /* Process limits. */
+ struct plimit *ps_limit; /* [m,r] Process limits. */
struct pgrp *ps_pgrp; /* Pointer to process group. */
struct emul *ps_emul; /* Emulation information */
@@ -325,7 +332,7 @@ struct proc {
struct vmspace *p_vmspace; /* copy of p_p->ps_vmspace */
struct p_inentry p_spinentry;
struct p_inentry p_pcinentry;
-#define p_rlimit p_p->ps_limit->pl_rlimit
+ struct plimit *p_limit; /* read reference of p_p->ps_limit */
int p_flag; /* P_* flags. */
u_char p_spare; /* unused */
diff --git a/sys/sys/resourcevar.h b/sys/sys/resourcevar.h
index 4e4988e7d04..4200758bd04 100644
--- a/sys/sys/resourcevar.h
+++ b/sys/sys/resourcevar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: resourcevar.h,v 1.23 2019/06/02 03:58:28 visa Exp $ */
+/* $OpenBSD: resourcevar.h,v 1.24 2019/06/21 09:39:48 visa Exp $ */
/* $NetBSD: resourcevar.h,v 1.12 1995/11/22 23:01:53 cgd Exp $ */
/*
@@ -56,6 +56,9 @@ do { \
} while (0)
#ifdef _KERNEL
+
+#include <lib/libkern/libkern.h> /* for KASSERT() */
+
void addupc_intr(struct proc *, u_long);
void addupc_task(struct proc *, u_long, u_int);
void tuagg_unlocked(struct process *, struct proc *);
@@ -66,11 +69,39 @@ void calctsru(struct tusage *, struct timespec *, struct timespec *,
void calcru(struct tusage *, struct timeval *, struct timeval *,
struct timeval *);
void lim_startup(struct plimit *);
-struct plimit *limcopy(struct plimit *);
-void limfree(struct plimit *);
+void lim_free(struct plimit *);
+void lim_fork(struct process *, struct process *);
+struct plimit *lim_read_enter(void);
+
+/*
+ * Finish read access to resource limits.
+ */
+static inline void
+lim_read_leave(struct plimit *limit)
+{
+ /* nothing */
+}
+
+/*
+ * Get the value of the resource limit in current process.
+ */
+static inline rlim_t
+lim_cur(int which)
+{
+ struct plimit *limit;
+ rlim_t val;
+
+ KASSERT(which >= 0 && which < RLIM_NLIMITS);
+
+ limit = lim_read_enter();
+ val = limit->pl_rlimit[which].rlim_cur;
+ lim_read_leave(limit);
+ return (val);
+}
+
+rlim_t lim_cur_proc(struct proc *, int);
void ruadd(struct rusage *, struct rusage *);
void rucheck(void *);
-#define RUCHECK_INTERVAL 1000 /* check interval in msec */
#endif
#endif /* !_SYS_RESOURCEVAR_H_ */
diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h
index d75be8c8658..bb8c521f38e 100644
--- a/sys/sys/sysctl.h
+++ b/sys/sys/sysctl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sysctl.h,v 1.188 2019/06/01 14:11:18 mpi Exp $ */
+/* $OpenBSD: sysctl.h,v 1.189 2019/06/21 09:39:48 visa Exp $ */
/* $NetBSD: sysctl.h,v 1.16 1996/04/09 20:55:36 cgd Exp $ */
/*
@@ -536,6 +536,14 @@ struct kinfo_vmentry {
* p_tpgid, p_tsess, p_vm_rssize, p_u[us]time_{sec,usec}, p_cpuid
*/
+#if defined(_KERNEL)
+#define PR_LOCK(pr) mtx_enter(&(pr)->ps_mtx)
+#define PR_UNLOCK(pr) mtx_leave(&(pr)->ps_mtx)
+#else
+#define PR_LOCK(pr) /* nothing */
+#define PR_UNLOCK(pr) /* nothing */
+#endif
+
#define PTRTOINT64(_x) ((u_int64_t)(u_long)(_x))
#define FILL_KPROC(kp, copy_str, p, pr, uc, pg, paddr, \
@@ -638,9 +646,11 @@ do { \
(kp)->p_wchan = PTRTOINT64((p)->p_wchan); \
} \
\
+ PR_LOCK(pr); \
if (lim) \
(kp)->p_rlim_rss_cur = \
(lim)->pl_rlimit[RLIMIT_RSS].rlim_cur; \
+ PR_UNLOCK(pr); \
\
if (((pr)->ps_flags & PS_ZOMBIE) == 0) { \
struct timeval tv; \
diff --git a/sys/uvm/uvm_extern.h b/sys/uvm/uvm_extern.h
index 12dc1f7b32f..74982c37f6c 100644
--- a/sys/uvm/uvm_extern.h
+++ b/sys/uvm/uvm_extern.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_extern.h,v 1.146 2019/05/09 20:36:44 beck Exp $ */
+/* $OpenBSD: uvm_extern.h,v 1.147 2019/06/21 09:39:48 visa Exp $ */
/* $NetBSD: uvm_extern.h,v 1.57 2001/03/09 01:02:12 chs Exp $ */
/*
@@ -259,6 +259,8 @@ extern vaddr_t vm_min_kernel_address;
#define vm_resident_count(vm) (pmap_resident_count((vm)->vm_map.pmap))
+struct plimit;
+
void vmapbuf(struct buf *, vsize_t);
void vunmapbuf(struct buf *, vsize_t);
struct uvm_object *uao_create(vsize_t, int);
@@ -271,7 +273,7 @@ int uvm_fault(vm_map_t, vaddr_t, vm_fault_t, vm_prot_t);
vaddr_t uvm_uarea_alloc(void);
void uvm_uarea_free(struct proc *);
void uvm_exit(struct process *);
-void uvm_init_limits(struct proc *);
+void uvm_init_limits(struct plimit *);
boolean_t uvm_kernacc(caddr_t, size_t, int);
int uvm_vslock(struct proc *, caddr_t, size_t,
diff --git a/sys/uvm/uvm_glue.c b/sys/uvm/uvm_glue.c
index e17500c47d1..36105185591 100644
--- a/sys/uvm/uvm_glue.c
+++ b/sys/uvm/uvm_glue.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_glue.c,v 1.74 2019/01/10 20:26:34 kettenis Exp $ */
+/* $OpenBSD: uvm_glue.c,v 1.75 2019/06/21 09:39:49 visa Exp $ */
/* $NetBSD: uvm_glue.c,v 1.44 2001/02/06 19:54:44 eeh Exp $ */
/*
@@ -303,20 +303,19 @@ uvm_exit(struct process *pr)
* - called for process 0 and then inherited by all others.
*/
void
-uvm_init_limits(struct proc *p)
+uvm_init_limits(struct plimit *limit0)
{
-
/*
* Set up the initial limits on process VM. Set the maximum
* resident set size to be all of (reasonably) available memory.
* This causes any single, large process to start random page
* replacement once it fills memory.
*/
- p->p_rlimit[RLIMIT_STACK].rlim_cur = DFLSSIZ;
- p->p_rlimit[RLIMIT_STACK].rlim_max = MAXSSIZ;
- p->p_rlimit[RLIMIT_DATA].rlim_cur = DFLDSIZ;
- p->p_rlimit[RLIMIT_DATA].rlim_max = MAXDSIZ;
- p->p_rlimit[RLIMIT_RSS].rlim_cur = ptoa(uvmexp.free);
+ limit0->pl_rlimit[RLIMIT_STACK].rlim_cur = DFLSSIZ;
+ limit0->pl_rlimit[RLIMIT_STACK].rlim_max = MAXSSIZ;
+ limit0->pl_rlimit[RLIMIT_DATA].rlim_cur = DFLDSIZ;
+ limit0->pl_rlimit[RLIMIT_DATA].rlim_max = MAXDSIZ;
+ limit0->pl_rlimit[RLIMIT_RSS].rlim_cur = ptoa(uvmexp.free);
}
#ifdef DEBUG
diff --git a/sys/uvm/uvm_mmap.c b/sys/uvm/uvm_mmap.c
index 6b35906f142..9f1a6bd9197 100644
--- a/sys/uvm/uvm_mmap.c
+++ b/sys/uvm/uvm_mmap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_mmap.c,v 1.156 2019/05/11 20:02:00 deraadt Exp $ */
+/* $OpenBSD: uvm_mmap.c,v 1.157 2019/06/21 09:39:49 visa Exp $ */
/* $NetBSD: uvm_mmap.c,v 1.49 2001/02/18 21:19:08 chs Exp $ */
/*
@@ -218,7 +218,7 @@ sys_mmap(struct proc *p, void *v, register_t *retval)
vaddr_t addr;
struct vattr va;
off_t pos;
- vsize_t size, pageoff;
+ vsize_t limit, pageoff, size;
vm_prot_t prot, maxprot;
int flags, fd;
vaddr_t vm_min_address = VM_MIN_ADDRESS;
@@ -383,16 +383,16 @@ sys_mmap(struct proc *p, void *v, register_t *retval)
}
if ((flags & __MAP_NOFAULT) != 0 ||
((flags & MAP_PRIVATE) != 0 && (prot & PROT_WRITE) != 0)) {
- if (p->p_rlimit[RLIMIT_DATA].rlim_cur < size ||
- p->p_rlimit[RLIMIT_DATA].rlim_cur - size <
- ptoa(p->p_vmspace->vm_dused)) {
+ limit = lim_cur(RLIMIT_DATA);
+ if (limit < size ||
+ limit - size < ptoa(p->p_vmspace->vm_dused)) {
error = ENOMEM;
goto out;
}
}
KERNEL_LOCK();
- error = uvm_mmapfile(&p->p_vmspace->vm_map, &addr, size, prot, maxprot,
- flags, vp, pos, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur, p);
+ error = uvm_mmapfile(&p->p_vmspace->vm_map, &addr, size, prot,
+ maxprot, flags, vp, pos, lim_cur(RLIMIT_MEMLOCK), p);
KERNEL_UNLOCK();
} else { /* MAP_ANON case */
if (fd != -1)
@@ -404,9 +404,9 @@ is_anon: /* label for SunOS style /dev/zero */
if ((flags & __MAP_NOFAULT) != 0)
return EINVAL;
- if (p->p_rlimit[RLIMIT_DATA].rlim_cur < size ||
- p->p_rlimit[RLIMIT_DATA].rlim_cur - size <
- ptoa(p->p_vmspace->vm_dused)) {
+ limit = lim_cur(RLIMIT_DATA);
+ if (limit < size ||
+ limit - size < ptoa(p->p_vmspace->vm_dused)) {
return ENOMEM;
}
@@ -419,7 +419,7 @@ is_anon: /* label for SunOS style /dev/zero */
maxprot = PROT_MASK;
error = uvm_mmapanon(&p->p_vmspace->vm_map, &addr, size, prot,
- maxprot, flags, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur, p);
+ maxprot, flags, lim_cur(RLIMIT_MEMLOCK), p);
}
if (error == 0)
@@ -729,7 +729,7 @@ sys_mlock(struct proc *p, void *v, register_t *retval)
#ifdef pmap_wired_count
if (size + ptoa(pmap_wired_count(vm_map_pmap(&p->p_vmspace->vm_map))) >
- p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur)
+ lim_cur(RLIMIT_MEMLOCK))
return (EAGAIN);
#else
if ((error = suser(p)) != 0)
@@ -798,7 +798,7 @@ sys_mlockall(struct proc *p, void *v, register_t *retval)
#endif
error = uvm_map_pageable_all(&p->p_vmspace->vm_map, flags,
- p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
+ lim_cur(RLIMIT_MEMLOCK));
if (error != 0 && error != ENOMEM)
return (EAGAIN);
return (error);
diff --git a/sys/uvm/uvm_unix.c b/sys/uvm/uvm_unix.c
index 4618ce03559..c9dfd786fab 100644
--- a/sys/uvm/uvm_unix.c
+++ b/sys/uvm/uvm_unix.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_unix.c,v 1.65 2019/03/01 01:46:18 cheloha Exp $ */
+/* $OpenBSD: uvm_unix.c,v 1.66 2019/06/21 09:39:49 visa Exp $ */
/* $NetBSD: uvm_unix.c,v 1.18 2000/09/13 15:00:25 thorpej Exp $ */
/*
@@ -72,7 +72,7 @@ sys_obreak(struct proc *p, void *v, register_t *retval)
base = (vaddr_t)vm->vm_daddr;
new = round_page((vaddr_t)SCARG(uap, nsize));
- if (new < base || (new - base) > p->p_rlimit[RLIMIT_DATA].rlim_cur)
+ if (new < base || (new - base) > lim_cur(RLIMIT_DATA))
return (ENOMEM);
old = round_page(base + ptoa(vm->vm_dsize));
@@ -128,7 +128,7 @@ uvm_grow(struct proc *p, vaddr_t sp)
#else
si = atop((vaddr_t)vm->vm_minsaddr - sp) - vm->vm_ssize;
#endif
- if (vm->vm_ssize + si <= atop(p->p_rlimit[RLIMIT_STACK].rlim_cur))
+ if (vm->vm_ssize + si <= atop(lim_cur(RLIMIT_STACK)))
vm->vm_ssize += si;
}