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.

Reply via email to