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. */ > >