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

Reply via email to