DragonFlyBSD Kernel Audit
DF-0743 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/netinet/ip_gre.c b/sys/netinet/ip_gre.c
--- a/sys/netinet/ip_gre.c
+++ b/sys/netinet/ip_gre.c
@@ -130,7 +130,8 @@
 gre_input2(struct mbuf *m ,int hlen, u_char proto)
 {
 	static const uint32_t af = AF_INET;
-	struct greip *gip = mtod(m, struct greip *);
+	struct ip *ip = mtod(m, struct ip *);
+	struct gre_h *gh;		/* GRE header at ip_hl*4 (IP-options aware) */
 	int isr;
 	struct gre_softc *sc;
 	u_short flags;
@@ -145,10 +146,15 @@
 
 	switch (proto) {
 	case IPPROTO_GRE:
+		/* The GRE header follows the outer IP header, whose length is
+		 * ip_hl*4 (>= 20 when IP options are present).  Do NOT overlay
+		 * struct greip (which assumes a fixed 20-byte IP header) -- read
+		 * the GRE fields at the correct ip_hl-derived offset. */
+		gh = (struct gre_h *)((caddr_t)ip + hlen);
 		hlen += sizeof (struct gre_h);
 
 		/* process GRE flags as packet can be of variable len */
-		flags = ntohs(gip->gi_flags);
+		flags = ntohs(gh->flags);
 
 		/* Checksum & Offset are present */
 		if ((flags & GRE_CP) | (flags & GRE_RP))
@@ -161,7 +167,7 @@
 		if (flags & GRE_SP)
 			hlen +=4;
 
-		switch (ntohs(gip->gi_ptype)) { /* ethertypes */
+		switch (ntohs(gh->ptype)) { /* ethertypes */
 		case ETHERTYPE_IP:
 		case WCCP_PROTOCOL_TYPE:
 			isr = NETISR_IP;
@@ -207,7 +213,7 @@
 	static const uint32_t af = AF_INET;
 	struct mbuf *m = *mp;
 	struct ip *ip = mtod(m, struct ip *);
-	struct mobip_h *mip = mtod(m, struct mobip_h *);
+	struct mobile_h *mh = (struct mobile_h *)((caddr_t)ip + (ip->ip_hl << 2));
 	struct gre_softc *sc;
 	int msiz;
 
@@ -220,16 +226,16 @@
 	IFNET_STAT_INC(&sc->sc_if, ipackets, 1);
 	IFNET_STAT_INC(&sc->sc_if, ibytes, m->m_pkthdr.len);
 
-	if(ntohs(mip->mh.proto) & MOB_H_SBIT) {
+	if(ntohs(mh->proto) & MOB_H_SBIT) {
 		msiz = MOB_H_SIZ_L;
-		mip->mi.ip_src.s_addr = mip->mh.osrc;
+		ip->ip_src.s_addr = mh->osrc;
 	} else {
 		msiz = MOB_H_SIZ_S;
 	}
-	mip->mi.ip_dst.s_addr = mip->mh.odst;
-	mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8);
+	ip->ip_dst.s_addr = mh->odst;
+	ip->ip_p = (ntohs(mh->proto) >> 8);
 
-	if (gre_in_cksum((u_short*)&mip->mh,msiz) != 0) {
+	if (gre_in_cksum((u_short*)mh,msiz) != 0) {
 		m_freem(m);
 		return(IPPROTO_DONE);
 	}