| From 8d2b51b008c25240914984208b2ced57d1dd25a5 Mon Sep 17 00:00:00 2001 |
| From: Guillaume Nault <gnault@redhat.com> |
| Date: Sat, 16 Jan 2021 11:44:22 +0100 |
| Subject: udp: mask TOS bits in udp_v4_early_demux() |
| |
| From: Guillaume Nault <gnault@redhat.com> |
| |
| commit 8d2b51b008c25240914984208b2ced57d1dd25a5 upstream. |
| |
| udp_v4_early_demux() is the only function that calls |
| ip_mc_validate_source() with a TOS that hasn't been masked with |
| IPTOS_RT_MASK. |
| |
| This results in different behaviours for incoming multicast UDPv4 |
| packets, depending on if ip_mc_validate_source() is called from the |
| early-demux path (udp_v4_early_demux) or from the regular input path |
| (ip_route_input_noref). |
| |
| ECN would normally not be used with UDP multicast packets, so the |
| practical consequences should be limited on that side. However, |
| IPTOS_RT_MASK is used to also masks the TOS' high order bits, to align |
| with the non-early-demux path behaviour. |
| |
| Reproducer: |
| |
| Setup two netns, connected with veth: |
| $ ip netns add ns0 |
| $ ip netns add ns1 |
| $ ip -netns ns0 link set dev lo up |
| $ ip -netns ns1 link set dev lo up |
| $ ip link add name veth01 netns ns0 type veth peer name veth10 netns ns1 |
| $ ip -netns ns0 link set dev veth01 up |
| $ ip -netns ns1 link set dev veth10 up |
| $ ip -netns ns0 address add 192.0.2.10 peer 192.0.2.11/32 dev veth01 |
| $ ip -netns ns1 address add 192.0.2.11 peer 192.0.2.10/32 dev veth10 |
| |
| In ns0, add route to multicast address 224.0.2.0/24 using source |
| address 198.51.100.10: |
| $ ip -netns ns0 address add 198.51.100.10/32 dev lo |
| $ ip -netns ns0 route add 224.0.2.0/24 dev veth01 src 198.51.100.10 |
| |
| In ns1, define route to 198.51.100.10, only for packets with TOS 4: |
| $ ip -netns ns1 route add 198.51.100.10/32 tos 4 dev veth10 |
| |
| Also activate rp_filter in ns1, so that incoming packets not matching |
| the above route get dropped: |
| $ ip netns exec ns1 sysctl -wq net.ipv4.conf.veth10.rp_filter=1 |
| |
| Now try to receive packets on 224.0.2.11: |
| $ ip netns exec ns1 socat UDP-RECVFROM:1111,ip-add-membership=224.0.2.11:veth10,ignoreeof - |
| |
| In ns0, send packet to 224.0.2.11 with TOS 4 and ECT(0) (that is, |
| tos 6 for socat): |
| $ echo test0 | ip netns exec ns0 socat - UDP-DATAGRAM:224.0.2.11:1111,bind=:1111,tos=6 |
| |
| The "test0" message is properly received by socat in ns1, because |
| early-demux has no cached dst to use, so source address validation |
| is done by ip_route_input_mc(), which receives a TOS that has the |
| ECN bits masked. |
| |
| Now send another packet to 224.0.2.11, still with TOS 4 and ECT(0): |
| $ echo test1 | ip netns exec ns0 socat - UDP-DATAGRAM:224.0.2.11:1111,bind=:1111,tos=6 |
| |
| The "test1" message isn't received by socat in ns1, because, now, |
| early-demux has a cached dst to use and calls ip_mc_validate_source() |
| immediately, without masking the ECN bits. |
| |
| Fixes: bc044e8db796 ("udp: perform source validation for mcast early demux") |
| Signed-off-by: Guillaume Nault <gnault@redhat.com> |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| net/ipv4/udp.c | 3 ++- |
| 1 file changed, 2 insertions(+), 1 deletion(-) |
| |
| --- a/net/ipv4/udp.c |
| +++ b/net/ipv4/udp.c |
| @@ -2321,7 +2321,8 @@ int udp_v4_early_demux(struct sk_buff *s |
| */ |
| if (!inet_sk(sk)->inet_daddr && in_dev) |
| return ip_mc_validate_source(skb, iph->daddr, |
| - iph->saddr, iph->tos, |
| + iph->saddr, |
| + iph->tos & IPTOS_RT_MASK, |
| skb->dev, in_dev, &itag); |
| } |
| return 0; |