Hello,

I like the idea. I would just consider to make ip6_hbhchcheck()
to always free mp on error and set NULL as return value.

for example here in current ip6_input_if() we may leak memory
on error:

 308 int
 309 ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet 
*ifp)
 310 {
....
 423 #ifdef MROUTING
 424                 if (ip6_mforwarding && ip6_mrouter[ifp->if_rdomain]) {
 425                         int error;
 426 
 427                         nxt = ip6_hbhchcheck(&m, offp, &ours);
 428                         if (nxt == IPPROTO_DONE)
 429                                 goto out;
 430 
....
 575         return IPPROTO_DONE;
 576  bad:
 577         nxt = IPPROTO_DONE;
 578         m_freemp(mp);
 579  out:
 580         rtfree(rt);
 581         return nxt;
 582 }

another option would be to revisit all places where we call ip6_hbhchcheck()
and adjust caller accordingly. In my opinion all places where we
making ip6_hbhchcheck() to also free packet on error should be the
right thing to do.

other than that diff reads OK to me.

thanks and
regards
sashan


On Tue, Jun 28, 2022 at 11:50:03PM +0200, Alexander Bluhm wrote:
> Hi,
> 
> Deep in ip6_hbhchcheck() may modify the mbuf pointer.  Instead of
> having dangling pointer that we must not use, pass pointer to mbuf
> pointer and keep it consistent in the caller.
> 
> ok?
> 
> bluhm
> 
> Index: netinet6/ip6_input.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_input.c,v
> retrieving revision 1.246
> diff -u -p -r1.246 ip6_input.c
> --- netinet6/ip6_input.c      28 Jun 2022 08:24:29 -0000      1.246
> +++ netinet6/ip6_input.c      28 Jun 2022 10:51:43 -0000
> @@ -122,7 +122,7 @@ uint8_t ip6_soiikey[IP6_SOIIKEY_LEN];
>  int ip6_ours(struct mbuf **, int *, int, int);
>  int ip6_local(struct mbuf **, int *, int, int);
>  int ip6_check_rh0hdr(struct mbuf *, int *);
> -int ip6_hbhchcheck(struct mbuf *, int *, int *);
> +int ip6_hbhchcheck(struct mbuf **, int *, int *);
>  int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *);
>  struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int);
>  int ip6_sysctl_soiikey(void *, size_t *, void *, size_t);
> @@ -424,7 +424,7 @@ ip6_input_if(struct mbuf **mp, int *offp
>               if (ip6_mforwarding && ip6_mrouter[ifp->if_rdomain]) {
>                       int error;
>  
> -                     nxt = ip6_hbhchcheck(m, offp, &ours);
> +                     nxt = ip6_hbhchcheck(&m, offp, &ours);
>                       if (nxt == IPPROTO_DONE)
>                               goto out;
>  
> @@ -544,7 +544,7 @@ ip6_input_if(struct mbuf **mp, int *offp
>               goto bad;
>       }
>  
> -     nxt = ip6_hbhchcheck(m, offp, &ours);
> +     nxt = ip6_hbhchcheck(&m, offp, &ours);
>       if (nxt == IPPROTO_DONE)
>               goto out;
>  
> @@ -586,7 +586,7 @@ ip6_local(struct mbuf **mp, int *offp, i
>  {
>       NET_ASSERT_WLOCKED();
>  
> -     nxt = ip6_hbhchcheck(*mp, offp, NULL);
> +     nxt = ip6_hbhchcheck(mp, offp, NULL);
>       if (nxt == IPPROTO_DONE)
>               return IPPROTO_DONE;
>  
> @@ -597,13 +597,13 @@ ip6_local(struct mbuf **mp, int *offp, i
>  }
>  
>  int
> -ip6_hbhchcheck(struct mbuf *m, int *offp, int *oursp)
> +ip6_hbhchcheck(struct mbuf **mp, int *offp, int *oursp)
>  {
>       struct ip6_hdr *ip6;
>       u_int32_t plen, rtalert = ~0;
>       int nxt;
>  
> -     ip6 = mtod(m, struct ip6_hdr *);
> +     ip6 = mtod(*mp, struct ip6_hdr *);
>  
>       /*
>        * Process Hop-by-Hop options header if it's contained.
> @@ -615,12 +615,11 @@ ip6_hbhchcheck(struct mbuf *m, int *offp
>       if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
>               struct ip6_hbh *hbh;
>  
> -             if (ip6_hopopts_input(&plen, &rtalert, &m, offp)) {
> +             if (ip6_hopopts_input(&plen, &rtalert, mp, offp))
>                       goto bad;       /* m have already been freed */
> -             }
>  
>               /* adjust pointer */
> -             ip6 = mtod(m, struct ip6_hdr *);
> +             ip6 = mtod(*mp, struct ip6_hdr *);
>  
>               /*
>                * if the payload length field is 0 and the next header field
> @@ -634,13 +633,13 @@ ip6_hbhchcheck(struct mbuf *m, int *offp
>                        * (non-zero) payload length to the variable plen.
>                        */
>                       ip6stat_inc(ip6s_badoptions);
> -                     icmp6_error(m, ICMP6_PARAM_PROB,
> +                     icmp6_error(*mp, ICMP6_PARAM_PROB,
>                                   ICMP6_PARAMPROB_HEADER,
>                                   (caddr_t)&ip6->ip6_plen - (caddr_t)ip6);
>                       goto bad;
>               }
> -             IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
> -                     sizeof(struct ip6_hbh));
> +             IP6_EXTHDR_GET(hbh, struct ip6_hbh *, *mp,
> +                 sizeof(struct ip6_hdr), sizeof(struct ip6_hbh));
>               if (hbh == NULL) {
>                       ip6stat_inc(ip6s_tooshort);
>                       goto bad;
> @@ -662,18 +661,18 @@ ip6_hbhchcheck(struct mbuf *m, int *offp
>        * Trim mbufs if longer than we expect.
>        * Drop packet if shorter than we expect.
>        */
> -     if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) {
> +     if ((*mp)->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) {
>               ip6stat_inc(ip6s_tooshort);
> -             m_freem(m);
> +             m_freemp(mp);
>               goto bad;
>       }
> -     if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) {
> -             if (m->m_len == m->m_pkthdr.len) {
> -                     m->m_len = sizeof(struct ip6_hdr) + plen;
> -                     m->m_pkthdr.len = sizeof(struct ip6_hdr) + plen;
> +     if ((*mp)->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) {
> +             if ((*mp)->m_len == (*mp)->m_pkthdr.len) {
> +                     (*mp)->m_len = sizeof(struct ip6_hdr) + plen;
> +                     (*mp)->m_pkthdr.len = sizeof(struct ip6_hdr) + plen;
>               } else {
> -                     m_adj(m,
> -                         sizeof(struct ip6_hdr) + plen - m->m_pkthdr.len);
> +                     m_adj((*mp), sizeof(struct ip6_hdr) + plen -
> +                         (*mp)->m_pkthdr.len);
>               }
>       }
>  
> @@ -760,19 +759,18 @@ int
>  ip6_hopopts_input(u_int32_t *plenp, u_int32_t *rtalertp, struct mbuf **mp,
>      int *offp)
>  {
> -     struct mbuf *m = *mp;
>       int off = *offp, hbhlen;
>       struct ip6_hbh *hbh;
>  
>       /* validation of the length of the header */
> -     IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m,
> +     IP6_EXTHDR_GET(hbh, struct ip6_hbh *, *mp,
>               sizeof(struct ip6_hdr), sizeof(struct ip6_hbh));
>       if (hbh == NULL) {
>               ip6stat_inc(ip6s_tooshort);
>               return -1;
>       }
>       hbhlen = (hbh->ip6h_len + 1) << 3;
> -     IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
> +     IP6_EXTHDR_GET(hbh, struct ip6_hbh *, *mp, sizeof(struct ip6_hdr),
>               hbhlen);
>       if (hbh == NULL) {
>               ip6stat_inc(ip6s_tooshort);
> @@ -781,12 +779,11 @@ ip6_hopopts_input(u_int32_t *plenp, u_in
>       off += hbhlen;
>       hbhlen -= sizeof(struct ip6_hbh);
>  
> -     if (ip6_process_hopopts(m, (u_int8_t *)hbh + sizeof(struct ip6_hbh),
> +     if (ip6_process_hopopts(*mp, (u_int8_t *)hbh + sizeof(struct ip6_hbh),
>                               hbhlen, rtalertp, plenp) < 0)
>               return (-1);
>  
>       *offp = off;
> -     *mp = m;
>       return (0);
>  }
>  
> 

Reply via email to