PERFORCE change 146140 for review

Ed Schouten ed at FreeBSD.org
Mon Jul 28 18:11:46 UTC 2008


http://perforce.freebsd.org/chv.cgi?CH=146140

Change 146140 by ed at 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);


More information about the p4-projects mailing list