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);
> 

Reply via email to