udp_input: remove a BSD stack relict

I should had removed it 9 years ago in 8ad458a471.  That commit
left save_ip as a write-only variable.

With save_ip removed we got one case when IP header can be modified:
the calculation of IP checksum with zeroed out header.  This place
already has had a header saver char b[9].  However, the b[9] saver
didn't cover the ip_sum field, which we explicitly overwrite aliased
as (struct ipovly *)->ih_len.  This was fine in cb34210012, since
checksum doesn't need to be restored if packet is consumed.  Now we
need to extend up to ip_sum field.

In collaboration with:	ae
Differential revision:	https://reviews.freebsd.org/D32719
This commit is contained in:
Gleb Smirnoff 2021-10-28 00:07:02 -07:00
parent b788a226f6
commit 3358df2973

View File

@ -398,7 +398,6 @@ udp_input(struct mbuf **mp, int *offp, int proto)
struct inpcb *inp;
uint16_t len, ip_len;
struct inpcbinfo *pcbinfo;
struct ip save_ip;
struct sockaddr_in udp_in[2];
struct mbuf *m;
struct m_tag *fwd_tag;
@ -474,15 +473,6 @@ udp_input(struct mbuf **mp, int *offp, int proto)
m_adj(m, len - ip_len);
}
/*
* Save a copy of the IP header in case we want restore it for
* sending an ICMP error message in response.
*/
if (!V_udp_blackhole)
save_ip = *ip;
else
memset(&save_ip, 0, sizeof(save_ip));
/*
* Checksum extended UDP header and data.
*/
@ -499,14 +489,15 @@ udp_input(struct mbuf **mp, int *offp, int proto)
m->m_pkthdr.csum_data + proto));
uh_sum ^= 0xffff;
} else {
char b[9];
char b[offsetof(struct ipovly, ih_src)];
struct ipovly *ipov = (struct ipovly *)ip;
bcopy(((struct ipovly *)ip)->ih_x1, b, 9);
bzero(((struct ipovly *)ip)->ih_x1, 9);
((struct ipovly *)ip)->ih_len = (proto == IPPROTO_UDP) ?
bcopy(ipov, b, sizeof(b));
bzero(ipov, sizeof(ipov->ih_x1));
ipov->ih_len = (proto == IPPROTO_UDP) ?
uh->uh_ulen : htons(ip_len);
uh_sum = in_cksum(m, len + sizeof (struct ip));
bcopy(b, ((struct ipovly *)ip)->ih_x1, 9);
bcopy(b, ipov, sizeof(b));
}
if (uh_sum) {
UDPSTAT_INC(udps_badsum);
@ -714,7 +705,6 @@ udp_input(struct mbuf **mp, int *offp, int proto)
goto badunlocked;
if (badport_bandlim(BANDLIM_ICMP_UNREACH) < 0)
goto badunlocked;
*ip = save_ip;
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
return (IPPROTO_DONE);
}