Date: Mon, 28 Jul 2008 18:11:45 GMT From: Ed Schouten <ed@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 146140 for review Message-ID: <200807281811.m6SIBjFm057249@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=146140 Change 146140 by ed@ed_dull on 2008/07/28 18:10:59 Introduce a new resource limit: RLIMIT_NPTS. We can now place limits on pseudo-terminals. Unfortunately, OpenSSH doesn't want to play along, but applications like screen and xterm should behave nicely. Affected files ... .. //depot/projects/mpsafetty/bin/sh/miscbltin.c#2 edit .. //depot/projects/mpsafetty/etc/login.conf#2 edit .. //depot/projects/mpsafetty/lib/libc/sys/getrlimit.2#2 edit .. //depot/projects/mpsafetty/lib/libutil/login_class.c#3 edit .. //depot/projects/mpsafetty/sys/dev/pts/pts.c#8 edit .. //depot/projects/mpsafetty/sys/dev/pts/pts.h#3 edit .. //depot/projects/mpsafetty/sys/dev/ptycompat/ptycompat.c#5 edit .. //depot/projects/mpsafetty/sys/kern/kern_resource.c#2 edit .. //depot/projects/mpsafetty/sys/sys/resource.h#2 edit .. //depot/projects/mpsafetty/sys/sys/resourcevar.h#2 edit Differences ... ==== //depot/projects/mpsafetty/bin/sh/miscbltin.c#2 (text+ko) ==== @@ -342,6 +342,9 @@ #ifdef RLIMIT_SBSIZE { "sbsize", "bytes", RLIMIT_SBSIZE, 1, 'b' }, #endif +#ifdef RLIMIT_NPTS + { "pseudo-terminals", (char *)0, RLIMIT_NPTS, 1, 'p' }, +#endif { (char *) 0, (char *)0, 0, 0, '\0' } }; @@ -358,7 +361,7 @@ struct rlimit limit; what = 'f'; - while ((optc = nextopt("HSatfdsmcnuvlb")) != '\0') + while ((optc = nextopt("HSatfdsmcnuvlbp")) != '\0') switch (optc) { case 'H': how = HARD; ==== //depot/projects/mpsafetty/etc/login.conf#2 (text+ko) ==== @@ -40,6 +40,7 @@ :maxproc=unlimited:\ :sbsize=unlimited:\ :vmemoryuse=unlimited:\ + :pseudoterminals=unlimited:\ :priority=0:\ :ignoretime@:\ :umask=022: ==== //depot/projects/mpsafetty/lib/libc/sys/getrlimit.2#2 (text+ko) ==== @@ -97,6 +97,8 @@ The maximum size (in bytes) of the stack segment for a process; this defines how far a program's stack segment may be extended. Stack extension is performed automatically by the system. +.It Dv RLIMIT_NPTS +The maximum number of pseudo-terminals created by this user id. .El .Pp A resource limit is specified as a soft limit and a hard limit. ==== //depot/projects/mpsafetty/lib/libutil/login_class.c#3 (text+ko) ==== @@ -50,18 +50,19 @@ rlim_t (*who)(login_cap_t *, const char *, rlim_t, rlim_t); int why; } resources[] = { - { "cputime", login_getcaptime, RLIMIT_CPU }, - { "filesize", login_getcapsize, RLIMIT_FSIZE }, - { "datasize", login_getcapsize, RLIMIT_DATA }, - { "stacksize", login_getcapsize, RLIMIT_STACK }, - { "memoryuse", login_getcapsize, RLIMIT_RSS }, - { "memorylocked", login_getcapsize, RLIMIT_MEMLOCK }, - { "maxproc", login_getcapnum, RLIMIT_NPROC }, - { "openfiles", login_getcapnum, RLIMIT_NOFILE }, - { "coredumpsize", login_getcapsize, RLIMIT_CORE }, - { "sbsize", login_getcapsize, RLIMIT_SBSIZE }, - { "vmemoryuse", login_getcapsize, RLIMIT_VMEM }, - { NULL, 0, 0 } + { "cputime", login_getcaptime, RLIMIT_CPU }, + { "filesize", login_getcapsize, RLIMIT_FSIZE }, + { "datasize", login_getcapsize, RLIMIT_DATA }, + { "stacksize", login_getcapsize, RLIMIT_STACK }, + { "memoryuse", login_getcapsize, RLIMIT_RSS }, + { "memorylocked", login_getcapsize, RLIMIT_MEMLOCK }, + { "maxproc", login_getcapnum, RLIMIT_NPROC }, + { "openfiles", login_getcapnum, RLIMIT_NOFILE }, + { "coredumpsize", login_getcapsize, RLIMIT_CORE }, + { "sbsize", login_getcapsize, RLIMIT_SBSIZE }, + { "vmemoryuse", login_getcapsize, RLIMIT_VMEM }, + { "pseudoterminals", login_getcapnum, RLIMIT_NPTS }, + { NULL, 0, 0 } }; ==== //depot/projects/mpsafetty/sys/dev/pts/pts.c#8 (text+ko) ==== @@ -51,6 +51,7 @@ #include <sys/mutex.h> #include <sys/poll.h> #include <sys/proc.h> +#include <sys/resourcevar.h> #include <sys/serial.h> #include <sys/stat.h> #include <sys/syscall.h> @@ -89,19 +90,20 @@ */ struct pts_softc { int pts_unit; /* (c) Device unit number */ + unsigned int pts_flags; /* (t) Device flags */ +#define PTS_PKT 0x1 /* Packet mode */ struct cv pts_inwait; /* (t) Blocking write() on master */ struct selinfo pts_inpoll; /* (t) Select queue for write() */ struct cv pts_outwait; /* (t) Blocking read() on master */ struct selinfo pts_outpoll; /* (t) Select queue for read() */ - unsigned int pts_flags; /* (t) Device flags */ -#define PTS_PKT 0x1 /* Packet mode */ - #ifdef PTS_EXTERNAL pts_external_free_t *pts_external_free; /* (c) Destructor callback */ void *pts_external_softc; /* (c) Destructor softc */ #endif /* PTS_EXTERNAL */ + + struct uidinfo *pts_uidinfo; /* (c) Resource limit */ }; /* @@ -489,6 +491,9 @@ mtx_unlock(&pts_lock); } + chgptscnt(psc->pts_uidinfo, -1, 0); + uifree(psc->pts_uidinfo); + #ifdef PTS_EXTERNAL /* Call shutdown hook */ if (psc->pts_external_free != NULL) @@ -509,15 +514,25 @@ static int pts_alloc(int fflags, struct thread *td, struct file *fp) { - int unit; + int unit, ok; struct tty *tp; struct pts_softc *psc; + struct proc *p = td->td_proc; + struct uidinfo *uid = td->td_ucred->cr_ruidinfo; + /* Resource limiting */ + PROC_LOCK(p); + ok = chgptscnt(uid, 1, lim_cur(p, RLIMIT_NPTS)); + PROC_UNLOCK(p); + if (!ok) + return (EAGAIN); + /* Try to allocate a new pts unit number */ mtx_lock(&pts_lock); unit = alloc_unrl(pts_pool); if (unit < 0) { mtx_unlock(&pts_lock); + chgptscnt(uid, -1, 0); return (EAGAIN); } pts_ndevs++; @@ -529,6 +544,8 @@ cv_init(&psc->pts_outwait, "pts outwait"); psc->pts_unit = unit; + psc->pts_uidinfo = uid; + uihold(uid); tp = tty_alloc(&pts_class, psc, NULL); @@ -541,12 +558,22 @@ } #ifdef PTS_EXTERNAL -void +int pts_alloc_external(int fflags, struct thread *td, struct file *fp, pts_external_free_t freefunc, void *softc, const char *name) { + int ok; struct tty *tp; struct pts_softc *psc; + struct proc *p = td->td_proc; + struct uidinfo *uid = td->td_ucred->cr_ruidinfo; + + /* Resource limiting */ + PROC_LOCK(p); + ok = chgptscnt(uid, 1, lim_cur(p, RLIMIT_NPTS)); + PROC_UNLOCK(p); + if (!ok) + return (EAGAIN); /* Allocate TTY and softc */ psc = malloc(sizeof(struct pts_softc), M_PTS, M_WAITOK|M_ZERO); @@ -556,6 +583,8 @@ psc->pts_unit = -1; psc->pts_external_free = freefunc; psc->pts_external_softc = softc; + psc->pts_uidinfo = uid; + uihold(uid); tp = tty_alloc(&pts_class, psc, NULL); @@ -563,6 +592,8 @@ tty_makedev(tp, td->td_ucred, "%s", name); finit(fp, fflags, DTYPE_PTS, tp, &ptsdev_ops); + + return (0); } #endif /* PTS_EXTERNAL */ ==== //depot/projects/mpsafetty/sys/dev/pts/pts.h#3 (text+ko) ==== @@ -41,7 +41,7 @@ typedef void pts_external_free_t(void *softc); -void pts_alloc_external(int, struct thread *, struct file *, +int pts_alloc_external(int, struct thread *, struct file *, pts_external_free_t, void *, const char *); #endif /* _PTS_H_ */ ==== //depot/projects/mpsafetty/sys/dev/ptycompat/ptycompat.c#5 (text+ko) ==== @@ -62,7 +62,7 @@ static int ptydev_fdopen(struct cdev *dev, int fflags, struct thread *td, struct file *fp) { - int u; + int u, error; char name[] = "ttyXX"; if (!atomic_cmpset_ptr((uintptr_t *)&dev->si_drv1, 0, 1)) @@ -72,8 +72,13 @@ u = minor2unit(minor(dev)); name[3] = u >> 8; name[4] = u; - pts_alloc_external(fflags & (FREAD|FWRITE), td, fp, + + error = pts_alloc_external(fflags & (FREAD|FWRITE), td, fp, ptydev_free, dev, name); + if (error != 0) { + destroy_dev_sched(dev); + return (error); + } /* Raise a warning when a legacy PTY has been allocated */ if (pty_warningcnt > 0) { ==== //depot/projects/mpsafetty/sys/kern/kern_resource.c#2 (text+ko) ==== @@ -1329,3 +1329,28 @@ *hiwat = to; return (1); } + +/* + * Change the count associated with number of pseudo-terminals + * a given user is using. When 'max' is 0, don't enforce a limit + */ +int +chgptscnt(uip, diff, max) + struct uidinfo *uip; + int diff; + rlim_t max; +{ + + /* Don't allow them to exceed max, but allow subtraction. */ + if (diff > 0 && max != 0) { + if (atomic_fetchadd_long(&uip->ui_ptscnt, (long)diff) + diff > max) { + atomic_subtract_long(&uip->ui_ptscnt, (long)diff); + return (0); + } + } else { + atomic_add_long(&uip->ui_ptscnt, (long)diff); + if (uip->ui_ptscnt < 0) + printf("negative ptscnt for uid = %d\n", uip->ui_uid); + } + return (1); +} ==== //depot/projects/mpsafetty/sys/sys/resource.h#2 (text+ko) ==== @@ -93,8 +93,9 @@ #define RLIMIT_SBSIZE 9 /* maximum size of all socket buffers */ #define RLIMIT_VMEM 10 /* virtual process size (inclusive of mmap) */ #define RLIMIT_AS RLIMIT_VMEM /* standard name for RLIMIT_VMEM */ +#define RLIMIT_NPTS 11 /* pseudo-terminals */ -#define RLIM_NLIMITS 11 /* number of resource limits */ +#define RLIM_NLIMITS 12 /* number of resource limits */ #define RLIM_INFINITY ((rlim_t)(((uint64_t)1 << 63) - 1)) /* XXX Missing: RLIM_SAVED_MAX, RLIM_SAVED_CUR */ ==== //depot/projects/mpsafetty/sys/sys/resourcevar.h#2 (text+ko) ==== @@ -91,6 +91,7 @@ LIST_ENTRY(uidinfo) ui_hash; /* (c) hash chain of uidinfos */ long ui_sbsize; /* (b) socket buffer space consumed */ long ui_proccnt; /* (b) number of processes */ + long ui_ptscnt; /* (a) number of pseudo-terminals */ uid_t ui_uid; /* (a) uid */ u_int ui_ref; /* (b) reference count */ }; @@ -106,6 +107,7 @@ int chgproccnt(struct uidinfo *uip, int diff, rlim_t maxval); int chgsbsize(struct uidinfo *uip, u_int *hiwat, u_int to, rlim_t maxval); +int chgptscnt(struct uidinfo *uip, int diff, rlim_t maxval); int fuswintr(void *base); struct plimit *lim_alloc(void);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200807281811.m6SIBjFm057249>