Bugzilla – Bug 968175
VUL-0: CVE-2015-9265: libtirpc: remote crash of RPC services
Last modified: 2018-10-23 22:50:53 UTC
libtirpc has a built-in limit on the file descriptors it can handle, because it relies on select() with its associated FD_SETSIZE limit. When you register a TCP transport, incoming connections will be handled by a function calledd rendezvous_request(), which does this: newxprt = makefd_xprt(sock, r->sendsize, r->recvsize); if (!__rpc_set_netbuf(&newxprt->xp_rtaddr, &addr, len)) return (FALSE); makefd_xprt in turn has this little safety built in: if (fd >= FD_SETSIZE) { warnx("svc_vc: makefd_xprt: fd too high\n"); xprt = NULL; goto done; } [...] done: return (xprt); That combination is not a healthy one. This issue was fixed upstream by 1c77f7a869bdea2a34799d774460d1f9983d45f0 but I don't think this ever received a CVE.
Created attachment 666827 [details] Upstream patch
Moving to security incidents. Olaf, where is the upstream git, or could you check the commit ID? Reason is that it's not found in git://git.infradead.org/~steved/libtirpc.git And I guess you would like us to get a CVE assigned?
Hi Andreas, the upstream git repo moved to git://linux-nfs.org/~steved/libtirpc Whether you want a CVE for this or not is a decision I leave to you. But since it's a remote DoS I guess it warrants a CVE, and a heads-up to other vendors.
We should differentiate here, about which libtirpc version we are speaking. For the version using select() (shipped by us until SLE12SP1), this is correct. For the version using poll() (shipped with Tumbleweed and starting of SLE12 SP2), the FD_SETSIZE check is completly wrong. I have to go through the tirpc code and remove all this obsolete stuff.
Okay... http://git.linux-nfs.org/?p=steved/libtirpc.git;a=commit;h=1c77f7a869bdea2a34799d774460d1f9983d45f0 Alex?
Okay, this is not the only remote DoS along these lines. If you're opening more connnections than the server's ulimits allow, it runs into an endless loop: again: if ((sock = accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, &len)) < 0) { if (errno == EINTR) goto again; /* * Clean out the most idle file descriptor when we're * running out. */ if (errno == EMFILE || errno == ENFILE) { cleanfds = svc_fdset; __svc_clean_idle(&cleanfds, 0, FALSE); goto again; } return (FALSE); } The "clean_idle" stuff looks like it's a great idea, except that it's a NOP in our case, as shown by strace: accept(5, 0x7ffd6c4ea2a0, [128]) = -1 EMFILE (Too many open files) accept(5, 0x7ffd6c4ea2a0, [128]) = -1 EMFILE (Too many open files) accept(5, 0x7ffd6c4ea2a0, [128]) = -1 EMFILE (Too many open files) accept(5, 0x7ffd6c4ea2a0, [128]) = -1 EMFILE (Too many open files) accept(5, 0x7ffd6c4ea2a0, [128]) = -1 EMFILE (Too many open files) accept(5, 0x7ffd6c4ea2a0, [128]) = -1 EMFILE (Too many open files) accept(5, 0x7ffd6c4ea2a0, [128]) = -1 EMFILE (Too many open files) accept(5, 0x7ffd6c4ea2a0, [128]) = -1 EMFILE (Too many open files) accept(5, 0x7ffd6c4ea2a0, [128]) = -1 EMFILE (Too many open files) accept(5, 0x7ffd6c4ea2a0, [128]) = -1 EMFILE (Too many open files) accept(5, 0x7ffd6c4ea2a0, [128]) = -1 EMFILE (Too many open files) accept(5, 0x7ffd6c4ea2a0, [128]) = -1 EMFILE (Too many open files) ... This probably goes back to all connections being created as "blocking", i.e. with cd->nonblock = FALSE. This causes them to get skipped in __svc_clean_idle()
Thorsten, I checked and this is also a problem in the latest upstream code. You gutted __svc_clean_idle there (because the new code no longer as the SVC_FDSETSIZE limit) - but when running into an EMFILE, the new code will loop just like the old code does.
(In reply to Olaf Kirch from comment #7) > Thorsten, I checked and this is also a problem in the latest upstream code. > You gutted __svc_clean_idle there (because the new code no longer as the > SVC_FDSETSIZE limit) - but when running into an EMFILE, the new code will > loop just like the old code does. The "goto again;" needs to be removed in the current git version.
Created attachment 666865 [details] Patch for the second issue This is a potential patch for the EMFILE issue. Thorsten, would you do me a favor and review this patch, please?
(In reply to Olaf Kirch from comment #9) > Created attachment 666865 [details] > Patch for the second issue > > This is a potential patch for the EMFILE issue. Thorsten, would you do me a > favor and review this patch, please? Since the code was copied 1:1 from netbsd, we should create a bug report against netbsd... The patch looks Ok for me, but I don't know if it will help and I did never really understand this part of the code.
bugbot adjusting priority
Thorsten, I see that you are active in the upstream.. do you mind if I ask for a CVE?
(In reply to Victor Pereira from comment #12) > Thorsten, > > I see that you are active in the upstream.. do you mind if I ask for a CVE? I have nothing to do with this bug. Maybe Olaf knows.
So this bug is still private. If we want to get a CVE we need to make the information public. Is this okay for you Olaf, or do you want to coordinate with upstream?
(In reply to Johannes Segitz from comment #14) > So this bug is still private. If we want to get a CVE we need to make the > information public. Is this okay for you Olaf, or do you want to coordinate > with upstream? Fine with me!
(In reply to Thorsten Kukuk from comment #8) > (In reply to Olaf Kirch from comment #7) > > Thorsten, I checked and this is also a problem in the latest upstream code. > > You gutted __svc_clean_idle there (because the new code no longer as the > > SVC_FDSETSIZE limit) - but when running into an EMFILE, the new code will > > loop just like the old code does. > > The "goto again;" needs to be removed in the current git version. It seems that has been addressed upstream: --> commit fce98161d9815ea016855d9f00274276452c2c4b (tag: libtirpc-1-0-2-rc2) Author: Steve Dickson <steved@redhat.com> Date: Thu Mar 3 14:31:08 2016 -0500 rendezvous_request: fix endless loop in EMFILE case With the port to poll, and endless loop can be created when we run out of file descriptors. Remove the code that tries to recover from that error Signed-off-by: Steve Dickson <steved@redhat.com> diff --git a/src/svc_vc.c b/src/svc_vc.c index 7415244..97a76a3 100644 --- a/src/svc_vc.c +++ b/src/svc_vc.c @@ -332,22 +332,10 @@ rendezvous_request(xprt, msg) r = (struct cf_rendezvous *)xprt->xp_p1; again: len = sizeof addr; - if ((sock = accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, - &len)) < 0) { + sock = accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, &len); + if (sock < 0) { if (errno == EINTR) goto again; - - if (errno == EMFILE || errno == ENFILE) { - /* 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. */ - struct timespec ts = { .tv_sec = 0, .tv_nsec = 50000000 }; - nanosleep (&ts, NULL); - goto again; - } return (FALSE); } /* --< Thorsten, can you confirm please?
(In reply to Thomas Blume from comment #17) > Thorsten, can you confirm please? It shouldn't loop anymore, so you can assume it is fixed. I have no test case to verify that.
(In reply to Thorsten Kukuk from comment #18) > (In reply to Thomas Blume from comment #17) > > > Thorsten, can you confirm please? > > It shouldn't loop anymore, so you can assume it is fixed. I have no test > case to verify that. Thanks Thorsten. I've double checked the libtirpc sources. codestream SUSE:SLE-12-SP2:Update contains the commits: 1c77f7a869bdea2a34799d774460d1f9983d45f0 b2c9430f46c4ac848957fb8adaac176a3f6ac03f but is missing: fce98161d9815ea016855d9f00274276452c2c4b I will provide a submission. The libtirpc version in SLE15 contains all commits.
Seems all codestreams are covered now. Reassigning to security team to wrap up and close.
SUSE-SU-2018:2171-1: An update that contains security fixes can now be installed. Category: security (important) Bug References: 1072183,968175 CVE References: Sources used: SUSE Linux Enterprise Software Development Kit 12-SP3 (src): libtirpc-1.0.1-17.3.1 SUSE Linux Enterprise Server 12-SP3 (src): libtirpc-1.0.1-17.3.1 SUSE Linux Enterprise Desktop 12-SP3 (src): libtirpc-1.0.1-17.3.1 SUSE CaaS Platform ALL (src): libtirpc-1.0.1-17.3.1 SUSE CaaS Platform 3.0 (src): libtirpc-1.0.1-17.3.1
openSUSE-SU-2018:2288-1: An update that contains security fixes can now be installed. Category: security (important) Bug References: 1072183,968175 CVE References: Sources used: openSUSE Leap 42.3 (src): libtirpc-1.0.1-5.3.1
SUSE-SU-2018:2557-1: An update that contains security fixes can now be installed. Category: security (moderate) Bug References: 968175 CVE References: Sources used: SUSE Linux Enterprise Software Development Kit 11-SP4 (src): libtirpc-0.2.1-1.13.3.3 SUSE Linux Enterprise Server 11-SP4 (src): libtirpc-0.2.1-1.13.3.3 SUSE Linux Enterprise Debuginfo 11-SP4 (src): libtirpc-0.2.1-1.13.3.3
*** Bug 1106517 has been marked as a duplicate of this bug. ***
there was a CVE assignment race collision. CVE-2018-14622 is the same issue and should be prefered.
done
SUSE-SU-2018:3146-1: An update that solves two vulnerabilities and has one errata is now available. Category: security (moderate) Bug References: 1106517,1106519,968175 CVE References: CVE-2018-14621,CVE-2018-14622 Sources used: SUSE Linux Enterprise Software Development Kit 11-SP4 (src): libtirpc-0.2.1-1.13.6.1 SUSE Linux Enterprise Server 11-SP4 (src): libtirpc-0.2.1-1.13.6.1 SUSE Linux Enterprise Debuginfo 11-SP4 (src): libtirpc-0.2.1-1.13.6.1