diff mbox

[nfs-utils,3/3] rpc.mountd: set libtirpc nonblocking mode to avoid DOS

Message ID d6437a$6ag165@dgate10u.abg.fsc.net (mailing list archive)
State New, archived
Headers show

Commit Message

Bodo Stroesser Nov. 5, 2014, 8:24 p.m. UTC
From: Bodo Stroesser <bstroesser@ts.fujitsu.com>
Date: Thu, 09 Oct 2014 13:06:19 +0200
Subject: [nfs-utils] [PATCH 3/3] rpc.mountd: set libtirpc nonblocking mode to avoid DOS

This patch is experimental. In works fine in that it removes the vulnerability
against a DOS attack. rpc.mountd can be blocked by a bad client, that sends
many RPC requests but never reads the responses. This might happen intentionally
or caused by a wrong network config (MTU).
The patch switches on the nonblocking mode of libtirpc. In that mode writes can
block for a max. of 2 seconds. Attackers are forced to send requests slower, as
libtirpc will close a connection if it finds two requests to read at the same
time.
I do not know, whether setting MAXREC could cause trouble e.g. with big replies.
 

Signed-off-by: Bodo Stroesser <bstroesser@ts.fujitsu.com>
---
diff mbox

Patch

--- nfs-utils-1.3.1/support/nfs/svc_create.c	2014-10-09 12:09:15.000000000 +0200
+++ nfs-utils-1.3.1/support/nfs/svc_create.c	2014-10-09 12:13:32.000000000 +0200
@@ -49,6 +49,8 @@ 
 
 #ifdef HAVE_LIBTIRPC
 
+#include <rpc/rpc_com.h>
+
 #define SVC_CREATE_XPRT_CACHE_SIZE	(8)
 static SVCXPRT *svc_create_xprt_cache[SVC_CREATE_XPRT_CACHE_SIZE] = { NULL, };
 
@@ -401,6 +403,7 @@ 
 	const struct sigaction create_sigaction = {
 		.sa_handler	= SIG_IGN,
 	};
+	int maxrec = RPC_MAXDATASIZE;
 	unsigned int visible, up, servport;
 	struct netconfig *nconf;
 	void *handlep;
@@ -412,6 +415,20 @@ 
 	 */
 	(void)sigaction(SIGPIPE, &create_sigaction, NULL);
 
+	/*
+	 * Setting MAXREC also enables non-blocking mode for tcp connections.
+	 * This avoids DOS attacks by a client sending many requests but never
+	 * reading the reply:
+	 * - if a second request already is present for reading in the socket,
+	 *   after the first request just was read, libtirpc will break the
+	 *   connection. Thus an attacker can't simply send requests as fast as
+	 *   he can without waiting for the response.
+	 * - if the write buffer of the socket is full, the next write() will
+	 *   fail with EAGAIN. libtirpc will retry the write in a loop for max.
+	 *   2 seconds. If write still fails, the connection will be closed.
+	 */   
+	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
+
 	handlep = setnetconfig();
 	if (handlep == NULL) {
 		xlog(L_ERROR, "Failed to access local netconfig database: %s",