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