From: Bodo Stroesser <bstroesser@xxxxxxxxxxxxxx> 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@xxxxxxxxxxxxxx> --- --- 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", ÿôèº{.nÇ+?·?®??+%?Ëÿ±éݶ¥?wÿº{.nÇ+?·¥?{±þwìþ)í?æèw*jg¬±¨¶????Ý¢jÿ¾«þG«?éÿ¢¸¢·¦j:+v?¨?wèjØm¶?ÿþø¯ù®w¥þ?àþf£¢·h??â?úÿ?Ù¥