Bug 968175 (CVE-2015-9265)

Summary: VUL-0: CVE-2015-9265: libtirpc: remote crash of RPC services
Product: [Novell Products] SUSE Security Incidents Reporter: Olaf Kirch <okir>
Component: IncidentsAssignee: Security Team bot <security-team>
Status: RESOLVED FIXED QA Contact: Security Team bot <security-team>
Severity: Major    
Priority: P3 - Medium CC: abergmann, astieger, jsegitz, karol, kukuk, meissner, okir, vpereira
Version: unspecified   
Target Milestone: unspecified   
Hardware: Other   
OS: Other   
URL: https://smash.suse.de/issue/162227/
Whiteboard: CVSSv3:SUSE:CVE-2015-9265:5.3:(AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L)
Found By: --- Services Priority:
Business Priority: Blocker: ---
Marketing QA Status: --- IT Deployment: ---
Attachments: Upstream patch
Patch for the second issue

Description Olaf Kirch 2016-02-25 08:11:59 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.
Comment 1 Olaf Kirch 2016-02-25 08:15:13 UTC
Created attachment 666827 [details]
Upstream patch
Comment 2 Andreas Stieger 2016-02-25 08:29:46 UTC
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?
Comment 3 Olaf Kirch 2016-02-25 08:53:32 UTC
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.
Comment 4 Thorsten Kukuk 2016-02-25 08:57:52 UTC
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.
Comment 6 Olaf Kirch 2016-02-25 10:15:10 UTC
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()
Comment 7 Olaf Kirch 2016-02-25 10:16:57 UTC
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.
Comment 8 Thorsten Kukuk 2016-02-25 10:32:12 UTC
(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.
Comment 9 Olaf Kirch 2016-02-25 12:22:30 UTC
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?
Comment 10 Thorsten Kukuk 2016-02-25 12:39:56 UTC
(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.
Comment 11 Swamp Workflow Management 2016-02-25 23:00:14 UTC
bugbot adjusting priority
Comment 12 Victor Pereira 2016-03-08 08:35:41 UTC
Thorsten,

I see that you are active in the upstream.. do you mind if I ask for a CVE?
Comment 13 Thorsten Kukuk 2016-03-08 11:58:18 UTC
(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.
Comment 14 Johannes Segitz 2016-04-22 10:04:17 UTC
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?
Comment 15 Olaf Kirch 2016-04-28 09:38:19 UTC
(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!
Comment 17 Thomas Blume 2018-06-15 07:05:24 UTC
(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?
Comment 18 Thorsten Kukuk 2018-06-18 08:15:04 UTC
(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.
Comment 19 Thomas Blume 2018-06-20 14:28:34 UTC
(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.
Comment 24 Thomas Blume 2018-07-02 09:04:13 UTC
Seems all codestreams are covered now.
Reassigning to security team to wrap up and close.
Comment 26 Swamp Workflow Management 2018-08-02 16:08:22 UTC
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
Comment 27 Swamp Workflow Management 2018-08-10 01:11:20 UTC
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
Comment 28 Swamp Workflow Management 2018-08-30 12:06:15 UTC
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
Comment 29 Marcus Meissner 2018-08-30 13:33:20 UTC
*** Bug 1106517 has been marked as a duplicate of this bug. ***
Comment 30 Marcus Meissner 2018-08-30 14:06:59 UTC
there was a CVE assignment race collision.

CVE-2018-14622 is the same issue and should be prefered.
Comment 32 Marcus Meissner 2018-10-15 08:58:05 UTC
done
Comment 33 Swamp Workflow Management 2018-10-15 13:09:54 UTC
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