git: 74839871be36 - main - ip_mroute: Make privilege checking more consistent

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Mon, 02 Feb 2026 16:55:16 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=74839871be363c5c2ac7ccd3396f36bdb58d19de

commit 74839871be363c5c2ac7ccd3396f36bdb58d19de
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2026-02-02 14:53:35 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-02-02 16:54:54 +0000

    ip_mroute: Make privilege checking more consistent
    
    - The v6 socket option and ioctl handlers had no privilege checks at
      all.  The socket options, I believe, can only be reached via a raw
      socket, but a jailed root user with a raw socket shouldn't be able to
      configure multicast routing in a non-VNET jail.  The ioctls can only
      be used to fetch stats.
    - Delete a bogus comment in X_mrt_ioctl(), one can issue multicast
      routing ioctls against any socket.  Note that the call path is
      soo_ioctl()->rtioctl_fib()->mrt_ioctl().
    
    I think all of the mroute privilege checks should be done within the
    ip(6)_mroute code, but let's first make the v4 and v6 modules
    consistent.
    
    Reviewed by:    glebius
    MFC after:      2 weeks
    Sponsored by:   Stormshield
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D54982
---
 sys/netinet/ip_mroute.c   |  5 -----
 sys/netinet6/ip6_mroute.c | 15 +++++++++------
 sys/netinet6/raw_ip6.c    |  6 ++++++
 3 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c
index ca32f381ff51..196ae5292909 100644
--- a/sys/netinet/ip_mroute.c
+++ b/sys/netinet/ip_mroute.c
@@ -546,11 +546,6 @@ X_mrt_ioctl(u_long cmd, caddr_t data, int fibnum __unused)
 {
 	int error;
 
-	/*
-	 * Currently the only function calling this ioctl routine is rtioctl_fib().
-	 * Typically, only root can create the raw socket in order to execute
-	 * this ioctl method, however the request might be coming from a prison
-	 */
 	error = priv_check(curthread, PRIV_NETINET_MROUTE);
 	if (error)
 		return (error);
diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c
index 5a60a3ed368f..6ca17774784b 100644
--- a/sys/netinet6/ip6_mroute.c
+++ b/sys/netinet6/ip6_mroute.c
@@ -89,6 +89,7 @@
 #include <sys/mbuf.h>
 #include <sys/module.h>
 #include <sys/domain.h>
+#include <sys/priv.h>
 #include <sys/protosw.h>
 #include <sys/sdt.h>
 #include <sys/signalvar.h>
@@ -458,24 +459,26 @@ X_ip6_mrouter_get(struct socket *so, struct sockopt *sopt)
 static int
 X_mrt6_ioctl(u_long cmd, caddr_t data)
 {
-	int ret;
-
-	ret = EINVAL;
+	int error;
 
+	error = priv_check(curthread, PRIV_NETINET_MROUTE);
+	if (error)
+		return (error);
+	error = EINVAL;
 	switch (cmd) {
 	case SIOCGETSGCNT_IN6:
-		ret = get_sg_cnt((struct sioc_sg_req6 *)data);
+		error = get_sg_cnt((struct sioc_sg_req6 *)data);
 		break;
 
 	case SIOCGETMIFCNT_IN6:
-		ret = get_mif6_cnt((struct sioc_mif_req6 *)data);
+		error = get_mif6_cnt((struct sioc_mif_req6 *)data);
 		break;
 
 	default:
 		break;
 	}
 
-	return (ret);
+	return (error);
 }
 
 /*
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index c90a1213bd66..7deb605c07a2 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -604,6 +604,9 @@ rip6_ctloutput(struct socket *so, struct sockopt *sopt)
 		case MRT6_ADD_MFC:
 		case MRT6_DEL_MFC:
 		case MRT6_PIM:
+			error = priv_check(curthread, PRIV_NETINET_MROUTE);
+			if (error != 0)
+				return (error);
 			if (inp->inp_ip_p != IPPROTO_ICMPV6)
 				return (EOPNOTSUPP);
 			error = ip6_mrouter_get ?  ip6_mrouter_get(so, sopt) :
@@ -627,6 +630,9 @@ rip6_ctloutput(struct socket *so, struct sockopt *sopt)
 		case MRT6_ADD_MFC:
 		case MRT6_DEL_MFC:
 		case MRT6_PIM:
+			error = priv_check(curthread, PRIV_NETINET_MROUTE);
+			if (error != 0)
+				return (error);
 			if (inp->inp_ip_p != IPPROTO_ICMPV6)
 				return (EOPNOTSUPP);
 			error = ip6_mrouter_set ?  ip6_mrouter_set(so, sopt) :