svn commit: r358730 - in head: sys/netinet usr.bin/netstat

Hiroki Sato hrs at FreeBSD.org
Sat Mar 7 08:41:11 UTC 2020


Author: hrs
Date: Sat Mar  7 08:41:10 2020
New Revision: 358730
URL: https://svnweb.freebsd.org/changeset/base/358730

Log:
  Fix an issue of net.inet.igmp.stats handler.
  The header of (struct igmpstat) could be cleared by sysctl(3).
  This can be reproduced by "netstat -s -z -p igmp".
  
  PR:	244584
  MFC after:	1 week

Modified:
  head/sys/netinet/igmp.c
  head/usr.bin/netstat/inet.c

Modified: head/sys/netinet/igmp.c
==============================================================================
--- head/sys/netinet/igmp.c	Sat Mar  7 03:58:58 2020	(r358729)
+++ head/sys/netinet/igmp.c	Sat Mar  7 08:41:10 2020	(r358730)
@@ -145,6 +145,7 @@ static void	igmp_v3_suppress_group_record(struct in_mu
 static int	sysctl_igmp_default_version(SYSCTL_HANDLER_ARGS);
 static int	sysctl_igmp_gsr(SYSCTL_HANDLER_ARGS);
 static int	sysctl_igmp_ifinfo(SYSCTL_HANDLER_ARGS);
+static int	sysctl_igmp_stat(SYSCTL_HANDLER_ARGS);
 
 static const struct netisr_handler igmp_nh = {
 	.nh_name = "igmp",
@@ -260,8 +261,9 @@ VNET_DEFINE_STATIC(int, igmp_default_version) = IGMP_V
 /*
  * Virtualized sysctls.
  */
-SYSCTL_STRUCT(_net_inet_igmp, IGMPCTL_STATS, stats, CTLFLAG_VNET | CTLFLAG_RW,
-    &VNET_NAME(igmpstat), igmpstat, "");
+SYSCTL_PROC(_net_inet_igmp, IGMPCTL_STATS, stats,
+    CTLFLAG_VNET | CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_MPSAFE,
+    &VNET_NAME(igmpstat), 0, sysctl_igmp_stat, "S,igmpstat", "");
 SYSCTL_INT(_net_inet_igmp, OID_AUTO, recvifkludge, CTLFLAG_VNET | CTLFLAG_RW,
     &VNET_NAME(igmp_recvifkludge), 0,
     "Rewrite IGMPv1/v2 reports from 0.0.0.0 to contain subnet address");
@@ -333,6 +335,59 @@ igmp_restore_context(struct mbuf *m)
 #endif
 #endif
 	return (m->m_pkthdr.flowid);
+}
+
+/*
+ * IGMP statistics.
+ */
+static int
+sysctl_igmp_stat(SYSCTL_HANDLER_ARGS)
+{
+	struct igmpstat igps0;
+	int error;
+	char *p;
+
+	error = sysctl_wire_old_buffer(req, sizeof(V_igmpstat));
+	if (error)
+		return (error);
+
+	if (req->oldptr != NULL) {
+		if (req->oldlen < sizeof(V_igmpstat))
+			error = ENOMEM;
+		else 
+			error = SYSCTL_OUT(req, &V_igmpstat,
+			    sizeof(V_igmpstat));
+	} else
+		req->validlen = sizeof(V_igmpstat);
+	if (error)
+		goto out;
+	if (req->newptr != NULL) {
+		if (req->newlen < sizeof(V_igmpstat))
+			error = ENOMEM;
+		else
+			error = SYSCTL_IN(req, &igps0,
+			    sizeof(igps0));
+		if (error)
+			goto out;
+		/*
+		 * igps0 must be "all zero".
+		 */
+		p = (char *)&igps0;
+		while (*p == '\0' && p < (char *)&igps0 + sizeof(igps0))
+			p++;
+		if (p != (char *)&igps0 + sizeof(igps0)) {
+			error = EINVAL;
+			goto out;
+		}
+		/*
+		 * Avoid overwrite of the version and length field.
+		 */
+		igps0.igps_version = V_igmpstat.igps_version;
+		igps0.igps_len = V_igmpstat.igps_len;
+		bcopy(&igps0, &V_igmpstat, sizeof(V_igmpstat));
+	}
+out:
+	return (error);
 }
 
 /*

Modified: head/usr.bin/netstat/inet.c
==============================================================================
--- head/usr.bin/netstat/inet.c	Sat Mar  7 03:58:58 2020	(r358729)
+++ head/usr.bin/netstat/inet.c	Sat Mar  7 08:41:10 2020	(r358730)
@@ -1222,10 +1222,26 @@ void
 igmp_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
 {
 	struct igmpstat igmpstat;
+	int error, zflag0;
 
 	if (fetch_stats("net.inet.igmp.stats", 0, &igmpstat,
 	    sizeof(igmpstat), kread) != 0)
 		return;
+	/*
+	 * Reread net.inet.igmp.stats when zflag == 1.
+	 * This is because this MIB contains version number and
+	 * length of the structure which are not set when clearing
+	 * the counters.
+	 */
+	zflag0 = zflag;
+	if (zflag) {
+		zflag = 0;
+		error = fetch_stats("net.inet.igmp.stats", 0, &igmpstat,
+		    sizeof(igmpstat), kread);
+		zflag = zflag0;
+		if (error)
+			return;
+	}
 
 	if (igmpstat.igps_version != IGPS_VERSION_3) {
 		xo_warnx("%s: version mismatch (%d != %d)", __func__,


More information about the svn-src-head mailing list