NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

lib/45007: rcmd_af(3) and thusly rsh(1) ignore requested address family



>Number:         45007
>Category:       lib
>Synopsis:       rcmd_af(3) and thusly rsh(1) ignore requested address family
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue May 31 05:10:00 +0000 2011
>Originator:     Martin Neitzel
>Release:        5.1 and anything prior; 5-STABLE and 5.99 as of 2011-05-30
>Organization:
        Gaertner Datensysteme, Marshlabs
>Environment:
System: NetBSD nguyen.marshlabs.gaertner.de 5.1_STABLE NetBSD 5.1_STABLE 
(NGUYEN) #0: Tue May 24 22:39:32 CEST 2011 
neitzel%nguyen.marshlabs.gaertner.de@localhost:/u1/scratch/obj/sys/arch/i386/compile/NGUYEN
 i386
Architecture: any
Machine: any
>Description:
        The rsh(1) options -4 and -6 are supposed to select explicitely
        between the IPv4/IPv6 protocols but either option is effectively
        ignored.  Between a dual-stacked rsh client and server, network
        traffic will still silently flow via the system-preferred protocol,
        perhaps evading assumed crypto policies on the requested protocol
        or clashing against access restrictions on the actually used one..

        It turns out that the actual bug is in the underlying rcmd_af(3)
        library routine (part of libc).  The routine ignores its "af"
        parameter when calling out to the shell service.

        [I am torn between categories "lib" and "bin" while submitting
        this PR.  Please re-assign the category if I'm wrong with "lib".]

>How-To-Repeat:
        From some dual-stacked client,
        $ rsh -4 to.some.dualstacked.server date
        while running
        # tcpdump -tnn port 514

        You need a server name with both A and AAAA records.
        Instead of expected IPv4 traffic, you will see IPv6 traffic.

        (If you do not have the "shell" service activated: you'll
        see the SYN/RST packets using the wrong protocol.   Thusly,
        "rsh -4 www.netbsd.org date" does nicely to prove the bug
        if you just have a dual-stacked client.  Do not try to
        repeat the the bug with "localhost" as server -- rsh(1)
        will shortcut this into "/bin/sh -c ...", avoiding any
        network traffic.  A temporary, additional name for the
        v4 and v6 localhost lines in /etc/hosts would allow you
        to avoid the "localhost" shortcut and to watch the bug
        on the lo0 interface on a isolated box.)

>Fix:
        Work around on buggy systems: rcmd(1) instead of rsh(1).

        While the rcmd(1) man page doesn't mention them, it will
        handle the -4 and -6 options just fine.  (A separate PR
        will fix that documentation.)

        Real fix:

        Both rsh(1) and rcmd(1) build from the same source.
        This is the control flow:

        rsh(1) -> rcmd_af(3) -> rcmd(1)[setuid root] -> orcmd_af(3)

        rsh(1) is doing the right, turning the none/-4/-6 option
        into an AF_UNSPEC/AF_INET/AF_INET6 parameter for rcmd_af(3).
        rmcd_af(3) drops track of its "af" parameter when the target
        service is "shell" (514), however.

        The following patch (against NETBSD-5 and -current as of today,
        2011-05-30) corrects this.  The AF_whatever will be passed
        onwards and turned back into an "-4" or "-6" option to the
        rcmd(1) to be exec()ed.

        (To be frank: all this to and fro in the name of privilege
        separation doesn't make very much sense to me.  But who am
        I to tell... perhaps someone is relying on having $IN_RCMD
        pluggable, so I'm sticking with the current approach, too.)


Index: lib/libc/net/rcmd.c
===================================================================
RCS file: /cvsroot/src/lib/libc/net/rcmd.c,v
retrieving revision 1.65
diff -u -r1.65 rcmd.c
--- lib/libc/net/rcmd.c 3 Jan 2007 11:46:22 -0000       1.65
+++ lib/libc/net/rcmd.c 30 May 2011 23:54:36 -0000
@@ -77,8 +77,8 @@
 int    __ivaliduser __P((FILE *, u_int32_t, const char *, const char *));
 int    __ivaliduser_sa __P((FILE *, const struct sockaddr *, socklen_t,
            const char *, const char *));
-static int rshrcmd __P((char **, u_int32_t, const char *, const char *,
-           const char *, int *, const char *));
+static int rshrcmd __P((int, char **, u_int32_t, const char *,
+           const char *, const char *, int *, const char *));
 static int resrcmd __P((struct addrinfo *, char **, u_int32_t, const char *,
            const char *, const char *, int *));
 static int __icheckhost __P((const struct sockaddr *, socklen_t,
@@ -142,7 +142,7 @@
         */
        sp = getservbyname("shell", "tcp");
        if (sp != NULL && sp->s_port == rport)
-               error = rshrcmd(ahost, (u_int32_t)rport,
+               error = rshrcmd(af, ahost, (u_int32_t)rport,
                    locuser, remuser, cmd, fd2p, getenv("RCMD_CMD"));
        else
                error = resrcmd(res, ahost, (u_int32_t)rport,
@@ -379,7 +379,8 @@
  */
 /* ARGSUSED */
 static int
-rshrcmd(ahost, rport, locuser, remuser, cmd, fd2p, rshcmd)
+rshrcmd(af, ahost, rport, locuser, remuser, cmd, fd2p, rshcmd)
+       int     af;
        char    **ahost;
        u_int32_t       rport;
        const   char *locuser, *remuser, *cmd;
@@ -479,9 +480,26 @@
                        p = strrchr(rshcmd, '/');
                        execlp(rshcmd, p ? p + 1 : rshcmd, "-c", cmd, NULL);
                } else {
-                       p = strrchr(rshcmd, '/');
-                       execlp(rshcmd, p ? p + 1 : rshcmd, *ahost, "-l",
-                           remuser, cmd, NULL);
+                       const char *program;
+                       program = strrchr(rshcmd, '/');
+                       program = program ? program + 1 : rshcmd;
+                       switch (af) {
+                       case AF_INET:
+                               execlp(rshcmd, program, "-4", "-l", remuser,
+                                   *ahost, cmd, NULL);
+                               break;
+
+                       case AF_INET6:
+                               execlp(rshcmd, program, "-6", "-l", remuser,
+                                   *ahost, cmd, NULL);
+                               break;
+
+                       default:
+                               /* typically AF_UNSPEC, plus whatever */
+                               execlp(rshcmd, program,       "-l", remuser,
+                                   *ahost, cmd, NULL);
+                               break;
+                       }
                }
                warn("rshrcmd: exec %s", rshcmd);
                _exit(1);



Home | Main Index | Thread Index | Old Index