From e4569a0961ff9f059b9ae71327d291cf95399597 Mon Sep 17 00:00:00 2001 From: Bodo Stroesser Date: Wed, 12 Nov 2014 09:43:29 -0500 Subject: 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. Reviewed-by: NeilBrown Signed-off-by: Bodo Stroesser Signed-off-by: Steve Dickson --- support/nfs/svc_create.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c index 5291921..5cb5ff6 100644 --- a/support/nfs/svc_create.c +++ b/support/nfs/svc_create.c @@ -49,6 +49,8 @@ #ifdef HAVE_LIBTIRPC +#include + #define SVC_CREATE_XPRT_CACHE_SIZE (8) static SVCXPRT *svc_create_xprt_cache[SVC_CREATE_XPRT_CACHE_SIZE] = { NULL, }; @@ -401,6 +403,7 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version, 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 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version, */ (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", -- cgit