diff options
author | John Baldwin <jhb@FreeBSD.org> | 2004-02-04 21:52:57 +0000 |
---|---|---|
committer | John Baldwin <jhb@FreeBSD.org> | 2004-02-04 21:52:57 +0000 |
commit | 91d5354a2ce810d848eca6ecf9da1027aeb2be6d (patch) | |
tree | d9c0a05d62914174d6f00ab22300e935c3e6d983 /sys/kern | |
parent | 890cefab5b3dd6f2a1fbfffae44730a0434b2e84 (diff) | |
download | src-91d5354a2ce810d848eca6ecf9da1027aeb2be6d.tar.gz src-91d5354a2ce810d848eca6ecf9da1027aeb2be6d.zip |
Locking for the per-process resource limits structure.
- struct plimit includes a mutex to protect a reference count. The plimit
structure is treated similarly to struct ucred in that is is always copy
on write, so having a reference to a structure is sufficient to read from
it without needing a further lock.
- The proc lock protects the p_limit pointer and must be held while reading
limits from a process to keep the limit structure from changing out from
under you while reading from it.
- Various global limits that are ints are not protected by a lock since
int writes are atomic on all the archs we support and thus a lock
wouldn't buy us anything.
- All accesses to individual resource limits from a process are abstracted
behind a simple lim_rlimit(), lim_max(), and lim_cur() API that return
either an rlimit, or the current or max individual limit of the specified
resource from a process.
- dosetrlimit() was renamed to kern_setrlimit() to match existing style of
other similar syscall helper functions.
- The alpha OSF/1 compat layer no longer calls getrlimit() and setrlimit()
(it didn't used the stackgap when it should have) but uses lim_rlimit()
and kern_setrlimit() instead.
- The svr4 compat no longer uses the stackgap for resource limits calls,
but uses lim_rlimit() and kern_setrlimit() instead.
- The ibcs2 compat no longer uses the stackgap for resource limits. It
also no longer uses the stackgap for accessing sysctl's for the
ibcs2_sysconf() syscall but uses kernel_sysctl() instead. As a result,
ibcs2_sysconf() no longer needs Giant.
- The p_rlimit macro no longer exists.
Submitted by: mtm (mostly, I only did a few cleanups and catchups)
Tested on: i386
Compiled on: alpha, amd64
Notes
Notes:
svn path=/head/; revision=125454
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/imgact_aout.c | 8 | ||||
-rw-r--r-- | sys/kern/imgact_elf.c | 11 | ||||
-rw-r--r-- | sys/kern/imgact_gzip.c | 6 | ||||
-rw-r--r-- | sys/kern/init_main.c | 24 | ||||
-rw-r--r-- | sys/kern/kern_acct.c | 14 | ||||
-rw-r--r-- | sys/kern/kern_descrip.c | 23 | ||||
-rw-r--r-- | sys/kern/kern_exit.c | 11 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 9 | ||||
-rw-r--r-- | sys/kern/kern_resource.c | 223 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 8 | ||||
-rw-r--r-- | sys/kern/subr_trap.c | 8 | ||||
-rw-r--r-- | sys/kern/sys_generic.c | 5 | ||||
-rw-r--r-- | sys/kern/uipc_sockbuf.c | 10 | ||||
-rw-r--r-- | sys/kern/uipc_socket2.c | 10 |
14 files changed, 247 insertions, 123 deletions
diff --git a/sys/kern/imgact_aout.c b/sys/kern/imgact_aout.c index 4cb7b6349a2b..6bad705b87a5 100644 --- a/sys/kern/imgact_aout.c +++ b/sys/kern/imgact_aout.c @@ -177,14 +177,16 @@ exec_aout_imgact(imgp) /* * text/data/bss must not exceed limits */ - mtx_assert(&Giant, MA_OWNED); + PROC_LOCK(imgp->proc); if (/* text can't exceed maximum text size */ a_out->a_text > maxtsiz || /* data + bss can't exceed rlimit */ - a_out->a_data + bss_size > - imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur) + a_out->a_data + bss_size > lim_cur(imgp->proc, RLIMIT_DATA)) { + PROC_UNLOCK(imgp->proc); return (ENOMEM); + } + PROC_UNLOCK(imgp->proc); /* copy in arguments and/or environment from old process */ error = exec_extract_strings(imgp); diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index ff1107807e25..fac25e8c8be0 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -794,11 +794,11 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) * limits after loading the segments since we do * not actually fault in all the segments pages. */ - if (data_size > - imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur || + PROC_LOCK(imgp->proc); + if (data_size > lim_cur(imgp->proc, RLIMIT_DATA) || text_size > maxtsiz || - total_size > - imgp->proc->p_rlimit[RLIMIT_VMEM].rlim_cur) { + total_size > lim_cur(imgp->proc, RLIMIT_VMEM)) { + PROC_UNLOCK(imgp->proc); error = ENOMEM; goto fail; } @@ -815,7 +815,8 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) * its maximum allowed size. */ addr = round_page((vm_offset_t)imgp->proc->p_vmspace->vm_daddr + - imgp->proc->p_rlimit[RLIMIT_DATA].rlim_max); + lim_max(imgp->proc, RLIMIT_DATA)); + PROC_UNLOCK(imgp->proc); imgp->entry_addr = entry; diff --git a/sys/kern/imgact_gzip.c b/sys/kern/imgact_gzip.c index 76602f9b4702..b4d985ac8941 100644 --- a/sys/kern/imgact_gzip.c +++ b/sys/kern/imgact_gzip.c @@ -209,16 +209,18 @@ do_aout_hdr(struct imgact_gzip * gz) /* * text/data/bss must not exceed limits */ - mtx_assert(&Giant, MA_OWNED); + PROC_LOCK(gz->ip->proc); if ( /* text can't exceed maximum text size */ gz->a_out.a_text > maxtsiz || /* data + bss can't exceed rlimit */ gz->a_out.a_data + gz->bss_size > - gz->ip->proc->p_rlimit[RLIMIT_DATA].rlim_cur) { + lim_cur(gz->ip->proc, RLIMIT_DATA)) { + PROC_UNLOCK(gz->ip->proc); gz->where = __LINE__; return (ENOMEM); } + PROC_UNLOCK(gz->ip->proc); /* Find out how far we should go */ gz->file_end = gz->file_offset + gz->a_out.a_text + gz->a_out.a_data; diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 71288352e1ed..4e91f649c2fc 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -93,7 +93,6 @@ struct thread thread0; struct kse kse0; struct ksegrp ksegrp0; static struct filedesc0 filedesc0; -static struct plimit limit0; struct vmspace vmspace0; struct proc *initproc; @@ -419,19 +418,18 @@ proc0_init(void *dummy __unused) fdp->fd_fd.fd_map = fdp->fd_dmap; /* Create the limits structures. */ - p->p_limit = &limit0; - for (i = 0; i < sizeof(p->p_rlimit)/sizeof(p->p_rlimit[0]); i++) - limit0.pl_rlimit[i].rlim_cur = - limit0.pl_rlimit[i].rlim_max = RLIM_INFINITY; - limit0.pl_rlimit[RLIMIT_NOFILE].rlim_cur = - limit0.pl_rlimit[RLIMIT_NOFILE].rlim_max = maxfiles; - limit0.pl_rlimit[RLIMIT_NPROC].rlim_cur = - limit0.pl_rlimit[RLIMIT_NPROC].rlim_max = maxproc; + p->p_limit = lim_alloc(); + for (i = 0; i < RLIM_NLIMITS; i++) + p->p_limit->pl_rlimit[i].rlim_cur = + p->p_limit->pl_rlimit[i].rlim_max = RLIM_INFINITY; + p->p_limit->pl_rlimit[RLIMIT_NOFILE].rlim_cur = + p->p_limit->pl_rlimit[RLIMIT_NOFILE].rlim_max = maxfiles; + p->p_limit->pl_rlimit[RLIMIT_NPROC].rlim_cur = + p->p_limit->pl_rlimit[RLIMIT_NPROC].rlim_max = maxproc; i = ptoa(cnt.v_free_count); - limit0.pl_rlimit[RLIMIT_RSS].rlim_max = i; - limit0.pl_rlimit[RLIMIT_MEMLOCK].rlim_max = i; - limit0.pl_rlimit[RLIMIT_MEMLOCK].rlim_cur = i / 3; - limit0.p_refcnt = 1; + p->p_limit->pl_rlimit[RLIMIT_RSS].rlim_max = i; + p->p_limit->pl_rlimit[RLIMIT_MEMLOCK].rlim_max = i; + p->p_limit->pl_rlimit[RLIMIT_MEMLOCK].rlim_cur = i / 3; p->p_cpulimit = RLIM_INFINITY; /* Allocate a prototype map so we have something to fork. */ diff --git a/sys/kern/kern_acct.c b/sys/kern/kern_acct.c index 827a034af96d..613a19844d00 100644 --- a/sys/kern/kern_acct.c +++ b/sys/kern/kern_acct.c @@ -228,6 +228,7 @@ acct_process(td) int t, ret; struct vnode *vp; struct ucred *uc; + struct plimit *newlim, *oldlim; mtx_lock(&acct_mtx); @@ -300,11 +301,14 @@ acct_process(td) /* * Eliminate any file size rlimit. */ - if (p->p_limit->p_refcnt > 1) { - p->p_limit->p_refcnt--; - p->p_limit = limcopy(p->p_limit); - } - p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; + newlim = lim_alloc(); + PROC_LOCK(p); + oldlim = p->p_limit; + lim_copy(newlim, oldlim); + newlim->pl_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; + p->p_limit = newlim; + PROC_UNLOCK(p); + lim_free(oldlim); VOP_LEASE(vp, td, uc, LEASE_WRITE); ret = vn_rdwr(UIO_WRITE, vp, (caddr_t)&acct, sizeof (acct), diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index b6eaee271a6c..abaac90655e6 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -224,10 +224,10 @@ getdtablesize(td, uap) { struct proc *p = td->td_proc; - mtx_lock(&Giant); + PROC_LOCK(p); td->td_retval[0] = - min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfilesperproc); - mtx_unlock(&Giant); + min((int)lim_cur(p, RLIMIT_NOFILE), maxfilesperproc); + PROC_UNLOCK(p); return (0); } @@ -353,11 +353,14 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) case F_DUPFD: FILEDESC_UNLOCK(fdp); newmin = arg; - if (newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur || + PROC_LOCK(p); + if (newmin >= lim_cur(p, RLIMIT_NOFILE) || newmin >= maxfilesperproc) { + PROC_UNLOCK(p); error = EINVAL; break; } + PROC_UNLOCK(p); error = do_dup(td, DUP_VARIABLE, fd, newmin, td->td_retval); break; @@ -572,7 +575,9 @@ do_dup(td, type, old, new, retval) */ if (old < 0 || new < 0) return (EBADF); - maxfd = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfilesperproc); + PROC_LOCK(p); + maxfd = min((int)lim_cur(p, RLIMIT_NOFILE), maxfilesperproc); + PROC_UNLOCK(p); if (new >= maxfd) return (EMFILE); @@ -1213,7 +1218,9 @@ fdalloc(struct thread *td, int minfd, int *result) FILEDESC_LOCK_ASSERT(fdp, MA_OWNED); - maxfd = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfilesperproc); + PROC_LOCK(p); + maxfd = min((int)lim_cur(p, RLIMIT_NOFILE), maxfilesperproc); + PROC_UNLOCK(p); /* * Search the bitmap for a free descriptor. If none is found, try @@ -1261,7 +1268,9 @@ fdavail(td, n) FILEDESC_LOCK_ASSERT(fdp, MA_OWNED); - lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfilesperproc); + PROC_LOCK(p); + lim = min((int)lim_cur(p, RLIMIT_NOFILE), maxfilesperproc); + PROC_UNLOCK(p); if ((i = lim - fdp->fd_nfiles) > 0 && (n -= i) <= 0) return (1); last = min(fdp->fd_nfiles, lim); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 28b39c62a7d6..f332e6bf6744 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -119,6 +119,7 @@ exit1(struct thread *td, int rv) struct vnode *tracevp; struct ucred *tracecred; #endif + struct plimit *plim; GIANT_REQUIRED; @@ -373,11 +374,11 @@ exit1(struct thread *td, int rv) /* * Release our limits structure. */ - mtx_assert(&Giant, MA_OWNED); - if (--p->p_limit->p_refcnt == 0) { - FREE(p->p_limit, M_SUBPROC); - p->p_limit = NULL; - } + PROC_LOCK(p); + plim = p->p_limit; + p->p_limit = NULL; + PROC_UNLOCK(p); + lim_free(plim); /* * Release this thread's reference to the ucred. The actual proc diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 445c6063156c..5937c473875b 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -308,7 +308,7 @@ fork1(td, flags, pages, procp) */ PROC_LOCK(p1); ok = chgproccnt(td->td_ucred->cr_ruidinfo, 1, - (uid != 0) ? p1->p_rlimit[RLIMIT_NPROC].rlim_cur : 0); + (uid != 0) ? lim_cur(p1, RLIMIT_NPROC) : 0); PROC_UNLOCK(p1); if (!ok) { error = EAGAIN; @@ -528,14 +528,13 @@ again: VREF(p2->p_textvp); p2->p_fd = fd; p2->p_fdtol = fdtol; - PROC_UNLOCK(p1); - PROC_UNLOCK(p2); /* * p_limit is copy-on-write, bump refcnt, */ - p2->p_limit = p1->p_limit; - p2->p_limit->p_refcnt++; + p2->p_limit = lim_hold(p1->p_limit); + PROC_UNLOCK(p1); + PROC_UNLOCK(p2); /* * Setup linkage for kernel based threading diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index 80bf382b2ea8..3b011e356e22 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$"); static int donice(struct thread *td, struct proc *chgp, int n); +static MALLOC_DEFINE(M_PLIMIT, "plimit", "plimit structures"); static MALLOC_DEFINE(M_UIDINFO, "uidinfo", "uidinfo structures"); #define UIHASH(uid) (&uihashtbl[(uid) & uihash]) static struct mtx uihashtbl_mtx; @@ -459,9 +460,7 @@ osetrlimit(td, uap) return (error); lim.rlim_cur = olim.rlim_cur; lim.rlim_max = olim.rlim_max; - mtx_lock(&Giant); - error = dosetrlimit(td, uap->which, &lim); - mtx_unlock(&Giant); + error = kern_setrlimit(td, uap->which, &lim); return (error); } @@ -482,19 +481,17 @@ ogetrlimit(td, uap) { struct proc *p = td->td_proc; struct orlimit olim; + struct rlimit rl; int error; if (uap->which >= RLIM_NLIMITS) return (EINVAL); - mtx_lock(&Giant); - olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur; - if (olim.rlim_cur == -1) - olim.rlim_cur = 0x7fffffff; - olim.rlim_max = p->p_rlimit[uap->which].rlim_max; - if (olim.rlim_max == -1) - olim.rlim_max = 0x7fffffff; + PROC_LOCK(p); + lim_rlimit(p, uap->which, &rl); + PROC_UNLOCK(p); + olim.rlim_cur = rl.rlim_cur == -1 ? 0x7fffffff : rl.rlim_cur; + olim.rlim_max = rl.rlim_max == -1 ? 0x7fffffff : rl.rlim_max; error = copyout(&olim, uap->rlp, sizeof(olim)); - mtx_unlock(&Giant); return (error); } #endif /* COMPAT_43 || COMPAT_SUNOS */ @@ -519,27 +516,24 @@ setrlimit(td, uap) if ((error = copyin(uap->rlp, &alim, sizeof (struct rlimit)))) return (error); - mtx_lock(&Giant); - error = dosetrlimit(td, uap->which, &alim); - mtx_unlock(&Giant); + error = kern_setrlimit(td, uap->which, &alim); return (error); } int -dosetrlimit(td, which, limp) +kern_setrlimit(td, which, limp) struct thread *td; u_int which; struct rlimit *limp; { struct proc *p = td->td_proc; + struct plimit *newlim, *oldlim; register struct rlimit *alimp; + rlim_t oldssiz; int error; - GIANT_REQUIRED; - if (which >= RLIM_NLIMITS) return (EINVAL); - alimp = &p->p_rlimit[which]; /* * Preserve historical bugs by treating negative limits as unsigned. @@ -549,17 +543,22 @@ dosetrlimit(td, which, limp) if (limp->rlim_max < 0) limp->rlim_max = RLIM_INFINITY; + oldssiz = 0; + newlim = lim_alloc(); + PROC_LOCK(p); + oldlim = p->p_limit; + alimp = &oldlim->pl_rlimit[which]; if (limp->rlim_cur > alimp->rlim_max || limp->rlim_max > alimp->rlim_max) - if ((error = suser_cred(td->td_ucred, PRISON_ROOT))) + if ((error = suser_cred(td->td_ucred, PRISON_ROOT))) { + PROC_UNLOCK(p); + lim_free(newlim); return (error); + } if (limp->rlim_cur > limp->rlim_max) limp->rlim_cur = limp->rlim_max; - if (p->p_limit->p_refcnt > 1) { - p->p_limit->p_refcnt--; - p->p_limit = limcopy(p->p_limit); - alimp = &p->p_rlimit[which]; - } + lim_copy(newlim, oldlim); + alimp = &newlim->pl_rlimit[which]; switch (which) { @@ -580,53 +579,62 @@ dosetrlimit(td, which, limp) limp->rlim_cur = maxssiz; if (limp->rlim_max > maxssiz) limp->rlim_max = maxssiz; + oldssiz = alimp->rlim_cur; + break; + + case RLIMIT_NOFILE: + if (limp->rlim_cur > maxfilesperproc) + limp->rlim_cur = maxfilesperproc; + if (limp->rlim_max > maxfilesperproc) + limp->rlim_max = maxfilesperproc; + break; + + case RLIMIT_NPROC: + if (limp->rlim_cur > maxprocperuid) + limp->rlim_cur = maxprocperuid; + if (limp->rlim_max > maxprocperuid) + limp->rlim_max = maxprocperuid; + if (limp->rlim_cur < 1) + limp->rlim_cur = 1; + if (limp->rlim_max < 1) + limp->rlim_max = 1; + break; + } + *alimp = *limp; + p->p_limit = newlim; + PROC_UNLOCK(p); + lim_free(oldlim); + + if (which == RLIMIT_STACK) { /* * Stack is allocated to the max at exec time with only * "rlim_cur" bytes accessible. If stack limit is going * up make more accessible, if going down make inaccessible. */ - if (limp->rlim_cur != alimp->rlim_cur) { + if (limp->rlim_cur != oldssiz) { vm_offset_t addr; vm_size_t size; vm_prot_t prot; - if (limp->rlim_cur > alimp->rlim_cur) { + mtx_lock(&Giant); + if (limp->rlim_cur > oldssiz) { prot = p->p_sysent->sv_stackprot; - size = limp->rlim_cur - alimp->rlim_cur; + size = limp->rlim_cur - oldssiz; addr = p->p_sysent->sv_usrstack - limp->rlim_cur; } else { prot = VM_PROT_NONE; - size = alimp->rlim_cur - limp->rlim_cur; + size = oldssiz - limp->rlim_cur; addr = p->p_sysent->sv_usrstack - - alimp->rlim_cur; + oldssiz; } addr = trunc_page(addr); size = round_page(size); (void) vm_map_protect(&p->p_vmspace->vm_map, addr, addr+size, prot, FALSE); + mtx_unlock(&Giant); } - break; - - case RLIMIT_NOFILE: - if (limp->rlim_cur > maxfilesperproc) - limp->rlim_cur = maxfilesperproc; - if (limp->rlim_max > maxfilesperproc) - limp->rlim_max = maxfilesperproc; - break; - - case RLIMIT_NPROC: - if (limp->rlim_cur > maxprocperuid) - limp->rlim_cur = maxprocperuid; - if (limp->rlim_max > maxprocperuid) - limp->rlim_max = maxprocperuid; - if (limp->rlim_cur < 1) - limp->rlim_cur = 1; - if (limp->rlim_max < 1) - limp->rlim_max = 1; - break; } - *alimp = *limp; return (0); } @@ -647,13 +655,14 @@ getrlimit(td, uap) { int error; struct proc *p = td->td_proc; + struct rlimit rlim; if (uap->which >= RLIM_NLIMITS) return (EINVAL); - mtx_lock(&Giant); - error = copyout(&p->p_rlimit[uap->which], uap->rlp, - sizeof (struct rlimit)); - mtx_unlock(&Giant); + PROC_LOCK(p); + lim_rlimit(p, uap->which, &rlim); + PROC_UNLOCK(p); + error = copyout(&rlim, uap->rlp, sizeof (struct rlimit)); return(error); } @@ -814,21 +823,107 @@ ruadd(ru, ru2) } /* - * Make a copy of the plimit structure. - * We share these structures copy-on-write after fork, - * and copy when a limit is changed. + * Allocate a new resource limits structure, initialize it's + * reference count and mutex. + */ +struct plimit * +lim_alloc(void) +{ + struct plimit *limp; + + limp = (struct plimit *)malloc(sizeof(struct plimit), M_PLIMIT, + M_WAITOK | M_ZERO); + limp->pl_refcnt = 1; + mtx_init(&limp->pl_mtx, "plimit lock", NULL, MTX_DEF); + return (limp); +} + +/* + * NOTE: The caller must own the proc lock this limit is associated with. */ struct plimit * -limcopy(lim) - struct plimit *lim; +lim_hold(limp) + struct plimit *limp; { - register struct plimit *copy; - MALLOC(copy, struct plimit *, sizeof(struct plimit), - M_SUBPROC, M_WAITOK); - bcopy(lim->pl_rlimit, copy->pl_rlimit, sizeof(struct plimit)); - copy->p_refcnt = 1; - return (copy); + LIM_LOCK(limp); + limp->pl_refcnt++; + LIM_UNLOCK(limp); + return (limp); +} + +/* + * NOTE: The caller must own the proc lock this plimit belongs to. + */ +void +lim_free(limp) + struct plimit *limp; +{ + + LIM_LOCK(limp); + KASSERT(limp->pl_refcnt > 0, ("bad plimit refcnt: %d", limp->pl_refcnt)); + if (--limp->pl_refcnt == 0) { + mtx_destroy(&limp->pl_mtx); + free((void *)limp, M_PLIMIT); + return; + } + LIM_UNLOCK(limp); +} + +/* + * Make a copy of the plimit structure. + * We share these structures copy-on-write after fork. + */ +void +lim_copy(dst, src) + struct plimit *dst, *src; +{ + + KASSERT(dst->pl_refcnt == 1, ("lim_copy of shared limit")); + bcopy(src->pl_rlimit, dst->pl_rlimit, sizeof(src->pl_rlimit)); +} + +/* + * Obtain the hard limit for a particular system resource. + * which - index into the rlimit array + * Note: callers must hold proc lock. + */ +rlim_t +lim_max(struct proc *p, int which) +{ + struct rlimit rl; + + lim_rlimit(p, which, &rl); + return (rl.rlim_max); +} + +/* + * Obtain the current (soft) limit for a particular system resource. + * which - index into the rlimit array + * Note: callers must hold proc lock. + */ +rlim_t +lim_cur(struct proc *p, int which) +{ + struct rlimit rl; + + lim_rlimit(p, which, &rl); + return (rl.rlim_max); +} + +/* + * Obtain the entire rlimit structure for a particular system limit. + * which - index into the rlimit array + * rlp - address into which the rlimit structure will be placed + */ +void +lim_rlimit(struct proc *p, int which, struct rlimit *rlp) +{ + + PROC_LOCK_ASSERT(p, MA_OWNED); + KASSERT(which >= 0 && which < RLIM_NLIMITS, + ("request for invalid resource limit")); + *rlp = p->p_limit->pl_rlimit[which]; } /* diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index bf224f2a4330..aa1e19da0546 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -2554,12 +2554,10 @@ coredump(struct thread *td) * a corefile is truncated instead of not being created, * if it is larger than the limit. */ - limit = p->p_rlimit[RLIMIT_CORE].rlim_cur; - if (limit == 0) { - PROC_UNLOCK(p); - return EFBIG; - } + limit = (off_t)lim_cur(p, RLIMIT_CORE); PROC_UNLOCK(p); + if (limit == 0) + return (EFBIG); restart: name = expand_name(p->p_comm, td->td_ucred->cr_uid, p->p_pid); diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index 2390087d97ba..a556d0eefd2a 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -143,7 +143,7 @@ ast(struct trapframe *framep) struct proc *p; struct kse *ke; struct ksegrp *kg; - struct rlimit *rlim; + struct rlimit rlim; u_int prticks, sticks; int sflag; int flags; @@ -223,13 +223,13 @@ ast(struct trapframe *framep) } if (sflag & PS_XCPU) { PROC_LOCK(p); - rlim = &p->p_rlimit[RLIMIT_CPU]; + lim_rlimit(p, RLIMIT_CPU, &rlim); mtx_lock_spin(&sched_lock); - if (p->p_runtime.sec >= rlim->rlim_max) { + if (p->p_runtime.sec >= rlim.rlim_max) { mtx_unlock_spin(&sched_lock); killproc(p, "exceeded maximum CPU limit"); } else { - if (p->p_cpulimit < rlim->rlim_max) + if (p->p_cpulimit < rlim.rlim_max) p->p_cpulimit += 5; mtx_unlock_spin(&sched_lock); psignal(p, SIGXCPU); diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index e725f8fc1e18..7ba4f2629b27 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -961,11 +961,14 @@ poll(td, uap) * least enough for the current limits. We want to be reasonably * safe, but not overly restrictive. */ - if ((nfds > td->td_proc->p_rlimit[RLIMIT_NOFILE].rlim_cur) && + PROC_LOCK(td->td_proc); + if ((nfds > lim_cur(td->td_proc, RLIMIT_NOFILE)) && (nfds > FD_SETSIZE)) { + PROC_UNLOCK(td->td_proc); error = EINVAL; goto done2; } + PROC_UNLOCK(td->td_proc); ni = nfds * sizeof(struct pollfd); if (ni > sizeof(smallbits)) bits = malloc(ni, M_TEMP, M_WAITOK); diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c index 64199fc78b1e..9f5da29644e0 100644 --- a/sys/kern/uipc_sockbuf.c +++ b/sys/kern/uipc_sockbuf.c @@ -411,6 +411,7 @@ sbreserve(sb, cc, so, td) struct socket *so; struct thread *td; { + rlim_t sbsize_limit; /* * td will only be NULL when we're in an interrupt @@ -418,10 +419,15 @@ sbreserve(sb, cc, so, td) */ if (cc > sb_max_adj) return (0); + if (td != NULL) { + PROC_LOCK(td->td_proc); + sbsize_limit = lim_cur(td->td_proc, RLIMIT_SBSIZE); + PROC_UNLOCK(td->td_proc); + } else + sbsize_limit = RLIM_INFINITY; if (!chgsbsize(so->so_cred->cr_uidinfo, &sb->sb_hiwat, cc, - td ? td->td_proc->p_rlimit[RLIMIT_SBSIZE].rlim_cur : RLIM_INFINITY)) { + sbsize_limit)) return (0); - } sb->sb_mbmax = min(cc * sb_efficiency, sb_max); if (sb->sb_lowat > sb->sb_hiwat) sb->sb_lowat = sb->sb_hiwat; diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c index 64199fc78b1e..9f5da29644e0 100644 --- a/sys/kern/uipc_socket2.c +++ b/sys/kern/uipc_socket2.c @@ -411,6 +411,7 @@ sbreserve(sb, cc, so, td) struct socket *so; struct thread *td; { + rlim_t sbsize_limit; /* * td will only be NULL when we're in an interrupt @@ -418,10 +419,15 @@ sbreserve(sb, cc, so, td) */ if (cc > sb_max_adj) return (0); + if (td != NULL) { + PROC_LOCK(td->td_proc); + sbsize_limit = lim_cur(td->td_proc, RLIMIT_SBSIZE); + PROC_UNLOCK(td->td_proc); + } else + sbsize_limit = RLIM_INFINITY; if (!chgsbsize(so->so_cred->cr_uidinfo, &sb->sb_hiwat, cc, - td ? td->td_proc->p_rlimit[RLIMIT_SBSIZE].rlim_cur : RLIM_INFINITY)) { + sbsize_limit)) return (0); - } sb->sb_mbmax = min(cc * sb_efficiency, sb_max); if (sb->sb_lowat > sb->sb_hiwat) sb->sb_lowat = sb->sb_hiwat; |