icmp: Validate packets received on ping sockets

We access fields of packets received from ping sockets assuming they're
echo replies, without actually checking that.  Of course, we don't expect
anything else from the kernel, but it's probably best to verify.

While we're at it, also check for short packets, or a receive address of
the wrong family.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
David Gibson 2024-01-16 16:16:17 +11:00 committed by Stefano Brivio
parent 6e86511f59
commit b6a4e20aa6

13
icmp.c
View file

@ -86,16 +86,25 @@ void icmp_sock_handler(const struct ctx *c, int af, union epoll_ref ref)
pname, strerror(errno)); pname, strerror(errno));
return; return;
} }
if (sr.sa.sa_family != af)
goto unexpected;
if (af == AF_INET) { if (af == AF_INET) {
struct icmphdr *ih4 = (struct icmphdr *)buf; struct icmphdr *ih4 = (struct icmphdr *)buf;
if ((size_t)n < sizeof(*ih4) || ih4->type != ICMP_ECHOREPLY)
goto unexpected;
/* Adjust packet back to guest-side ID */ /* Adjust packet back to guest-side ID */
ih4->un.echo.id = htons(ref.icmp.id); ih4->un.echo.id = htons(ref.icmp.id);
seq = ntohs(ih4->un.echo.sequence); seq = ntohs(ih4->un.echo.sequence);
} else if (af == AF_INET6) { } else if (af == AF_INET6) {
struct icmp6hdr *ih6 = (struct icmp6hdr *)buf; struct icmp6hdr *ih6 = (struct icmp6hdr *)buf;
if ((size_t)n < sizeof(*ih6) ||
ih6->icmp6_type != ICMPV6_ECHO_REPLY)
goto unexpected;
/* Adjust packet back to guest-side ID */ /* Adjust packet back to guest-side ID */
ih6->icmp6_identifier = htons(ref.icmp.id); ih6->icmp6_identifier = htons(ref.icmp.id);
seq = ntohs(ih6->icmp6_sequence); seq = ntohs(ih6->icmp6_sequence);
@ -118,6 +127,10 @@ void icmp_sock_handler(const struct ctx *c, int af, union epoll_ref ref)
else if (af == AF_INET6) else if (af == AF_INET6)
tap_icmp6_send(c, &sr.sa6.sin6_addr, tap_icmp6_send(c, &sr.sa6.sin6_addr,
tap_ip6_daddr(c, &sr.sa6.sin6_addr), buf, n); tap_ip6_daddr(c, &sr.sa6.sin6_addr), buf, n);
return;
unexpected:
warn("%s: Unexpected packet on ping socket", pname);
} }
/** /**