On 05 Nov 2014 21:24:29 +0100 bstroesser@xxxxxxxxxxxxxx wrote: > 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", RPC_MAXDATASIZE is 9000. This number is only relevant on the receive size. When sending, the "sendsz" passed to svc_tli_create (which default to 64K for TCP) is used for the 'record size'. When receiving, any 'record' in a tcp connection which is larger than 9000 bytes will be rejected. No message to mountd or statd could ever be that large, so this number does not impose a problematic limit. As far as I can tell, this patch is safe and is a clear improvement. Reviewed-by: NeilBrown <neilb@xxxxxxx> Thanks, NeilBrown
Attachment:
pgpnanxPN1GSl.pgp
Description: OpenPGP digital signature