Module Name:    src
Committed By:   ozaki-r
Date:           Mon Feb 13 07:18:20 UTC 2017

Modified Files:
        src/sys/netinet: in_proto.c ip_icmp.c
        src/sys/netinet6: icmp6.c in6_proto.c

Log Message:
Protect mtudisc and redirect stuffs of icmp/icmp6 with mutex

We have to run pr_init of icmp and icmp6 prior to tcp and tcp6 ones
for mutex initialization.


To generate a diff of this commit:
cvs rdiff -u -r1.120 -r1.121 src/sys/netinet/in_proto.c
cvs rdiff -u -r1.157 -r1.158 src/sys/netinet/ip_icmp.c
cvs rdiff -u -r1.208 -r1.209 src/sys/netinet6/icmp6.c
cvs rdiff -u -r1.114 -r1.115 src/sys/netinet6/in6_proto.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/netinet/in_proto.c
diff -u src/sys/netinet/in_proto.c:1.120 src/sys/netinet/in_proto.c:1.121
--- src/sys/netinet/in_proto.c:1.120	Tue Apr 26 08:44:44 2016
+++ src/sys/netinet/in_proto.c	Mon Feb 13 07:18:20 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: in_proto.c,v 1.120 2016/04/26 08:44:44 ozaki-r Exp $	*/
+/*	$NetBSD: in_proto.c,v 1.121 2017/02/13 07:18:20 ozaki-r Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.120 2016/04/26 08:44:44 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.121 2017/02/13 07:18:20 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_mrouting.h"
@@ -201,6 +201,16 @@ const struct protosw inetsw[] = {
 	.pr_slowtimo = ip_slowtimo,
 	.pr_drain = ip_drainstub,
 },
+{	.pr_type = SOCK_RAW,
+	.pr_domain = &inetdomain,
+	.pr_protocol = IPPROTO_ICMP,
+	.pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR,
+	.pr_input = icmp_input,
+	.pr_ctlinput = rip_ctlinput,
+	.pr_ctloutput = rip_ctloutput,
+	.pr_usrreqs = &rip_usrreqs,
+	.pr_init = icmp_init,
+},
 {	.pr_type = SOCK_DGRAM,
 	.pr_domain = &inetdomain,
 	.pr_protocol = IPPROTO_UDP,
@@ -277,16 +287,6 @@ const struct protosw inetsw[] = {
 	.pr_ctloutput = rip_ctloutput,
 	.pr_usrreqs = &rip_usrreqs,
 },
-{	.pr_type = SOCK_RAW,
-	.pr_domain = &inetdomain,
-	.pr_protocol = IPPROTO_ICMP,
-	.pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR,
-	.pr_input = icmp_input,
-	.pr_ctlinput = rip_ctlinput,
-	.pr_ctloutput = rip_ctloutput,
-	.pr_usrreqs = &rip_usrreqs,
-	.pr_init = icmp_init,
-},
 #ifdef GATEWAY
 {	.pr_domain = &inetdomain,
 	.pr_protocol = IPPROTO_IP,

Index: src/sys/netinet/ip_icmp.c
diff -u src/sys/netinet/ip_icmp.c:1.157 src/sys/netinet/ip_icmp.c:1.158
--- src/sys/netinet/ip_icmp.c:1.157	Tue Feb  7 02:38:08 2017
+++ src/sys/netinet/ip_icmp.c	Mon Feb 13 07:18:20 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_icmp.c,v 1.157 2017/02/07 02:38:08 ozaki-r Exp $	*/
+/*	$NetBSD: ip_icmp.c,v 1.158 2017/02/13 07:18:20 ozaki-r Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -94,7 +94,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_icmp.c,v 1.157 2017/02/07 02:38:08 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_icmp.c,v 1.158 2017/02/13 07:18:20 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ipsec.h"
@@ -171,6 +171,9 @@ static int icmp_rediraccept = 1;
 static int icmp_redirtimeout = 600;
 static struct rttimer_queue *icmp_redirect_timeout_q = NULL;
 
+/* Protect mtudisc and redirect stuffs */
+static kmutex_t icmp_mtx __cacheline_aligned;
+
 static void icmp_mtudisc_timeout(struct rtentry *, struct rttimer *);
 static void icmp_redirect_timeout(struct rtentry *, struct rttimer *);
 
