From fa76812bd1aff4b60248f0a69976a465755ad96d Mon Sep 17 00:00:00 2001 From: Jan Macku Date: Fri, 6 Sep 2024 14:13:23 +0200 Subject: [PATCH] ping: Fix ping6 binding to VRF and address Resolves: RHEL-57734 --- ...Fix-ping6-binding-to-VRF-and-address.patch | 95 +++++++++++++++++++ 012-ping6-Avoid-binding-to-non-VRF.patch | 54 +++++++++++ iputils.spec | 7 +- 3 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 011-ping-Fix-ping6-binding-to-VRF-and-address.patch create mode 100644 012-ping6-Avoid-binding-to-non-VRF.patch diff --git a/011-ping-Fix-ping6-binding-to-VRF-and-address.patch b/011-ping-Fix-ping6-binding-to-VRF-and-address.patch new file mode 100644 index 0000000..10a41a5 --- /dev/null +++ b/011-ping-Fix-ping6-binding-to-VRF-and-address.patch @@ -0,0 +1,95 @@ +From 36580e1d539b4bb7c187d4cf9ccc63afad9edbb1 Mon Sep 17 00:00:00 2001 +From: Lahav Schlesinger +Date: Wed, 30 Jun 2021 13:06:13 +0300 +Subject: [PATCH 1/2] ping: Fix ping6 binding to VRF and address + +Since Linux kernel commit 1893ff20275b ("net/ipv6: Add l3mdev check to +ipv6_chk_addr_and_flags") from v4.17-rc1 ping fails when trying to +create IPv6 SOCK_RAW socket (e.g. if net.ipv4.ping_group_range = 1 0) +and passing both -I and -I . +It works for IPv4 SOCK_RAW socket. + + # ip netns add tmp_ns + # ip -n tmp_ns link add vrf_1 type vrf table 10001 + # ip -n tmp_ns link add lo10 type dummy + # ip -n tmp_ns link set lo10 master vrf_1 + # ip -n tmp_ns link set vrf_1 up + # ip -n tmp_ns link set lo10 up + # ip -n tmp_ns link set lo up + # ip -n tmp_ns addr add 1:2::3:4/128 dev lo10 + # ip -n tmp_ns addr add 1.2.3.4/32 dev lo10 + + # ip netns exec tmp_ns ping -6 1:2::3:4 -I vrf_1 -I 1:2::3:4 -c 1 # IPv6 broken + ping: bind icmp socket: Cannot assign requested address + + # ping 1.2.3.4 -I vrf_1 -I 1.2.3.4 -c 1 # IPv4 working + PING 1.2.3.4 (1.2.3.4) from 1.2.3.4 vrf_1: 56(84) bytes of data. + 64 bytes from 1.2.3.4: icmp_seq=1 ttl=64 time=0.090 ms + + --- 1.2.3.4 ping statistics --- + 1 packets transmitted, 1 received, 0% packet loss, time 0ms + rtt min/avg/max/mdev = 0.090/0.090/0.090/0.000 ms + +ping fails because it doesn't actually bind to the VRF interface, while +after 1893ff20275b, binding to an IPv6 address searches only on the same +l3mdev as the device the function receives. If the socket wasn't +SO_BINDTODEVICE-ed, then the kernel will only search for devices that +are not ensalved to an l3mdev device (= in the default VRF), which will +cause the bind() to fail. + +Only SOCK_RAW socket is affected. SOCK_DGRAM is not affected because +Linux kernel doesn't check the device the socket was SO_BINDTODEVICE-ed +to, but only the device from addr->sin6_scope_id (which if none is +passed, it will again only search devices in the default VRF). + +NOTE: creating network namespace to reproduce the issue is needed just +on systems with net.ipv4.ping_group_range = 0 2147483647 (e.g. current +Fedora, openSUSE, Ubuntu), which causes to use SOCK_DGRAM socket. +Alternatively to force SOCK_RAW to it'd be enough just to properly set +net.ipv4.ping_group_range: + + # echo "1 0" > /proc/sys/net/ipv4/ping_group_range + +Closes: https://github.com/iputils/iputils/pull/344 + +Reviewed-by: Petr Vorel +Signed-off-by: Lahav Schlesinger +[ pvorel: adjusted commit message ] +Signed-off-by: Petr Vorel +(cherry picked from commit 7c65999f98bc4a1984594b7fad1af0eaf0b9d34b) +--- + ping/ping6_common.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/ping/ping6_common.c b/ping/ping6_common.c +index 4712928..98b5adb 100644 +--- a/ping/ping6_common.c ++++ b/ping/ping6_common.c +@@ -223,6 +223,8 @@ int ping6_run(struct ping_rts *rts, int argc, char **argv, struct addrinfo *ai, + if (rts->device) { + struct cmsghdr *cmsg; + struct in6_pktinfo *ipi; ++ int rc; ++ int errno_save; + + cmsg = (struct cmsghdr *)(rts->cmsgbuf + rts->cmsglen); + rts->cmsglen += CMSG_SPACE(sizeof(*ipi)); +@@ -233,6 +235,15 @@ int ping6_run(struct ping_rts *rts, int argc, char **argv, struct addrinfo *ai, + ipi = (struct in6_pktinfo *)CMSG_DATA(cmsg); + memset(ipi, 0, sizeof(*ipi)); + ipi->ipi6_ifindex = if_name2index(rts->device); ++ ++ enable_capability_raw(); ++ rc = setsockopt(sock->fd, SOL_SOCKET, SO_BINDTODEVICE, ++ rts->device, strlen(rts->device) + 1); ++ errno_save = errno; ++ disable_capability_raw(); ++ ++ if (rc == -1) ++ error(2, errno_save, "SO_BINDTODEVICE %s", rts->device); + } + + if (IN6_IS_ADDR_MULTICAST(&rts->whereto6.sin6_addr)) { +-- +2.46.0 + diff --git a/012-ping6-Avoid-binding-to-non-VRF.patch b/012-ping6-Avoid-binding-to-non-VRF.patch new file mode 100644 index 0000000..40e26b8 --- /dev/null +++ b/012-ping6-Avoid-binding-to-non-VRF.patch @@ -0,0 +1,54 @@ +From a2d2428c5fa6bf370486f509b18862c5c7b8b47e Mon Sep 17 00:00:00 2001 +From: Petr Vorel +Date: Tue, 9 Nov 2021 02:39:56 +0100 +Subject: [PATCH 2/2] ping6: Avoid binding to non-VRF + +This fixes permission issue when specifying just address (without VRF) +unless having CAP_NET_ADMIN (i.e. root) permission: + + $ ./builddir/ping/ping -c1 -I lo ::1 + ./builddir/ping/ping: SO_BINDTODEVICE lo: Operation not permitted + +because setsockopt() SO_BINDTODEVICE (similar to bind()) can be only done on +opt_strictsource. + +Fixes: 7c65999 ("ping: Fix ping6 binding to VRF and address") + +Signed-off-by: Petr Vorel +(cherry picked from commit f52b582248f1f870e870a9973621805d969906b4) +--- + ping/ping6_common.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/ping/ping6_common.c b/ping/ping6_common.c +index 98b5adb..a784be0 100644 +--- a/ping/ping6_common.c ++++ b/ping/ping6_common.c +@@ -236,14 +236,16 @@ int ping6_run(struct ping_rts *rts, int argc, char **argv, struct addrinfo *ai, + memset(ipi, 0, sizeof(*ipi)); + ipi->ipi6_ifindex = if_name2index(rts->device); + +- enable_capability_raw(); +- rc = setsockopt(sock->fd, SOL_SOCKET, SO_BINDTODEVICE, +- rts->device, strlen(rts->device) + 1); +- errno_save = errno; +- disable_capability_raw(); +- +- if (rc == -1) +- error(2, errno_save, "SO_BINDTODEVICE %s", rts->device); ++ if (rts->opt_strictsource) { ++ enable_capability_raw(); ++ rc = setsockopt(sock->fd, SOL_SOCKET, SO_BINDTODEVICE, ++ rts->device, strlen(rts->device) + 1); ++ errno_save = errno; ++ disable_capability_raw(); ++ ++ if (rc == -1) ++ error(2, errno_save, "SO_BINDTODEVICE %s", rts->device); ++ } + } + + if (IN6_IS_ADDR_MULTICAST(&rts->whereto6.sin6_addr)) { +-- +2.46.0 + diff --git a/iputils.spec b/iputils.spec index 6cad551..e1ca804 100644 --- a/iputils.spec +++ b/iputils.spec @@ -3,7 +3,7 @@ Summary: Network monitoring tools including ping Name: iputils Version: 20210202 -Release: 10%{?dist} +Release: 11%{?dist} # some parts are under the original BSD (ping.c) # some are under GPLv2+ (tracepath.c) License: BSD and GPLv2+ @@ -29,6 +29,8 @@ Patch007: 007-ping-Move-ping_rts-multicast.patch Patch008: 008-ping-Print-reply-from-Subnet-Router-anycast-address.patch Patch009: 009-ping-Print-reply-with-wrong-source-with-warning.patch Patch010: 010-ping-Fix-socket-error-reporting.patch +Patch011: 011-ping-Fix-ping6-binding-to-VRF-and-address.patch +Patch012: 012-ping6-Avoid-binding-to-non-VRF.patch # Downstream-only patches Patch100: 100-iputils-ifenslave.patch @@ -139,6 +141,9 @@ install -cp ifenslave.8 ${RPM_BUILD_ROOT}%{_mandir}/man8/ %attr(644,root,root) %{_mandir}/man8/ninfod.8.gz %changelog +* Fri Sep 06 2024 Jan Macku - 20210202-11 +- ping: Fix ping6 binding to VRF and address (RHEL-57734) + * Wed Aug 28 2024 Jan Macku - 20210202-10 - arping: Fix 1s delay on exit for unsolicited arpings (RHEL-34110) - arping: exit 0 if running in deadline mode and we see replies (RHEL-27718)