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 { \