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);
}
/*