@@ -186,14 +189,17 @@ icmp_init(void)
 
 	sysctl_netinet_icmp_setup(NULL);
 
+	mutex_init(&icmp_mtx, MUTEX_DEFAULT, IPL_NONE);
 	/*
 	 * This is only useful if the user initializes redirtimeout to
 	 * something other than zero.
 	 */
+	mutex_enter(&icmp_mtx);
 	if (icmp_redirtimeout != 0) {
 		icmp_redirect_timeout_q =
 			rt_timer_queue_create(icmp_redirtimeout);
 	}
+	mutex_exit(&icmp_mtx);
 
 	icmpstat_percpu = percpu_alloc(sizeof(uint64_t) * ICMP_NSTATS);
 	icmp_wqinput = wqinput_create("icmp", _icmp_input);
@@ -205,17 +211,23 @@ icmp_init(void)
 void
 icmp_mtudisc_callback_register(void (*func)(struct in_addr))
 {
-	struct icmp_mtudisc_callback *mc;
+	struct icmp_mtudisc_callback *mc, *new;
+
+	new = kmem_alloc(sizeof(*mc), KM_SLEEP);
 
+	mutex_enter(&icmp_mtx);
 	for (mc = LIST_FIRST(&icmp_mtudisc_callbacks); mc != NULL;
 	     mc = LIST_NEXT(mc, mc_list)) {
-		if (mc->mc_func == func)
+		if (mc->mc_func == func) {
+			mutex_exit(&icmp_mtx);
+			kmem_free(new, sizeof(*mc));
 			return;
+		}
 	}
 
-	mc = kmem_alloc(sizeof(*mc), KM_SLEEP);
-	mc->mc_func = func;
-	LIST_INSERT_HEAD(&icmp_mtudisc_callbacks, mc, mc_list);
+	new->mc_func = func;
+	LIST_INSERT_HEAD(&icmp_mtudisc_callbacks, new, mc_list);
+	mutex_exit(&icmp_mtx);
 }
 
 /*
@@ -640,6 +652,7 @@ reflect:
 		rt = NULL;
 		rtredirect(sintosa(&icmpsrc), sintosa(&icmpdst),
 		    NULL, RTF_GATEWAY | RTF_HOST, sintosa(&icmpgw), &rt);
+		mutex_enter(&icmp_mtx);
 		if (rt != NULL && icmp_redirtimeout != 0) {
 			i = rt_timer_add(rt, icmp_redirect_timeout,
 					 icmp_redirect_timeout_q);
@@ -651,6 +664,7 @@ reflect:
 				    IN_PRINT(buf, &icp->icmp_ip.ip_dst), i);
 			}
 		}
+		mutex_exit(&icmp_mtx);
 		if (rt != NULL)
 			rt_unref(rt);
 
@@ -1016,19 +1030,20 @@ sysctl_net_inet_icmp_redirtimeout(SYSCTL
 	int error, tmp;
 	struct sysctlnode node;
 
+	mutex_enter(&icmp_mtx);
+
 	node = *rnode;
 	node.sysctl_data = &tmp;
 	tmp = icmp_redirtimeout;
 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
 	if (error || newp == NULL)
-		return (error);
-	if (tmp < 0)
-		return (EINVAL);
+		goto out;
+	if (tmp < 0) {
+		error = EINVAL;
+		goto out;
+	}
 	icmp_redirtimeout = tmp;
 
-	/* XXX NOMPSAFE still need softnet_lock */
-	mutex_enter(softnet_lock);
-
 	/*
 	 * was it a *defined* side-effect that anyone even *reading*
 	 * this value causes these things to happen?
@@ -1045,10 +1060,10 @@ sysctl_net_inet_icmp_redirtimeout(SYSCTL
 		icmp_redirect_timeout_q =
 		    rt_timer_queue_create(icmp_redirtimeout);
 	}
-
-	mutex_exit(softnet_lock);
-
-	return (0);
+	error = 0;
+out:
+	mutex_exit(&icmp_mtx);
+	return error;
 }
 
 static int
@@ -1175,9 +1190,11 @@ icmp_mtudisc(struct icmp *icp, struct in
 		rt = nrt;
 	}
 
+	mutex_enter(&icmp_mtx);
 	if (ip_mtudisc_timeout_q == NULL)
 		ip_mtudisc_timeout_q = rt_timer_queue_create(ip_mtudisc_timeout);
 	error = rt_timer_add(rt, icmp_mtudisc_timeout, ip_mtudisc_timeout_q);
+	mutex_exit(&icmp_mtx);
 	if (error) {
 		rt_unref(rt);
 		return;
@@ -1234,9 +1251,11 @@ icmp_mtudisc(struct icmp *icp, struct in
 	 * Notify protocols that the MTU for this destination
 	 * has changed.
 	 */
