On Mon, 5 Feb 2018, Alexander Bluhm wrote:

> Hi,
> 
> While reading ah_massage_headers() for the erratas, I found some
> issues which are ugly, but not security relevant.
> 
> - Declare global array ipseczeroes with zeroes constant.
> - The proto parameter contains the address family, so call it af.
> - Remove an unused if block, just keep the else.
> - If m_copyback(M_NOWAIT) fails, return with error instead of working
>   with an inconsistent mbuf.
> - ip6_nxt is u_int8_t, no need to clear the high bits.
> - The offset and next protocol are advanced for all extension
>   headers, move it after the switch.
> - ah_massage_headers() returns an errno, call the variable error.
> 
> ok?

one comment inline 

ok procter@

> 
> bluhm
> 
> Index: netinet/ip_ah.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ah.c,v
> retrieving revision 1.134
> diff -u -p -r1.134 ip_ah.c
> --- netinet/ip_ah.c   1 Feb 2018 21:06:31 -0000       1.134
> +++ netinet/ip_ah.c   5 Feb 2018 16:05:04 -0000
> @@ -80,7 +80,7 @@ void        ah_output_cb(struct cryptop *);
>  void ah_input_cb(struct cryptop *);
>  int  ah_massage_headers(struct mbuf **, int, int, int, int);
>  
> -unsigned char ipseczeroes[IPSEC_ZEROES_SIZE]; /* zeroes! */
> +const unsigned char ipseczeroes[IPSEC_ZEROES_SIZE]; /* zeroes! */
>  
>  
>  /*
> @@ -190,21 +190,19 @@ ah_zeroize(struct tdb *tdbp)
>   * Massage IPv4/IPv6 headers for AH processing.
>   */
>  int
> -ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
> +ah_massage_headers(struct mbuf **m0, int af, int skip, int alg, int out)
>  {
>       struct mbuf *m = *m0;
>       unsigned char *ptr;
> -     int off, count;
> -
> +     int error, off, count;
>       struct ip *ip;
> -
>  #ifdef INET6
>       struct ip6_ext *ip6e;
>       struct ip6_hdr ip6;
>       int ad, alloc, nxt, noff;
>  #endif /* INET6 */
>  
> -     switch (proto) {
> +     switch (af) {
>       case AF_INET:
>               /*
>                * This is the least painful way of dealing with IPv4 header
> @@ -229,10 +227,8 @@ ah_massage_headers(struct mbuf **m0, int
>  
>               /* IPv4 option processing */
>               for (off = sizeof(struct ip); off < skip;) {
> -                     if (ptr[off] == IPOPT_EOL || ptr[off] == IPOPT_NOP ||
> -                         off + 1 < skip)
> -                             ;
> -                     else {
> +                     if (ptr[off] != IPOPT_EOL && ptr[off] != IPOPT_NOP &&
> +                         off + 1 >= skip) {
>                               DPRINTF(("%s: illegal IPv4 option length for"
>                                   " option %d\n", __func__, ptr[off]));
>  
> @@ -355,7 +351,14 @@ ah_massage_headers(struct mbuf **m0, int
>                       ip6.ip6_dst.s6_addr16[1] = 0;
>  
>               /* Done with IPv6 header. */
> -             m_copyback(m, 0, sizeof(struct ip6_hdr), &ip6, M_NOWAIT);
> +             error = m_copyback(m, 0, sizeof(struct ip6_hdr), &ip6,
> +                 M_NOWAIT);
> +             if (error) {
> +                     DPRINTF(("%s: m_copyback no memory", __func__));
> +                     ahstat_inc(ahs_hdrops);
> +                     m_freem(m);
> +                     return error;
> +             }
>  
>               /* Let's deal with the remaining headers (if any). */
>               if (skip - sizeof(struct ip6_hdr) > 0) {
> @@ -386,7 +389,7 @@ ah_massage_headers(struct mbuf **m0, int
>               } else
>                       break;
>  
> -             nxt = ip6.ip6_nxt & 0xff; /* Next header type. */
> +             nxt = ip6.ip6_nxt;  /* Next header type. */
>  
>               for (off = 0; off < skip - sizeof(struct ip6_hdr);) {
>                       if (off + sizeof(struct ip6_ext) >
> @@ -428,10 +431,6 @@ ah_massage_headers(struct mbuf **m0, int
>  
>                               if (count != noff)
>                                       goto error6;
> -
> -                             /* Advance. */
> -                             off += ((ip6e->ip6e_len + 1) << 3);
> -                             nxt = ip6e->ip6e_nxt;
>                               break;
>  
>                       case IPPROTO_ROUTING:
> @@ -471,15 +470,17 @@ ah_massage_headers(struct mbuf **m0, int
>                                           (caddr_t)&ip6);
>                                       addr[0] = ip6.ip6_dst;
>                                       ip6.ip6_dst = finaldst;
> -                                     m_copyback(m, 0, sizeof(ip6), &ip6,
> -                                         M_NOWAIT);
> -
> +                                     error = m_copyback(m, 0, sizeof(ip6),
> +                                         &ip6, M_NOWAIT);
> +                                     if (error) {
> +                                             if (alloc)
> +                                                     free(ptr, M_XDATA, 0);
> +                                             ahstat_inc(ahs_hdrops);
> +                                             m_freem(m);
> +                                             return error;
> +                                     }
>                                       rh0->ip6r0_segleft = 0;
>                               }
> -
> -                             /* advance */
> -                             off += ((ip6e->ip6e_len + 1) << 3);
> -                             nxt = ip6e->ip6e_nxt;
>                               break;
>                           }
>  
> @@ -493,13 +494,22 @@ error6:
>                               m_freem(m);
>                               return EINVAL;
>                       }
> +
> +                     /* Advance. */
> +                     off += ((ip6e->ip6e_len + 1) << 3);
> +                     nxt = ip6e->ip6e_nxt;
>               }
>  
>               /* Copyback and free, if we allocated. */
>               if (alloc) {
> -                     m_copyback(m, sizeof(struct ip6_hdr),
> +                     error = m_copyback(m, sizeof(struct ip6_hdr),
>                           skip - sizeof(struct ip6_hdr), ptr, M_NOWAIT);
>                       free(ptr, M_XDATA, 0);
> +                     if (error) {
> +                             ahstat_inc(ahs_hdrops);
> +                             m_freem(m);
> +                             return error;
> +                     }
>               }
>  
>               break;
> @@ -520,7 +530,7 @@ ah_input(struct mbuf *m, struct tdb *tdb
>       struct tdb_crypto *tc;
>       u_int32_t btsx, esn;
>       u_int8_t hl;
> -     int rplen;
> +     int error, rplen;
>  #ifdef ENCDEBUG
>       char buf[INET6_ADDRSTRLEN];
>  #endif
> @@ -657,12 +667,13 @@ ah_input(struct mbuf *m, struct tdb *tdb
>       m_copyback(m, skip + rplen, ahx->authsize, ipseczeroes, M_NOWAIT);
>  
>       /* "Massage" the packet headers for crypto processing. */
> -     if ((btsx = ah_massage_headers(&m, tdb->tdb_dst.sa.sa_family,
> -         skip, ahx->type, 0)) != 0) {
> +     error = ah_massage_headers(&m, tdb->tdb_dst.sa.sa_family, skip,
> +         ahx->type, 0);
> +     if (error) {
>               /* mbuf will be free'd by callee. */

This pre-existing comment muddled me. ah_massage_headers() has already 
freed it on error.

(the callers of ah_input() pass it ownership of m, these being udp_input() 
via ipsec_common_input() and if_bridge.c:bridge_ipsec() so far as I can 
see.)

>               free(tc, M_XDATA, 0);
>               crypto_freereq(crp);
> -             return btsx;
> +             return error;
>       }
>  
>       /* Crypto operation descriptor. */
> @@ -912,7 +923,7 @@ ah_output(struct mbuf *m, struct tdb *td
>       struct mbuf *mi;
>       struct cryptop *crp;
>       u_int16_t iplen;
> -     int len, rplen, roff;
> +     int error, rplen, roff;
>       u_int8_t prot;
>       struct ah *ah;
>  #if NBPFILTER > 0
> @@ -1144,12 +1155,13 @@ ah_output(struct mbuf *m, struct tdb *td
>       m_copyback(m, protoff, sizeof(u_int8_t), &prot, M_NOWAIT);
>  
>       /* "Massage" the packet headers for crypto processing. */
> -     if ((len = ah_massage_headers(&m, tdb->tdb_dst.sa.sa_family,
> -         skip, ahx->type, 1)) != 0) {
> +     error = ah_massage_headers(&m, tdb->tdb_dst.sa.sa_family, skip,
> +         ahx->type, 1);
> +     if (error) {
>               /* mbuf will be free'd by callee. */

ditto 

>               free(tc, M_XDATA, 0);
>               crypto_freereq(crp);
> -             return len;
> +             return error;
>       }
>  
>       /* Crypto operation descriptor. */
> 
> 

Reply via email to