diff -up nfs-utils-1.3.1/support/include/nfslib.h.save nfs-utils-1.3.1/support/include/nfslib.h --- nfs-utils-1.3.1/support/include/nfslib.h.save 2014-11-13 13:36:10.054248000 -0500 +++ nfs-utils-1.3.1/support/include/nfslib.h 2014-11-13 13:37:14.045142000 -0500 @@ -174,6 +174,7 @@ void closeall(int min); int svctcp_socket (u_long __number, int __reuse); int svcudp_socket (u_long __number); +int svcsock_nonblock (int __sock); /* Misc shared code prototypes */ size_t strlcat(char *, const char *, size_t); diff -up nfs-utils-1.3.1/support/nfs/rpcmisc.c.save nfs-utils-1.3.1/support/nfs/rpcmisc.c --- nfs-utils-1.3.1/support/nfs/rpcmisc.c.save 2014-11-13 13:36:19.386524000 -0500 +++ nfs-utils-1.3.1/support/nfs/rpcmisc.c 2014-11-13 13:37:14.051143000 -0500 @@ -104,7 +104,7 @@ makesock(int port, int proto) return -1; } - return sock; + return svcsock_nonblock(sock); } void diff -up nfs-utils-1.3.1/support/nfs/svc_create.c.save nfs-utils-1.3.1/support/nfs/svc_create.c --- nfs-utils-1.3.1/support/nfs/svc_create.c.save 2014-11-13 13:36:44.554269000 -0500 +++ nfs-utils-1.3.1/support/nfs/svc_create.c 2014-11-13 13:37:29.571601000 -0500 @@ -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, }; @@ -277,6 +279,12 @@ svc_create_nconf_rand_port(const char *n "(%s, %u, %s)", name, version, nconf->nc_netid); return 0; } + if (svcsock_nonblock(xprt->xp_fd) < 0) { + /* close() already done by svcsock_nonblock() */ + xprt->xp_fd = RPC_ANYFD; + SVC_DESTROY(xprt); + return 0; + } if (!svc_reg(xprt, program, version, dispatch, nconf)) { /* svc_reg(3) destroys @xprt in this case */ @@ -332,6 +340,7 @@ svc_create_nconf_fixed_port(const char * int fd; fd = svc_create_sock(ai->ai_addr, ai->ai_addrlen, nconf); + fd = svcsock_nonblock(fd); if (fd == -1) goto out_free; @@ -394,6 +403,7 @@ nfs_svc_create(char *name, const rpcprog const struct sigaction create_sigaction = { .sa_handler = SIG_IGN, }; + int maxrec = RPC_MAXDATASIZE; unsigned int visible, up, servport; struct netconfig *nconf; void *handlep; @@ -405,6 +415,20 @@ nfs_svc_create(char *name, const rpcprog */ (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", diff -up nfs-utils-1.3.1/support/nfs/svc_socket.c.save nfs-utils-1.3.1/support/nfs/svc_socket.c --- nfs-utils-1.3.1/support/nfs/svc_socket.c.save 2014-11-13 13:36:29.925836000 -0500 +++ nfs-utils-1.3.1/support/nfs/svc_socket.c 2014-11-13 13:37:14.055142000 -0500 @@ -76,6 +76,39 @@ int getservport(u_long number, const cha return 0; } +int +svcsock_nonblock(int sock) +{ + int flags; + + if (sock < 0) + return sock; + + /* This socket might be shared among multiple processes + * if mountd is run multi-threaded. So it is safest to + * make it non-blocking, else all threads might wake + * one will get the data, and the others will block + * indefinitely. + * In all cases, transaction on this socket are atomic + * (accept for TCP, packet-read and packet-write for UDP) + * so O_NONBLOCK will not confuse unprepared code causing + * it to corrupt messages. + * It generally safest to have O_NONBLOCK when doing an accept + * as if we get a RST after the SYN and before accept runs, + * we can block despite being told there was an acceptable + * connection. + */ + if ((flags = fcntl(sock, F_GETFL)) < 0) + perror(_("svc_socket: can't get socket flags")); + else if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0) + perror(_("svc_socket: can't set socket flags")); + else + return sock; + + (void) __close(sock); + return -1; +} + static int svc_socket (u_long number, int type, int protocol, int reuse) { @@ -113,38 +146,7 @@ svc_socket (u_long number, int type, int sock = -1; } - if (sock >= 0) - { - /* This socket might be shared among multiple processes - * if mountd is run multi-threaded. So it is safest to - * make it non-blocking, else all threads might wake - * one will get the data, and the others will block - * indefinitely. - * In all cases, transaction on this socket are atomic - * (accept for TCP, packet-read and packet-write for UDP) - * so O_NONBLOCK will not confuse unprepared code causing - * it to corrupt messages. - * It generally safest to have O_NONBLOCK when doing an accept - * as if we get a RST after the SYN and before accept runs, - * we can block despite being told there was an acceptable - * connection. - */ - int flags; - if ((flags = fcntl(sock, F_GETFL)) < 0) - { - perror (_("svc_socket: can't get socket flags")); - (void) __close (sock); - sock = -1; - } - else if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0) - { - perror (_("svc_socket: can't set socket flags")); - (void) __close (sock); - sock = -1; - } - } - - return sock; + return svcsock_nonblock(sock); } /*