| diff -up nfs-utils-1.3.0/support/include/nfslib.h.orig nfs-utils-1.3.0/support/include/nfslib.h |
| --- nfs-utils-1.3.0/support/include/nfslib.h.orig 2014-03-25 11:12:07.000000000 -0400 |
| +++ nfs-utils-1.3.0/support/include/nfslib.h 2014-11-14 11:16:06.785633197 -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.0/support/nfs/rpcmisc.c.orig nfs-utils-1.3.0/support/nfs/rpcmisc.c |
| --- nfs-utils-1.3.0/support/nfs/rpcmisc.c.orig 2014-03-25 11:12:07.000000000 -0400 |
| +++ nfs-utils-1.3.0/support/nfs/rpcmisc.c 2014-11-14 11:16:06.785633197 -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.0/support/nfs/svc_create.c.orig nfs-utils-1.3.0/support/nfs/svc_create.c |
| --- nfs-utils-1.3.0/support/nfs/svc_create.c.orig 2014-03-25 11:12:07.000000000 -0400 |
| +++ nfs-utils-1.3.0/support/nfs/svc_create.c 2014-11-14 11:16:06.785633197 -0500 |
| @@ -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, }; |
| |
| @@ -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.0/support/nfs/svc_socket.c.orig nfs-utils-1.3.0/support/nfs/svc_socket.c |
| --- nfs-utils-1.3.0/support/nfs/svc_socket.c.orig 2014-03-25 11:12:07.000000000 -0400 |
| +++ nfs-utils-1.3.0/support/nfs/svc_socket.c 2014-11-14 11:16:06.785633197 -0500 |
| @@ -67,6 +67,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) |
| { |
| @@ -104,38 +137,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); |
| } |
| |
| /* |