]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ipv4: Fix incorrect TOS in route get reply
authorIdo Schimmel <idosch@nvidia.com>
Mon, 15 Jul 2024 14:23:53 +0000 (17:23 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 3 Aug 2024 07:00:20 +0000 (09:00 +0200)
[ Upstream commit 338bb57e4c2a1c2c6fc92f9c0bd35be7587adca7 ]

The TOS value that is returned to user space in the route get reply is
the one with which the lookup was performed ('fl4->flowi4_tos'). This is
fine when the matched route is configured with a TOS as it would not
match if its TOS value did not match the one with which the lookup was
performed.

However, matching on TOS is only performed when the route's TOS is not
zero. It is therefore possible to have the kernel incorrectly return a
non-zero TOS:

 # ip link add name dummy1 up type dummy
 # ip address add 192.0.2.1/24 dev dummy1
 # ip route get 192.0.2.2 tos 0xfc
 192.0.2.2 tos 0x1c dev dummy1 src 192.0.2.1 uid 0
     cache

Fix by adding a DSCP field to the FIB result structure (inside an
existing 4 bytes hole), populating it in the route lookup and using it
when filling the route get reply.

Output after the patch:

 # ip link add name dummy1 up type dummy
 # ip address add 192.0.2.1/24 dev dummy1
 # ip route get 192.0.2.2 tos 0xfc
 192.0.2.2 dev dummy1 src 192.0.2.1 uid 0
     cache

Fixes: 1a00fee4ffb2 ("ipv4: Remove rt_key_{src,dst,tos} from struct rtable.")
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Guillaume Nault <gnault@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
include/net/ip_fib.h
net/ipv4/fib_trie.c
net/ipv4/route.c

index 9b2f69ba5e4981fb108581c229ff008d04750ade..c29639b4323f369683358bb937dced735c7d5b38 100644 (file)
@@ -173,6 +173,7 @@ struct fib_result {
        unsigned char           type;
        unsigned char           scope;
        u32                     tclassid;
+       dscp_t                  dscp;
        struct fib_nh_common    *nhc;
        struct fib_info         *fi;
        struct fib_table        *table;
index f474106464d2f2a52fa6b7ecaf2146977d05eecc..8f30e3f00b7f27a7a719b0bfd13cd3b8c3b0a269 100644 (file)
@@ -1629,6 +1629,7 @@ set_result:
                        res->nhc = nhc;
                        res->type = fa->fa_type;
                        res->scope = fi->fib_scope;
+                       res->dscp = fa->fa_dscp;
                        res->fi = fi;
                        res->table = tb;
                        res->fa_head = &n->leaf;
index b3073d1c8f8f71c88dc525eefb2b03be8f1f2945..7790a834746180b88ad5bfd9bab4ad8570540210 100644 (file)
@@ -2868,9 +2868,9 @@ EXPORT_SYMBOL_GPL(ip_route_output_flow);
 
 /* called with rcu_read_lock held */
 static int rt_fill_info(struct net *net, __be32 dst, __be32 src,
-                       struct rtable *rt, u32 table_id, struct flowi4 *fl4,
-                       struct sk_buff *skb, u32 portid, u32 seq,
-                       unsigned int flags)
+                       struct rtable *rt, u32 table_id, dscp_t dscp,
+                       struct flowi4 *fl4, struct sk_buff *skb, u32 portid,
+                       u32 seq, unsigned int flags)
 {
        struct rtmsg *r;
        struct nlmsghdr *nlh;
@@ -2886,7 +2886,7 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src,
        r->rtm_family    = AF_INET;
        r->rtm_dst_len  = 32;
        r->rtm_src_len  = 0;
-       r->rtm_tos      = fl4 ? fl4->flowi4_tos : 0;
+       r->rtm_tos      = inet_dscp_to_dsfield(dscp);
        r->rtm_table    = table_id < 256 ? table_id : RT_TABLE_COMPAT;
        if (nla_put_u32(skb, RTA_TABLE, table_id))
                goto nla_put_failure;
@@ -3036,7 +3036,7 @@ static int fnhe_dump_bucket(struct net *net, struct sk_buff *skb,
                                goto next;
 
                        err = rt_fill_info(net, fnhe->fnhe_daddr, 0, rt,
-                                          table_id, NULL, skb,
+                                          table_id, 0, NULL, skb,
                                           NETLINK_CB(cb->skb).portid,
                                           cb->nlh->nlmsg_seq, flags);
                        if (err)
@@ -3359,8 +3359,8 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
                err = fib_dump_info(skb, NETLINK_CB(in_skb).portid,
                                    nlh->nlmsg_seq, RTM_NEWROUTE, &fri, 0);
        } else {
-               err = rt_fill_info(net, dst, src, rt, table_id, &fl4, skb,
-                                  NETLINK_CB(in_skb).portid,
+               err = rt_fill_info(net, dst, src, rt, table_id, res.dscp, &fl4,
+                                  skb, NETLINK_CB(in_skb).portid,
                                   nlh->nlmsg_seq, 0);
        }
        if (err < 0)