On 2026/11/03 5:18, Peter Maydell wrote:
In the eth_parse_ipv6_hdr() function, when parsing the extension headers we check if (input_size < ip6hdr_off + info->full_hdr_len) { return false; } This is checking that an extension header did not specify an extension header length that claims to extend off the end of the actual packet. However, we do it at the wrong end of the loop:* In the first iteration, full_hdr_len is sizeof(struct ipv6_header) (i.e. just the initial fixed IPv6 header); but this check is redundant because the initial part of the function did an iov_to_buf() of sizeof(ip6_hdr) bytes from offset ip6hdr_off, and checked that it read that many bytes. If input_size was small enough to fail the check here then the iov_to_buf() would have reported a short read * In the last iteration, we update full_hdr_len at the end of the loop, and then exit the loop without checking that that final extension header had a valid length Moving the length check to the end of the loop fixes this. This bug has no visible effects provided that all the callers validate accessses into the packet before doing them, but spotting the invalid headers at this level provides a defence in depth against bugs elsewhere; so it's cc'd to stable on that basis. Bugs #4138 and #4516 both note this mistake (in amongst a pile of other things). Cc: [email protected] Fixes: eb700029c78367 ("net_pkt: Extend packet abstraction as required by e1000e functionality") Signed-off-by: Peter Maydell <[email protected]>> ---> net/eth.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/eth.c b/net/eth.c index 12ec316e240..bc26d38dc21 100644 --- a/net/eth.c +++ b/net/eth.c @@ -485,10 +485,6 @@ bool eth_parse_ipv6_hdr(const struct iovec *pkt, int pkt_frags, info->has_ext_hdrs = true;do {- if (input_size < ip6hdr_off + info->full_hdr_len) { - return false; - } - bytes_read = iov_to_buf(pkt, pkt_frags, ip6hdr_off + info->full_hdr_len, &ext_hdr, sizeof(ext_hdr));@@ -514,6 +510,10 @@ bool eth_parse_ipv6_hdr(const struct iovec *pkt, int pkt_frags, info->full_hdr_len += (ext_hdr.ip6r_len + 1) * IP6_EXT_GRANULARITY;curr_ext_hdr_type = ext_hdr.ip6r_nxt; + if (input_size < ip6hdr_off + info->full_hdr_len) { + /* This extension header's length field was bogus */ + return false; + } } while (eth_is_ip6_extension_header_type(curr_ext_hdr_type));info->l4proto = ext_hdr.ip6r_nxt;
This is a duplicate of [1], which also contains additional changes to avoid rejecting a valid packet with the check moved, so please review it.
[1] https://lore.kernel.org/qemu-devel/[email protected]/
Regards, Akihiko Odaki
