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,