Module Name: src Committed By: ozaki-r Date: Fri Mar 31 06:49:44 UTC 2017
Modified Files: src/sys/netinet: ip_icmp.c ip_input.c ip_var.h tcp_input.c src/sys/sys: mbuf.h Log Message: Don't use a single global variable to store source route information for multiple incoming packets It's not MP-safe. So use a m_tag to store the information instead. Pointed out by knakahara@ The fix is from OpenBSD (originally fixed in FreeBSD) To generate a diff of this commit: cvs rdiff -u -r1.160 -r1.161 src/sys/netinet/ip_icmp.c cvs rdiff -u -r1.353 -r1.354 src/sys/netinet/ip_input.c cvs rdiff -u -r1.118 -r1.119 src/sys/netinet/ip_var.h cvs rdiff -u -r1.355 -r1.356 src/sys/netinet/tcp_input.c cvs rdiff -u -r1.168 -r1.169 src/sys/sys/mbuf.h 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/ip_icmp.c diff -u src/sys/netinet/ip_icmp.c:1.160 src/sys/netinet/ip_icmp.c:1.161 --- src/sys/netinet/ip_icmp.c:1.160 Mon Mar 6 07:31:15 2017 +++ src/sys/netinet/ip_icmp.c Fri Mar 31 06:49:44 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_icmp.c,v 1.160 2017/03/06 07:31:15 ozaki-r Exp $ */ +/* $NetBSD: ip_icmp.c,v 1.161 2017/03/31 06:49:44 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.160 2017/03/06 07:31:15 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_icmp.c,v 1.161 2017/03/31 06:49:44 ozaki-r Exp $"); #ifdef _KERNEL_OPT #include "opt_ipsec.h" @@ -888,7 +888,7 @@ icmp_reflect(struct mbuf *m) * add on any record-route or timestamp options. */ cp = (u_char *) (ip + 1); - if ((opts = ip_srcroute()) == NULL && + if ((opts = ip_srcroute(m)) == NULL && (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) { MCLAIM(opts, m->m_owner); opts->m_len = sizeof(struct in_addr); Index: src/sys/netinet/ip_input.c diff -u src/sys/netinet/ip_input.c:1.353 src/sys/netinet/ip_input.c:1.354 --- src/sys/netinet/ip_input.c:1.353 Fri Mar 31 06:42:19 2017 +++ src/sys/netinet/ip_input.c Fri Mar 31 06:49:44 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_input.c,v 1.353 2017/03/31 06:42:19 ozaki-r Exp $ */ +/* $NetBSD: ip_input.c,v 1.354 2017/03/31 06:49:44 ozaki-r Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -91,7 +91,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.353 2017/03/31 06:42:19 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.354 2017/03/31 06:49:44 ozaki-r Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -253,25 +253,23 @@ EVCNT_ATTACH_STATIC(ip_swcsum); #endif /* INET_CSUM_COUNTERS */ /* - * We need to save the IP options in case a protocol wants to respond + * Used to save the IP options in case a protocol wants to respond * to an incoming packet over the same route if the packet got here * using IP source routing. This allows connection establishment and * maintenance when the remote end is on a network that is not known * to us. */ - -static int ip_nhops = 0; - -static struct ip_srcrt { - struct in_addr dst; /* final destination */ - char nop; /* one NOP to align */ - char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ - struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; -} ip_srcrt; +struct ip_srcrt { + int isr_nhops; /* number of hops */ + struct in_addr isr_dst; /* final destination */ + char isr_nop; /* one NOP to align */ + char isr_hdr[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN & OFFSET */ + struct in_addr isr_routes[MAX_IPOPTLEN/sizeof(struct in_addr)]; +}; static int ip_drainwanted; -static void save_rte(u_char *, struct in_addr); +static void save_rte(struct mbuf *, u_char *, struct in_addr); #ifdef MBUFTRACE struct mowner ip_rx_mowner = MOWNER_INIT("internet", "rx"); @@ -664,7 +662,6 @@ ip_input(struct mbuf *m) * error was detected (causing an icmp message * to be sent and the original packet to be freed). */ - ip_nhops = 0; /* for source routed packets */ if (hlen > sizeof (struct ip) && ip_dooptions(m)) { m = NULL; goto out; @@ -987,7 +984,7 @@ ip_dooptions(struct mbuf *m) /* * End of source route. Should be for us. */ - save_rte(cp, ip->ip_src); + save_rte(m, cp, ip->ip_src); break; } /* @@ -1226,16 +1223,25 @@ ip_rtaddr(struct in_addr dst, struct psr * up later by ip_srcroute if the receiver is interested. */ static void -save_rte(u_char *option, struct in_addr dst) +save_rte(struct mbuf *m, u_char *option, struct in_addr dst) { + struct ip_srcrt *isr; + struct m_tag *mtag; unsigned olen; olen = option[IPOPT_OLEN]; - if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) + if (olen > sizeof(isr->isr_hdr) + sizeof(isr->isr_routes)) + return; + + mtag = m_tag_get(PACKET_TAG_SRCROUTE, sizeof(*isr), M_NOWAIT); + if (mtag == NULL) return; - memcpy((void *)ip_srcrt.srcopt, (void *)option, olen); - ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); - ip_srcrt.dst = dst; + isr = (struct ip_srcrt *)(mtag + 1); + + memcpy(isr->isr_hdr, option, olen); + isr->isr_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); + isr->isr_dst = dst; + m_tag_prepend(m, mtag); } /* @@ -1244,36 +1250,43 @@ save_rte(u_char *option, struct in_addr * The first hop is placed before the options, will be removed later. */ struct mbuf * -ip_srcroute(void) +ip_srcroute(struct mbuf *m0) { struct in_addr *p, *q; struct mbuf *m; + struct ip_srcrt *isr; + struct m_tag *mtag; + + mtag = m_tag_find(m0, PACKET_TAG_SRCROUTE, NULL); + if (mtag == NULL) + return NULL; + isr = (struct ip_srcrt *)(mtag + 1); - if (ip_nhops == 0) + if (isr->isr_nhops == 0) return NULL; + m = m_get(M_DONTWAIT, MT_SOOPTS); - if (m == 0) + if (m == NULL) return NULL; MCLAIM(m, &inetdomain.dom_mowner); -#define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) +#define OPTSIZ (sizeof(isr->isr_nop) + sizeof(isr->isr_hdr)) - /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ - m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + - OPTSIZ; + /* length is (nhops+1)*sizeof(addr) + sizeof(nop + header) */ + m->m_len = (isr->isr_nhops + 1) * sizeof(struct in_addr) + OPTSIZ; /* * First save first hop for return route */ - p = &ip_srcrt.route[ip_nhops - 1]; + p = &(isr->isr_routes[isr->isr_nhops - 1]); *(mtod(m, struct in_addr *)) = *p--; /* * Copy option fields and padding (nop) to mbuf. */ - ip_srcrt.nop = IPOPT_NOP; - ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; - memmove(mtod(m, char *) + sizeof(struct in_addr), &ip_srcrt.nop, + isr->isr_nop = IPOPT_NOP; + isr->isr_hdr[IPOPT_OFFSET] = IPOPT_MINOFF; + memmove(mtod(m, char *) + sizeof(struct in_addr), &isr->isr_nop, OPTSIZ); q = (struct in_addr *)(mtod(m, char *) + sizeof(struct in_addr) + OPTSIZ); @@ -1282,14 +1295,15 @@ ip_srcroute(void) * Record return path as an IP source route, * reversing the path (pointers are now aligned). */ - while (p >= ip_srcrt.route) { + while (p >= isr->isr_routes) { *q++ = *p--; } /* * Last hop goes to final destination. */ - *q = ip_srcrt.dst; - return (m); + *q = isr->isr_dst; + m_tag_delete(m0, mtag); + return m; } const int inetctlerrmap[PRC_NCMDS] = { Index: src/sys/netinet/ip_var.h diff -u src/sys/netinet/ip_var.h:1.118 src/sys/netinet/ip_var.h:1.119 --- src/sys/netinet/ip_var.h:1.118 Fri Mar 3 07:13:06 2017 +++ src/sys/netinet/ip_var.h Fri Mar 31 06:49:44 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_var.h,v 1.118 2017/03/03 07:13:06 ozaki-r Exp $ */ +/* $NetBSD: ip_var.h,v 1.119 2017/03/31 06:49:44 ozaki-r Exp $ */ /* * Copyright (c) 1982, 1986, 1993 @@ -226,7 +226,7 @@ void ip_savecontrol(struct inpcb *, str void ip_slowtimo(void); void ip_fasttimo(void); struct mbuf * - ip_srcroute(void); + ip_srcroute(struct mbuf *); int ip_sysctl(int *, u_int, void *, size_t *, void *, size_t); void ip_statinc(u_int); void * rip_ctlinput(int, const struct sockaddr *, void *); Index: src/sys/netinet/tcp_input.c diff -u src/sys/netinet/tcp_input.c:1.355 src/sys/netinet/tcp_input.c:1.356 --- src/sys/netinet/tcp_input.c:1.355 Fri Mar 3 07:13:06 2017 +++ src/sys/netinet/tcp_input.c Fri Mar 31 06:49:44 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_input.c,v 1.355 2017/03/03 07:13:06 ozaki-r Exp $ */ +/* $NetBSD: tcp_input.c,v 1.356 2017/03/31 06:49:44 ozaki-r Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -148,7 +148,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: tcp_input.c,v 1.355 2017/03/03 07:13:06 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: tcp_input.c,v 1.356 2017/03/31 06:49:44 ozaki-r Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -4004,7 +4004,7 @@ syn_cache_get(struct sockaddr *src, stru if (inp) { inp->inp_laddr = ((struct sockaddr_in *)dst)->sin_addr; inp->inp_lport = ((struct sockaddr_in *)dst)->sin_port; - inp->inp_options = ip_srcroute(); + inp->inp_options = ip_srcroute(m); in_pcbstate(inp, INP_BOUND); if (inp->inp_options == NULL) { inp->inp_options = sc->sc_ipopts; @@ -4341,7 +4341,7 @@ syn_cache_add(struct sockaddr *src, stru /* * Remember the IP options, if any. */ - ipopts = ip_srcroute(); + ipopts = ip_srcroute(m); break; #endif default: Index: src/sys/sys/mbuf.h diff -u src/sys/sys/mbuf.h:1.168 src/sys/sys/mbuf.h:1.169 --- src/sys/sys/mbuf.h:1.168 Tue Feb 7 02:36:48 2017 +++ src/sys/sys/mbuf.h Fri Mar 31 06:49:44 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: mbuf.h,v 1.168 2017/02/07 02:36:48 ozaki-r Exp $ */ +/* $NetBSD: mbuf.h,v 1.169 2017/03/31 06:49:44 ozaki-r Exp $ */ /*- * Copyright (c) 1996, 1997, 1999, 2001, 2007 The NetBSD Foundation, Inc. @@ -922,6 +922,7 @@ struct m_tag *m_tag_next(struct mbuf *, */ #define PACKET_TAG_MPLS 29 /* Indicate it's for MPLS */ +#define PACKET_TAG_SRCROUTE 30 /* IPv4 source routing */ /* * Return the number of bytes in the mbuf chain, m.