+	mutex_enter(&icmp_mtx);
 	for (mc = LIST_FIRST(&icmp_mtudisc_callbacks); mc != NULL;
 	     mc = LIST_NEXT(mc, mc_list))
 		(*mc->mc_func)(faddr);
+	mutex_exit(&icmp_mtx);
 }
 
 /*

Index: src/sys/netinet6/icmp6.c
diff -u src/sys/netinet6/icmp6.c:1.208 src/sys/netinet6/icmp6.c:1.209
--- src/sys/netinet6/icmp6.c:1.208	Tue Feb  7 02:38:08 2017
+++ src/sys/netinet6/icmp6.c	Mon Feb 13 07:18:20 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: icmp6.c,v 1.208 2017/02/07 02:38:08 ozaki-r Exp $	*/
+/*	$NetBSD: icmp6.c,v 1.209 2017/02/13 07:18:20 ozaki-r Exp $	*/
 /*	$KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.208 2017/02/07 02:38:08 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.209 2017/02/13 07:18:20 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -152,6 +152,9 @@ static struct rttimer_queue *icmp6_redir
 static int icmp6_redirect_hiwat = -1;
 static int icmp6_redirect_lowat = -1;
 
+/* Protect mtudisc and redirect stuffs */
+static kmutex_t icmp6_mtx __cacheline_aligned;
+
 static void icmp6_errcount(u_int, int, int);
 static int icmp6_rip6_input(struct mbuf **, int);
 static int icmp6_ratelimit(const struct in6_addr *, const int, const int);
@@ -180,8 +183,12 @@ icmp6_init(void)
 
 	sysctl_net_inet6_icmp6_setup(NULL);
 	mld_init();
+
+	mutex_init(&icmp6_mtx, MUTEX_DEFAULT, IPL_NONE);
+	mutex_enter(&icmp6_mtx);
 	icmp6_mtudisc_timeout_q = rt_timer_queue_create(pmtu_expire);
 	icmp6_redirect_timeout_q = rt_timer_queue_create(icmp6_redirtimeout);
+	mutex_exit(&icmp6_mtx);
 
 	icmp6stat_percpu = percpu_alloc(sizeof(uint64_t) * ICMP6_NSTATS);
 
