[PATCH] DoS in RPC implementation (CVE-2011-4069)

Jeff Law law@redhat.com
Wed Nov 28 18:17:00 GMT 2012


On 11/21/2012 03:10 PM, Roland McGrath wrote:
>> --- a/sunrpc/Versions
>> +++ b/sunrpc/Versions
>> @@ -118,5 +118,6 @@ libc {
>>     }
>>     GLIBC_PRIVATE {
>>       __libc_clntudp_bufcreate; __libc_rpc_getport;
>> +    __svc_accept_failed;
> [...]
>> --- a/sunrpc/rpc/svc.h
>> +++ b/sunrpc/rpc/svc.h
>> @@ -316,4 +316,5 @@ extern SVCXPRT *svcunix_create (int __sock, u_int __sendsize, u_int __recvsize,
>>
>>   __END_DECLS
>>
>> +extern void __svc_accept_failed (void) attribute_hidden;
>
> Either it's hidden or it needs to be exported, not both.
It should be hidden (I think); it doesn't need to be used by anything 
except the internal routines within the sunrpc code.

Here's the updated version with the patch to sunrpc/Versions eliminated.




-------------- next part --------------
diff --git a/ChangeLog b/ChangeLog
index 1a2e4da..3c9427f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2012-11-28  Jeff Law <law@redhat.com>
+	    Martin Osvald <mosvald@redhat.com>
+
+	* sunrpc/rpc/svc.h (__svc_accept_failed): New prototype.
+	* sunrpc/svc.c: Include time.h.
+	(__svc_accept_failed): New function.
+	* sunrpc/svc_tcp.c (rendezvous_request): If the accept fails for
+	any reason other than EINTR, call __svc_accept_failed.
+	* sunrpc/svc_udp.c (svcudp_recv): Similarly.
+	* sunrpc/svc_unix.c (rendezvous_request): Similarly.
+
 2012-11-27  Siddhesh Poyarekar  <siddhesh@redhat.com>
 
 	[BZ #11741]
diff --git a/sunrpc/rpc/svc.h b/sunrpc/rpc/svc.h
index 54d1ac1..b324b74 100644
--- a/sunrpc/rpc/svc.h
+++ b/sunrpc/rpc/svc.h
@@ -316,4 +316,5 @@ extern SVCXPRT *svcunix_create (int __sock, u_int __sendsize, u_int __recvsize,
 
 __END_DECLS
 
+extern void __svc_accept_failed (void) attribute_hidden;
 #endif /* rpc/svc.h */
diff --git a/sunrpc/svc.c b/sunrpc/svc.c
index 103770a..e48be67 100644
--- a/sunrpc/svc.c
+++ b/sunrpc/svc.c
@@ -41,6 +41,7 @@
 #include <rpc/svc.h>
 #include <rpc/pmap_clnt.h>
 #include <sys/poll.h>
+#include <time.h>
 
 #ifdef _RPC_THREAD_SAFE_
 #define xports RPC_THREAD_VARIABLE(svc_xports_s)
@@ -544,6 +545,21 @@ svc_getreq_common (const int fd)
 }
 libc_hidden_nolink_sunrpc (svc_getreq_common, GLIBC_2_2)
 
+/* If there are no file descriptors available, then accept will fail.
+   We want to delay here so the connection request can be dequeued;
+   otherwise we can bounce between polling and accepting, never giving the
+   request a chance to dequeue and eating an enormous amount of cpu time
+   in svc_run if we're polling on many file descriptors.  */
+void 
+__svc_accept_failed (void)
+{
+  if (errno == EMFILE)
+    {
+      struct timespec ts = { .tv_sec = 0, .tv_nsec = 50000000 };
+      __nanosleep (&ts, NULL);
+    }
+}
+
 #ifdef _RPC_THREAD_SAFE_
 
 void
diff --git a/sunrpc/svc_tcp.c b/sunrpc/svc_tcp.c
index eb61549..93f2ae2 100644
--- a/sunrpc/svc_tcp.c
+++ b/sunrpc/svc_tcp.c
@@ -247,6 +247,7 @@ again:
     {
       if (errno == EINTR)
 	goto again;
+      __svc_accept_failed ();
       return FALSE;
     }
   /*
diff --git a/sunrpc/svc_udp.c b/sunrpc/svc_udp.c
index 6c4d75a..3bd718b 100644
--- a/sunrpc/svc_udp.c
+++ b/sunrpc/svc_udp.c
@@ -277,8 +277,12 @@ again:
 		       (int) su->su_iosz, 0,
 		       (struct sockaddr *) &(xprt->xp_raddr), &len);
   xprt->xp_addrlen = len;
-  if (rlen == -1 && errno == EINTR)
-    goto again;
+  if (rlen == -1)
+    {
+      if (errno == EINTR)
+	goto again;
+      __svc_accept_failed ();
+    }
   if (rlen < 16)		/* < 4 32-bit ints? */
     return FALSE;
   xdrs->x_op = XDR_DECODE;
diff --git a/sunrpc/svc_unix.c b/sunrpc/svc_unix.c
index 94507b2..5de09c6 100644
--- a/sunrpc/svc_unix.c
+++ b/sunrpc/svc_unix.c
@@ -244,6 +244,7 @@ again:
     {
       if (errno == EINTR)
 	goto again;
+      __svc_accept_failed ();
       return FALSE;
     }
   /*


More information about the Libc-alpha mailing list