git: 3f8927179476 - stable/14 - blacklistd: Handle fds that are pointing to routing sockets

From: Ed Maste <emaste_at_FreeBSD.org>
Date: Mon, 25 Mar 2024 22:28:56 UTC
The branch stable/14 has been updated by emaste:

URL: https://cgit.FreeBSD.org/src/commit/?id=3f89271794763da1200ee4182b5fe030570f72ba

commit 3f89271794763da1200ee4182b5fe030570f72ba
Author:     Jose Luis Duran <jlduran@gmail.com>
AuthorDate: 2022-10-12 16:14:44 +0000
Commit:     Ed Maste <emaste@FreeBSD.org>
CommitDate: 2024-03-25 22:28:30 +0000

    blacklistd: Handle fds that are pointing to routing sockets
    
    If the fd has access to make changes via the routing socket, grant full
    permission to make filter changes.
    
    Obtained from:  https://github.com/zoulasc/blocklist/commit/1b9475b2c8e0be2b9adc4d88e521ed488ac3c43c
    
    (cherry picked from commit b73612a34259a478c53eab408362d7bf879fefa6)
---
 contrib/blocklist/bin/conf.c | 113 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 95 insertions(+), 18 deletions(-)

diff --git a/contrib/blocklist/bin/conf.c b/contrib/blocklist/bin/conf.c
index 6eadf6b2ac8c..8f7e75a56be1 100644
--- a/contrib/blocklist/bin/conf.c
+++ b/contrib/blocklist/bin/conf.c
@@ -46,6 +46,7 @@ __RCSID("$NetBSD: conf.c,v 1.24 2016/04/04 15:52:56 christos Exp $");
 #include <ctype.h>
 #include <inttypes.h>
 #include <netdb.h>
+#include <unistd.h>
 #include <pwd.h>
 #include <syslog.h>
 #include <errno.h>
@@ -55,6 +56,7 @@ __RCSID("$NetBSD: conf.c,v 1.24 2016/04/04 15:52:56 christos Exp $");
 #include <arpa/inet.h>
 #include <netinet/in.h>
 #include <net/if.h>
+#include <net/route.h>
 #include <sys/socket.h>
 
 #include "bl.h"
@@ -1000,32 +1002,72 @@ confset_match(const struct confset *cs, struct conf *c,
 	return i;
 }
 
-const struct conf *
-conf_find(int fd, uid_t uid, const struct sockaddr_storage *rss,
-    struct conf *cr)
+#ifdef AF_ROUTE
+static int
+conf_route_perm(int fd) {
+#if defined(RTM_IFANNOUNCE) && defined(SA_SIZE)
+	/*
+	 * Send a routing message that is not supported to check for access
+	 * We expect EOPNOTSUPP for having access, since we are sending a
+	 * request the system does not understand and EACCES if we don't have
+	 * access.
+	 */
+	static struct sockaddr_in sin = {
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+		.sin_len = sizeof(sin),
+#endif
+		.sin_family = AF_INET,
+	};
+	char buf[4096];
+	struct rt_msghdr *rtm = (void *)buf;
+	char *cp = (char *)(rtm + 1);
+	size_t l;
+
+#define NEXTADDR(s) \
+	l = SA_SIZE(sizeof(*s)); 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 = (u_short)((char *)cp - (char *)rtm);
+	if (write(fd, rtm, rtm->rtm_msglen) != -1) {
+		(*lfun)(LOG_ERR, "Writing to routing socket succeeded!");
+		return 0;
+	}
+	switch (errno) {
+	case EACCES:
+		return 0;
+	case EOPNOTSUPP:
+		return 1;
+	default:
+		(*lfun)(LOG_ERR,
+		    "Unexpected error writing to routing socket (%m)");
+		return 0;
+	}
+#else
+	return 0;
+#endif
+}
+#endif
+
+static int
+conf_handle_inet(int fd, const void *lss, struct conf *cr)
 {
-	int proto;
-	socklen_t slen;
-	struct sockaddr_storage lss;
-	size_t i;
 	char buf[BUFSIZ];
+	int proto;
+	socklen_t slen = sizeof(proto);
 
-	memset(cr, 0, sizeof(*cr));
-	slen = sizeof(lss);
-	memset(&lss, 0, slen);
-	if (getsockname(fd, (void *)&lss, &slen) == -1) {
-		(*lfun)(LOG_ERR, "getsockname failed (%m)");
-		return NULL;
-	}
-
-	slen = sizeof(proto);
 	if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &proto, &slen) == -1) {
 		(*lfun)(LOG_ERR, "getsockopt failed (%m)");
-		return NULL;
+		return -1;
 	}
 
 	if (debug) {
-		sockaddr_snprintf(buf, sizeof(buf), "%a:%p", (void *)&lss);
+		sockaddr_snprintf(buf, sizeof(buf), "%a:%p", lss);
 		(*lfun)(LOG_DEBUG, "listening socket: %s", buf);
 	}
 
@@ -1038,16 +1080,51 @@ conf_find(int fd, uid_t uid, const struct sockaddr_storage *rss,
 		break;
 	default:
 		(*lfun)(LOG_ERR, "unsupported protocol %d", proto);
+		return -1;
+	}
+	return 0;
+}
+
+const struct conf *
+conf_find(int fd, uid_t uid, const struct sockaddr_storage *rss,
+    struct conf *cr)
+{
+	socklen_t slen;
+	struct sockaddr_storage lss;
+	size_t i;
+	char buf[BUFSIZ];
+
+	memset(cr, 0, sizeof(*cr));
+	slen = sizeof(lss);
+	memset(&lss, 0, slen);
+	if (getsockname(fd, (void *)&lss, &slen) == -1) {
+		(*lfun)(LOG_ERR, "getsockname failed (%m)");
 		return NULL;
 	}
 
 	switch (lss.ss_family) {
 	case AF_INET:
 		cr->c_port = ntohs(((struct sockaddr_in *)&lss)->sin_port);
+		if (conf_handle_inet(fd, &lss, cr) == -1)
+			return NULL;
 		break;
 	case AF_INET6:
 		cr->c_port = ntohs(((struct sockaddr_in6 *)&lss)->sin6_port);
+		if (conf_handle_inet(fd, &lss, cr) == -1)
+			return NULL;
 		break;
+#ifdef AF_ROUTE
+	case AF_ROUTE:
+		if (!conf_route_perm(fd)) {
+			(*lfun)(LOG_ERR,
+			    "permission denied to routing socket (%m)");
+			return NULL;
+		}
+		cr->c_proto = FSTAR;
+		cr->c_port = FSTAR;
+		memcpy(&lss, rss, sizeof(lss));
+		break;
+#endif
 	default:
 		(*lfun)(LOG_ERR, "unsupported family %d", lss.ss_family);
 		return NULL;