@@ -253,17 +260,23 @@ icmp6_errcount(u_int base, int type, int
 void
 icmp6_mtudisc_callback_register(void (*func)(struct in6_addr *))
 {
-	struct icmp6_mtudisc_callback *mc;
+	struct icmp6_mtudisc_callback *mc, *new;
+
+	new = kmem_alloc(sizeof(*mc), KM_SLEEP);
 
+	mutex_enter(&icmp6_mtx);
 	for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL;
 	     mc = LIST_NEXT(mc, mc_list)) {
-		if (mc->mc_func == func)
+		if (mc->mc_func == func) {
+			mutex_exit(&icmp6_mtx);
+			kmem_free(new, sizeof(*mc));
 			return;
+		}
 	}
 
-	mc = kmem_alloc(sizeof(*mc), KM_SLEEP);
-	mc->mc_func = func;
-	LIST_INSERT_HEAD(&icmp6_mtudisc_callbacks, mc, mc_list);
+	new->mc_func = func;
+	LIST_INSERT_HEAD(&icmp6_mtudisc_callbacks, new, mc_list);
+	mutex_exit(&icmp6_mtx);
 }
 
 /*
@@ -1146,10 +1159,13 @@ icmp6_mtudisc_update(struct ip6ctlparam 
 	 * allow non-validated cases if memory is plenty, to make traffic
 	 * from non-connected pcb happy.
 	 */
+	mutex_enter(&icmp6_mtx);
 	rtcount = rt_timer_count(icmp6_mtudisc_timeout_q);
 	if (validated) {
-		if (0 <= icmp6_mtudisc_hiwat && rtcount > icmp6_mtudisc_hiwat)
+		if (0 <= icmp6_mtudisc_hiwat && rtcount > icmp6_mtudisc_hiwat) {
+			mutex_exit(&icmp6_mtx);
 			return;
+		}
 		else if (0 <= icmp6_mtudisc_lowat &&
 		    rtcount > icmp6_mtudisc_lowat) {
 			/*
@@ -1157,9 +1173,12 @@ icmp6_mtudisc_update(struct ip6ctlparam 
 			 */
 		}
 	} else {
-		if (0 <= icmp6_mtudisc_lowat && rtcount > icmp6_mtudisc_lowat)
+		if (0 <= icmp6_mtudisc_lowat && rtcount > icmp6_mtudisc_lowat) {
+			mutex_exit(&icmp6_mtx);
 			return;
+		}
 	}
+	mutex_exit(&icmp6_mtx);
 
 	memset(&sin6, 0, sizeof(sin6));
 	sin6.sin6_family = PF_INET6;
@@ -1192,9 +1211,11 @@ icmp6_mtudisc_update(struct ip6ctlparam 
 	 * Notify protocols that the MTU for this destination
 	 * has changed.
 	 */
+	mutex_enter(&icmp6_mtx);
 	for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL;
 	     mc = LIST_NEXT(mc, mc_list))
 		(*mc->mc_func)(&sin6.sin6_addr);
+	mutex_exit(&icmp6_mtx);
 }
 
 /*
@@ -2382,12 +2403,16 @@ icmp6_redirect_input(struct mbuf *m, int
 		 * work just fine even if we do not install redirect route
 		 * (there will be additional hops, though).
 		 */
+		mutex_enter(&icmp6_mtx);
 		rtcount = rt_timer_count(icmp6_redirect_timeout_q);
