Subject: looping portmapper solved
From: [email-masked] (Thomas Koenig)
Date: Wed, 31 Aug 1994 19:12:33 GMT
Newsgroups: comp.os.linux.announce

Following is a posting to comp.unix.wizards, which explains the looping
portmapper problem on Linux, with a fix.  I've appended a binary patch
of how to solve this for a Linux system running the 4.5.26 version of
libc.

Newsgroups: comp.unix.wizards,comp.unix.bsd,comp.bugs.4bsd,comp.os.386bsd.development,comp.unix.programmer
Subject: Widespread bug in rpc-lib
Date: 30 Aug 1994 18:46:48 -0400
Organization: University of Karlsruhe, Germany
Lines: 54
Message-ID: <[email-masked]>
Reply-To: [email-masked]

[Please forward this to whoever maintains an RPC-lib based on original
 SUN code]
[Followup-To: comp.unix.bsd]

Hello, world;

there's a widespread bug in the original SUN rpc lib, which should
affect many RPC - based applications on both commercial and free
UNIX versions, including (but not limited to :-) HP-UX.

The bug is in svc_udp.c, function udp_recv():

	register int rlen;

[...]

        rlen = recvfrom(xprt->xp_sock, rpc_buffer(xprt), (int) su->su_iosz,
            0, (struct sockaddr *)&(xprt->xp_raddr), &(xprt->xp_addrlen));
        if (rlen == -1 && errno == EINTR)
                goto again;
        if (rlen < 4*sizeof(u_long))
                return (FALSE);

[rest of processing follows]

The problem occurs when recvfrom returns -1 for any other reason than an
EINTR.  4*sizeof(u_long) is an unsigned quantity, according to ANSI-C,
the compare is done unsigned on machines for which int == long, so the
processing will continue.  The last content of the buffer will be
handed back again; if this was what caused the error, an endless loop
will occur.  This is probably the reason for the looping portmappers.

The fix is easy; just change the appropriate line to

	if (rlen < (int) (4*sizeof(u_long)))

Kernels which follow RFC 1122, which states in section 4.1.3.3

# UDP MUST pass to the application layer all ICMP error
# messages that it receives from the IP layer.  Conceptually
# at least, this may be accomplished with an upcall to the
# ERROR_REPORT routine (see Section 4.2.4.1).

and handle, for example, a ICMP Destination Unreachable message by
returning -1 from recvfrom and setting errno to ECONNREFUSED,
will encounter this behaviour often; BSD - based kernels, which
silently drop most error messages for UDP, won't.

Michael Pall ([email-masked]) actually found this bug while
debugging a portmapper for Linux.

(Posting ends)

For somebody who doesn't want to recompile libc, there's also
a binary patch:

Search for the bytes 77 19 31 C0 in the binary version of libc.4.5.26
(they should be starting at address 0002a869 for the shared
version) and change the 77 to a 7F.  IF YOU DON'T KNOW HOW
TO CHANGE LIBC FROM UNDER A RUNNING SYSTEM, DON'T DO THIS.
--
Thomas Koenig, [email-masked], [email-masked].
The joy of engineering is to find a straight line on a double
logarithmic diagram.
--
Send submissions for comp.os.linux.announce to: [email-masked]
Be sure to include Keywords: and a short description of your software.