tech-net archive

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

Routing socket code uses the wrong credentials for permissions checks



Hi,

If I have a setuid process that opens a file for write that I don't have access to, then drop privileges and try to write to the file, I expect the write to succeed.
Similarly if I pass a file descriptor opened for write to another process that does not have access to the file, I expect that process to be able to write to the file.
This does not work properly with the routing socket because it uses the current lwp's credentials to do the checking. Here's the relevant code as a patch to fix
the issue (to use the socket credentials) and a test program to demonstrate the issue. I am planning to fix this soon, unless someone has a reason why not to.

Best,

christos

Index: rtsock_shared.c
===================================================================
RCS file: /cvsroot/src/sys/net/rtsock_shared.c,v
retrieving revision 1.16
diff -u -u -r1.16 rtsock_shared.c
--- rtsock_shared.c     12 Mar 2020 19:36:33 -0000      1.16
+++ rtsock_shared.c     12 Mar 2020 22:17:02 -0000
@@ -703,10 +703,10 @@
        }

        /*
-        * Verify that the caller has the appropriate privilege; RTM_GET
+        * Verify that the socket has the appropriate privilege; RTM_GET
         * is the only operation the non-superuser is allowed.
         */
-       if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_ROUTE,
+       if (kauth_authorize_network(so->so_cred, KAUTH_NETWORK_ROUTE,
            0, rtm, NULL, NULL) != 0)
                senderr(EACCES);

[6:22pm] 10>cat ~/foo.c
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <unistd.h>
#include <sys/socket.h>
#include <net/route.h>
#include <netinet/in.h>

int
checkrtmsg(int fd) {
        /*
         * Send a routing message that is not supported to check for access
         */
        static struct sockaddr_in sin = {
                .sin_len = sizeof(sin),
                .sin_family = AF_INET,
        };
        char buf[4096];
        struct rt_msghdr *rtm = (void *)buf;
        char *cp = (char *)(rtm + 1);
        int l;

#define NEXTADDR(s) \
        l = RT_ROUNDUP((s)->sin_len); memmove(cp, s, l); cp += l;
        memset(buf, 0, sizeof(buf));
        rtm->rtm_type = RTM_IFANNOUNCE;
        rtm->rtm_flags = 0;
        rtm->rtm_addrs = RTA_DST|RTA_GATEWAY;
        rtm->rtm_version = RTM_VERSION;
        rtm->rtm_seq = 666;
        NEXTADDR(&sin);
        NEXTADDR(&sin);
        rtm->rtm_msglen = (char *)cp - (char *)rtm;
        if (write(fd, rtm, rtm->rtm_msglen) == -1)
                warn("write");
}

int main(void)
{
        int fd = socket(PF_ROUTE, SOCK_RAW, 0);
        setuid(getuid());
        printf("running as: %u %u\n", (int)geteuid(), (int)getuid());
        checkrtmsg(fd);
        return 0;
}

With a fixed kernel:
# cc foo.c
# chmod u+s a.out
#^D
[6:24pm] 13>./a.out
running as: 10080 10080
a.out: write: Operation not supported

With a broken kernel:
[6:25pm] 25>./a.out
running as: 10080 10080
a.out: write: Permission denied


Attachment: signature.asc
Description: Message signed with OpenPGP



Home | Main Index | Thread Index | Old Index