Module Name:    src
Committed By:   snj
Date:           Sat Apr 11 06:18:21 UTC 2009

Modified Files:
        src/sys/kern [netbsd-3]: uipc_usrreq.c
        src/sys/sys [netbsd-3]: file.h

Log Message:
Apply patch (requested by mlelstv in ticket #2004):
Avoid deep recursion and file descriptor exhaustion.

1. unp_detach: go not call unp_gc directly for descriptors
   that are unixdomain sockets themselves. Instead mark them
   for cleanup during garbage collection.

2. unp_gc: handle detach of descriptors that were marked earlier.

3. prohibit transfer of descriptors within SCM_RIGHTS messages if
   (num_files_in_transit > maxfiles / unp_rights_ratio)


To generate a diff of this commit:
cvs rdiff -u -r1.80.2.3 -r1.80.2.4 src/sys/kern/uipc_usrreq.c
cvs rdiff -u -r1.53 -r1.53.4.1 src/sys/sys/file.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/uipc_usrreq.c
diff -u src/sys/kern/uipc_usrreq.c:1.80.2.3 src/sys/kern/uipc_usrreq.c:1.80.2.4
--- src/sys/kern/uipc_usrreq.c:1.80.2.3	Sun Aug 26 20:27:07 2007
+++ src/sys/kern/uipc_usrreq.c	Sat Apr 11 06:18:20 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: uipc_usrreq.c,v 1.80.2.3 2007/08/26 20:27:07 bouyer Exp $	*/
+/*	$NetBSD: uipc_usrreq.c,v 1.80.2.4 2009/04/11 06:18:20 snj Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2004 The NetBSD Foundation, Inc.
@@ -103,7 +103,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_usrreq.c,v 1.80.2.3 2007/08/26 20:27:07 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_usrreq.c,v 1.80.2.4 2009/04/11 06:18:20 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -523,6 +523,7 @@
 u_long	unpdg_recvspace = 4*1024;
 
 int	unp_rights;			/* file descriptors in flight */
+int	unp_rights_ratio = 2;		/* limit, fraction of maxfiles */
 
 int
 unp_attach(struct socket *so)
@@ -959,6 +960,7 @@
 	int i, fd, *fdp;
 	int nfds;
 	u_int neededspace;
+	u_int maxmsg;
 
 	/* Sanity check the control message header */
 	if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
@@ -967,6 +969,11 @@
 
 	/* Verify that the file descriptors are valid */
 	nfds = (cm->cmsg_len - CMSG_ALIGN(sizeof(*cm))) / sizeof(int);
+
+	maxmsg = maxfiles / unp_rights_ratio;
+	if (unp_rights + nfds > maxmsg)
+		return (EAGAIN);
+
 	fdp = (int *)CMSG_DATA(cm);
 	for (i = 0; i < nfds; i++) {
 		fd = *fdp++;
@@ -1150,6 +1157,8 @@
 				if (fp->f_count == fp->f_msgcount)
 					continue;
 			}
+			if (fp->f_iflags & FIF_DISCARDED)
+				continue;
 			fp->f_flag |= FMARK;
 
 			if (fp->f_type != DTYPE_SOCKET ||
@@ -1255,6 +1264,14 @@
 	for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) {
 		fp = *fpp;
 		simple_lock(&fp->f_slock);
+		if (fp->f_iflags & FIF_DISCARDED) {
+			fp->f_usecount++;
+			fp->f_msgcount--;
+			simple_unlock(&fp->f_slock);
+			unp_rights--;
+			(void) closef(fp, (struct lwp *)0);
+			simple_lock(&fp->f_slock);
+		}
 		FILE_USE(fp);
 		(void) closef(fp, (struct proc *)0);
 	}
@@ -1339,7 +1356,24 @@
 {
 	if (fp == NULL)
 		return;
+
 	simple_lock(&fp->f_slock);
+	/*
+	 * closing unix domain sockets may cause a deep
+	 * recursion, so leave them open and mark them
+	 * for the garbage collector to discard them safely.
+	 */
+	if (fp->f_type == DTYPE_SOCKET && fp->f_count == 1) {
+		struct socket *so;
+
+		so = (struct socket *)fp->f_data;
+		if (so && so->so_proto->pr_domain == &unixdomain &&
+		    (so->so_proto->pr_flags&PR_RIGHTS) != 0) {
+			fp->f_iflags |= FIF_DISCARDED;
+			simple_unlock(&fp->f_slock);
+			return;
+		}
+	}
 	fp->f_usecount++;	/* i.e. FILE_USE(fp) sans locking */
 	fp->f_msgcount--;
 	simple_unlock(&fp->f_slock);

Index: src/sys/sys/file.h
diff -u src/sys/sys/file.h:1.53 src/sys/sys/file.h:1.53.4.1
--- src/sys/sys/file.h:1.53	Sat Feb 12 23:14:03 2005
+++ src/sys/sys/file.h	Sat Apr 11 06:18:21 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: file.h,v 1.53 2005/02/12 23:14:03 christos Exp $	*/
+/*	$NetBSD: file.h,v 1.53.4.1 2009/04/11 06:18:21 snj Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -94,9 +94,10 @@
 
 #define	FIF_WANTCLOSE		0x01	/* a close is waiting for usecount */
 #define	FIF_LARVAL		0x02	/* not fully constructed; don't use */
+#define	FIF_DISCARDED		0x04	/* file is discarded, pending close */
 
 #define	FILE_IS_USABLE(fp)	(((fp)->f_iflags &			\
-				  (FIF_WANTCLOSE|FIF_LARVAL)) == 0)
+			(FIF_WANTCLOSE|FIF_LARVAL|FIF_DISCARDED)) == 0)
 
 #define	FILE_SET_MATURE(fp)						\
 do {									\

Reply via email to