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