-		if (0 <= ip6_maxdynroutes && rtcount >= ip6_maxdynroutes)
+		if (0 <= ip6_maxdynroutes && rtcount >= ip6_maxdynroutes) {
+			mutex_exit(&icmp6_mtx);
 			goto freeit;
-		if (0 <= icmp6_redirect_hiwat && rtcount > icmp6_redirect_hiwat)
+		}
+		if (0 <= icmp6_redirect_hiwat && rtcount > icmp6_redirect_hiwat) {
+			mutex_exit(&icmp6_mtx);
 			goto freeit;
-		else if (0 <= icmp6_redirect_lowat &&
+		} else if (0 <= icmp6_redirect_lowat &&
 		    rtcount > icmp6_redirect_lowat) {
 			/*
 			 * XXX nuke a victim, install the new one.
@@ -2412,6 +2437,7 @@ icmp6_redirect_input(struct mbuf *m, int
 			    icmp6_redirect_timeout_q);
 			rt_unref(newrt);
 		}
+		mutex_exit(&icmp6_mtx);
 	}
 	/* finally update cached route in each socket via pfctlinput */
 	{
@@ -2804,8 +2830,12 @@ icmp6_mtudisc_clone(struct sockaddr *dst
 		rt_unref(rt);
 		rt = nrt;
 	}
+
+	mutex_enter(&icmp6_mtx);
 	error = rt_timer_add(rt, icmp6_mtudisc_timeout,
 			icmp6_mtudisc_timeout_q);
+	mutex_exit(&icmp6_mtx);
+
 	if (error) {
 		rt_unref(rt);
 		return NULL;
@@ -2876,14 +2906,18 @@ sysctl_net_inet6_icmp6_redirtimeout(SYSC
 	int error, tmp;
 	struct sysctlnode node;
 
+	mutex_enter(&icmp6_mtx);
+
 	node = *rnode;
 	node.sysctl_data = &tmp;
 	tmp = icmp6_redirtimeout;
 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
 	if (error || newp == NULL)
-		return error;
-	if (tmp < 0)
-		return EINVAL;
+		goto out;
+	if (tmp < 0) {
+		error = EINVAL;
+		goto out;
+	}
 	icmp6_redirtimeout = tmp;
 
 	if (icmp6_redirect_timeout_q != NULL) {
@@ -2897,8 +2931,10 @@ sysctl_net_inet6_icmp6_redirtimeout(SYSC
 		icmp6_redirect_timeout_q =
 		    rt_timer_queue_create(icmp6_redirtimeout);
 	}
-
-	return 0;
+	error = 0;
+out:
+	mutex_exit(&icmp6_mtx);
+	return error;
 }
 
 static void

Index: src/sys/netinet6/in6_proto.c
diff -u src/sys/netinet6/in6_proto.c:1.114 src/sys/netinet6/in6_proto.c:1.115
--- src/sys/netinet6/in6_proto.c:1.114	Tue Dec 13 08:29:03 2016
+++ src/sys/netinet6/in6_proto.c	Mon Feb 13 07:18:20 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6_proto.c,v 1.114 2016/12/13 08:29:03 ozaki-r Exp $	*/
+/*	$NetBSD: in6_proto.c,v 1.115 2017/02/13 07:18:20 ozaki-r Exp $	*/
 /*	$KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6_proto.c,v 1.114 2016/12/13 08:29:03 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_proto.c,v 1.115 2017/02/13 07:18:20 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_gateway.h"
@@ -213,6 +213,16 @@ const struct ip6protosw inet6sw[] = {
 	.pr_slowtimo = frag6_slowtimo,
 	.pr_drain = frag6_drainstub,
 },
+{	.pr_type = SOCK_RAW,
+	.pr_domain = &inet6domain,
+	.pr_protocol = IPPROTO_ICMPV6,
+	.pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR,
+	.pr_input = icmp6_input,
+	.pr_ctlinput = rip6_ctlinput,
+	.pr_ctloutput = icmp6_ctloutput,
+	.pr_usrreqs = &rip6_usrreqs,
+	.pr_init = icmp6_init,
+},
 {	.pr_type = SOCK_DGRAM,
 	.pr_domain = &inet6domain,
 	.pr_protocol = IPPROTO_UDP,
@@ -297,16 +307,6 @@ const struct ip6protosw inet6sw[] = {
 #endif /* GATEWAY */
 {	.pr_type = SOCK_RAW,
 	.pr_domain = &inet6domain,
-	.pr_protocol = IPPROTO_ICMPV6,
-	.pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR,
-	.pr_input = icmp6_input,
-	.pr_ctlinput = rip6_ctlinput,
-	.pr_ctloutput = icmp6_ctloutput,
-	.pr_usrreqs = &rip6_usrreqs,
-	.pr_init = icmp6_init,
-},
-{	.pr_type = SOCK_RAW,
-	.pr_domain = &inet6domain,
 	.pr_protocol = IPPROTO_DSTOPTS,
 	.pr_flags = PR_ATOMIC|PR_ADDR,
 	.pr_input = dest6_input,

Reply via email to