On 29/05/17(Mon) 23:45, Alexander Bluhm wrote: > Hi, > > Convert ip_input(), ip_our(), ip_deliver() functions to pr_input > parameter passing and protocol return style. Reset mp to NULL in > a few places to fail at mbuf use after free. Rename ipv4_input() > to ip_input(). > > Goal is to prepare the code that both mpi@'s and bluhm@'s diff > apply. > > ok?
I don't understand how I'm suppose to rebase my diff on top of this one. ip_ours() is now taking multiple arguments. > Index: netinet/ip_input.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_input.c,v > retrieving revision 1.306 > diff -u -p -r1.306 ip_input.c > --- netinet/ip_input.c 28 May 2017 12:22:54 -0000 1.306 > +++ netinet/ip_input.c 29 May 2017 21:38:51 -0000 > @@ -126,7 +126,7 @@ int ip_sysctl_ipstat(void *, size_t *, v > > static struct mbuf_queue ipsend_mq; > > -void ip_ours(struct mbuf *); > +int ip_ours(struct mbuf **, int *, int, int); > int ip_dooptions(struct mbuf *, struct ifnet *); > int in_ouraddr(struct mbuf *, struct ifnet *, struct rtentry **); > > @@ -211,6 +211,7 @@ void > ipintr(void) > { > struct mbuf *m; > + int off; > > /* > * Get next datagram off input queue and get IP header > @@ -221,7 +222,8 @@ ipintr(void) > if ((m->m_flags & M_PKTHDR) == 0) > panic("ipintr no HDR"); > #endif > - ipv4_input(m); > + off = 0; > + ip_input(&m, &off, IPPROTO_IPV4, AF_UNSPEC); > } > } > > @@ -230,39 +232,42 @@ ipintr(void) > * > * Checksum and byte swap header. Process options. Forward or deliver. > */ > -void > -ipv4_input(struct mbuf *m) > +int > +ip_input(struct mbuf **mp, int *offp, int nxt, int af) > { > + struct mbuf *m = *mp; > struct ifnet *ifp; > struct rtentry *rt = NULL; > struct ip *ip; > int hlen, len; > in_addr_t pfrdr = 0; > > + KASSERT(*offp == 0); > + > ifp = if_get(m->m_pkthdr.ph_ifidx); > if (ifp == NULL) > - goto bad; > + goto done; > > ipstat_inc(ips_total); > if (m->m_len < sizeof (struct ip) && > - (m = m_pullup(m, sizeof (struct ip))) == NULL) { > + (m = *mp = m_pullup(m, sizeof (struct ip))) == NULL) { > ipstat_inc(ips_toosmall); > - goto out; > + goto done; > } > ip = mtod(m, struct ip *); > if (ip->ip_v != IPVERSION) { > ipstat_inc(ips_badvers); > - goto bad; > + goto done; > } > hlen = ip->ip_hl << 2; > if (hlen < sizeof(struct ip)) { /* minimum header length */ > ipstat_inc(ips_badhlen); > - goto bad; > + goto done; > } > if (hlen > m->m_len) { > - if ((m = m_pullup(m, hlen)) == NULL) { > + if ((m = *mp = m_pullup(m, hlen)) == NULL) { > ipstat_inc(ips_badhlen); > - goto out; > + goto done; > } > ip = mtod(m, struct ip *); > } > @@ -272,20 +277,20 @@ ipv4_input(struct mbuf *m) > (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { > if ((ifp->if_flags & IFF_LOOPBACK) == 0) { > ipstat_inc(ips_badaddr); > - goto bad; > + goto done; > } > } > > if ((m->m_pkthdr.csum_flags & M_IPV4_CSUM_IN_OK) == 0) { > if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_IN_BAD) { > ipstat_inc(ips_badsum); > - goto bad; > + goto done; > } > > ipstat_inc(ips_inswcsum); > if (in_cksum(m, hlen) != 0) { > ipstat_inc(ips_badsum); > - goto bad; > + goto done; > } > } > > @@ -297,7 +302,7 @@ ipv4_input(struct mbuf *m) > */ > if (len < hlen) { > ipstat_inc(ips_badlen); > - goto bad; > + goto done; > } > > /* > @@ -308,7 +313,7 @@ ipv4_input(struct mbuf *m) > */ > if (m->m_pkthdr.len < len) { > ipstat_inc(ips_tooshort); > - goto bad; > + goto done; > } > if (m->m_pkthdr.len > len) { > if (m->m_len == m->m_pkthdr.len) { > @@ -321,7 +326,7 @@ ipv4_input(struct mbuf *m) > #if NCARP > 0 > if (ifp->if_type == IFT_CARP && ip->ip_p != IPPROTO_ICMP && > carp_lsdrop(m, AF_INET, &ip->ip_src.s_addr, &ip->ip_dst.s_addr)) > - goto bad; > + goto done; > #endif > > #if NPF > 0 > @@ -329,10 +334,11 @@ ipv4_input(struct mbuf *m) > * Packet filter > */ > pfrdr = ip->ip_dst.s_addr; > - if (pf_test(AF_INET, PF_IN, ifp, &m) != PF_PASS) > - goto bad; > + if (pf_test(AF_INET, PF_IN, ifp, mp) != PF_PASS) > + goto done; > + m = *mp; > if (m == NULL) > - goto out; > + goto done; > > ip = mtod(m, struct ip *); > hlen = ip->ip_hl << 2; > @@ -346,17 +352,18 @@ ipv4_input(struct mbuf *m) > * to be sent and the original packet to be freed). > */ > if (hlen > sizeof (struct ip) && ip_dooptions(m, ifp)) { > - goto out; > + m = *mp = NULL; > + goto done; > } > > if (ip->ip_dst.s_addr == INADDR_BROADCAST || > ip->ip_dst.s_addr == INADDR_ANY) { > - ip_ours(m); > + nxt = ip_ours(mp, offp, nxt, af); > goto out; > } > > if (in_ouraddr(m, ifp, &rt)) { > - ip_ours(m); > + nxt = ip_ours(mp, offp, nxt, af); > goto out; > } > > @@ -373,9 +380,9 @@ ipv4_input(struct mbuf *m) > int rv; > > if (m->m_flags & M_EXT) { > - if ((m = m_pullup(m, hlen)) == NULL) { > + if ((m = *mp = m_pullup(m, hlen)) == NULL) { > ipstat_inc(ips_toosmall); > - goto out; > + goto done; > } > ip = mtod(m, struct ip *); > } > @@ -396,7 +403,7 @@ ipv4_input(struct mbuf *m) > KERNEL_UNLOCK(); > if (rv != 0) { > ipstat_inc(ips_cantforward); > - goto bad; > + goto done; > } > > /* > @@ -405,7 +412,7 @@ ipv4_input(struct mbuf *m) > * host belongs to their destination groups. > */ > if (ip->ip_p == IPPROTO_IGMP) { > - ip_ours(m); > + nxt = ip_ours(mp, offp, nxt, af); > goto out; > } > ipstat_inc(ips_forward); > @@ -419,23 +426,23 @@ ipv4_input(struct mbuf *m) > ipstat_inc(ips_notmember); > if (!IN_LOCAL_GROUP(ip->ip_dst.s_addr)) > ipstat_inc(ips_cantforward); > - goto bad; > + goto done; > } > - ip_ours(m); > + nxt = ip_ours(mp, offp, nxt, af); > goto out; > } > > #if NCARP > 0 > if (ifp->if_type == IFT_CARP && ip->ip_p == IPPROTO_ICMP && > carp_lsdrop(m, AF_INET, &ip->ip_src.s_addr, &ip->ip_dst.s_addr)) > - goto bad; > + goto done; > #endif > /* > * Not for us; forward if possible and desirable. > */ > if (ipforwarding == 0) { > ipstat_inc(ips_cantforward); > - goto bad; > + goto done; > } > #ifdef IPSEC > if (ipsec_in_use) { > @@ -446,7 +453,7 @@ ipv4_input(struct mbuf *m) > KERNEL_UNLOCK(); > if (rv != 0) { > ipstat_inc(ips_cantforward); > - goto bad; > + goto done; > } > /* > * Fall through, forward packet. Outbound IPsec policy > @@ -456,13 +463,17 @@ ipv4_input(struct mbuf *m) > #endif /* IPSEC */ > > ip_forward(m, ifp, rt, pfrdr); > + *mp = NULL; > if_put(ifp); > - return; > -bad: > - m_freem(m); > -out: > + return IPPROTO_DONE; > + done: > + nxt = IPPROTO_DONE; > + m_freem(*mp); > + *mp = NULL; > + out: > rtfree(rt); > if_put(ifp); > + return nxt; > } > > /* > @@ -470,9 +481,10 @@ out: > * > * If fragmented try to reassemble. Pass to next level. > */ > -void > -ip_ours(struct mbuf *m) > +int > +ip_ours(struct mbuf **mp, int *offp, int nxt, int af) > { > + struct mbuf *m = *mp; > struct ip *ip = mtod(m, struct ip *); > struct ipq *fp; > struct ipqent *ipqe; > @@ -489,9 +501,9 @@ ip_ours(struct mbuf *m) > */ > if (ip->ip_off &~ htons(IP_DF | IP_RF)) { > if (m->m_flags & M_EXT) { /* XXX */ > - if ((m = m_pullup(m, hlen)) == NULL) { > + if ((m = *mp = m_pullup(m, hlen)) == NULL) { > ipstat_inc(ips_toosmall); > - return; > + goto done; > } > ip = mtod(m, struct ip *); > } > @@ -524,7 +536,7 @@ found: > if (ntohs(ip->ip_len) == 0 || > (ntohs(ip->ip_len) & 0x7) != 0) { > ipstat_inc(ips_badfrags); > - goto bad; > + goto done; > } > } > ip->ip_off = htons(ntohs(ip->ip_off) << 3); > @@ -539,22 +551,21 @@ found: > if (ip_frags + 1 > ip_maxqueue) { > ip_flush(); > ipstat_inc(ips_rcvmemdrop); > - goto bad; > + goto done; > } > > ipqe = pool_get(&ipqent_pool, PR_NOWAIT); > if (ipqe == NULL) { > ipstat_inc(ips_rcvmemdrop); > - goto bad; > + goto done; > } > ip_frags++; > ipqe->ipqe_mff = mff; > ipqe->ipqe_m = m; > ipqe->ipqe_ip = ip; > - m = ip_reass(ipqe, fp); > - if (m == NULL) { > - return; > - } > + m = *mp = ip_reass(ipqe, fp); > + if (m == NULL) > + goto done; > ipstat_inc(ips_reassembled); > ip = mtod(m, struct ip *); > hlen = ip->ip_hl << 2; > @@ -564,13 +575,15 @@ found: > ip_freef(fp); > } > > - ip_deliver(&m, &hlen, ip->ip_p, AF_INET); > - return; > -bad: > - m_freem(m); > + *offp = hlen; > + return ip_deliver(mp, offp, ip->ip_p, AF_INET); > + done: > + m_freem(*mp); > + *mp = NULL; > + return IPPROTO_DONE; > } > > -void > +int > ip_deliver(struct mbuf **mp, int *offp, int nxt, int af) > { > KERNEL_ASSERT_LOCKED(); > @@ -582,7 +595,7 @@ ip_deliver(struct mbuf **mp, int *offp, > if (ipsec_in_use) { > if (ipsec_local_check(*mp, *offp, nxt, af) != 0) { > ipstat_inc(ips_cantforward); > - goto bad; > + goto done; > } > } > /* Otherwise, just fall through and deliver the packet */ > @@ -594,11 +607,13 @@ ip_deliver(struct mbuf **mp, int *offp, > ipstat_inc(ips_delivered); > nxt = (*inetsw[ip_protox[nxt]].pr_input)(mp, offp, nxt, af); > KASSERT(nxt == IPPROTO_DONE); > - return; > + return nxt; > #ifdef IPSEC > - bad: > + done: > #endif > m_freem(*mp); > + *mp = NULL; > + return IPPROTO_DONE; > } > > int > @@ -867,7 +882,7 @@ dropfrag: > m_freem(m); > pool_put(&ipqent_pool, ipqe); > ip_frags--; > - return (0); > + return (NULL); > } > > /* > Index: netinet/ip_var.h > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_var.h,v > retrieving revision 1.76 > diff -u -p -r1.76 ip_var.h > --- netinet/ip_var.h 28 May 2017 09:25:51 -0000 1.76 > +++ netinet/ip_var.h 29 May 2017 21:17:35 -0000 > @@ -248,8 +248,8 @@ int ip_sysctl(int *, u_int, void *, siz > void ip_savecontrol(struct inpcb *, struct mbuf **, struct ip *, > struct mbuf *); > void ipintr(void); > -void ipv4_input(struct mbuf *); > -void ip_deliver(struct mbuf **, int *, int, int); > +int ip_input(struct mbuf **, int *, int, int); > +int ip_deliver(struct mbuf **, int *, int, int); > void ip_forward(struct mbuf *, struct ifnet *, struct rtentry *, int); > int rip_ctloutput(int, struct socket *, int, int, struct mbuf *); > void rip_init(void); >