VXLAN_VNIFILTER_ENTRY_START and VXLAN_VNIFILTER_ENTRY_END are bare
NLA_U32, so neither is bounded before vxlan_process_vni_filter() hands
them to vxlan_vni_add_del():

        int v, err = 0;
        ...
        for (v = start_vni; v <= end_vni; v++)

v is int and end_vni is __u32, so the comparison is done unsigned. A
request carrying only START=0xffffffff has vni_start == vni_end ==
0xffffffff and looks like a single VNI; v is then -1, the comparison
promotes it to 0xffffffff and passes, v++ makes v 0, and the loop walks
the space upwards from there, creating a VNI node and a per-CPU stats
block per iteration under rtnl_lock. Any range ending at 0xffffffff
behaves the same way.

Separately, a VNI at or above VXLAN_N_VID is accepted and stored even
though the VXLAN header carries only 24 bits: vxlan_vni_field() shifts
without masking, so such an entry keeps its own rhashtable slot while
being truncated on the wire.

Range-validate both attributes against the 24-bit space, as vxlan_mdb.c
already does for its own VNI attributes. With the nest now linked to
this policy, an out-of-range endpoint is rejected during netlink policy
validation, before vxlan_process_vni_filter() runs and before anything
is allocated. How many VNIs a single in-range request may span is a
separate question, bounded by the next patch; that limit is not a policy
check and does run in the handler.

Make the loop counter u32 as well. With the range bounded it is no
longer what keeps the loop finite, but it drops the undefined signed
overflow past INT_MAX and matches the u32 vni that vxlan_vni_add() and
vxlan_vni_del() already take.

Assisted-by: LLM
Signed-off-by: Ali Firas <[email protected]>
---

Notes:
    v3: was 1/5. No code change; the changelog now says the out-of-range 
rejection lands at policy validation, which holds for a multi-entry message 
once patch 1 links the nest.

 drivers/net/vxlan/vxlan_vnifilter.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/net/vxlan/vxlan_vnifilter.c 
b/drivers/net/vxlan/vxlan_vnifilter.c
index d391ec579661..9cffaf4998a9 100644
--- a/drivers/net/vxlan/vxlan_vnifilter.c
+++ b/drivers/net/vxlan/vxlan_vnifilter.c
@@ -459,9 +459,15 @@ static int vxlan_vnifilter_dump(struct sk_buff *skb, 
struct netlink_callback *cb
        return err;
 }
 
+static const struct netlink_range_validation vni_filter_vni_range = {
+       .max = VXLAN_N_VID - 1,
+};
+
 static const struct nla_policy 
vni_filter_entry_policy[VXLAN_VNIFILTER_ENTRY_MAX + 1] = {
-       [VXLAN_VNIFILTER_ENTRY_START] = { .type = NLA_U32 },
-       [VXLAN_VNIFILTER_ENTRY_END] = { .type = NLA_U32 },
+       [VXLAN_VNIFILTER_ENTRY_START] = NLA_POLICY_FULL_RANGE(NLA_U32,
+                                                             
&vni_filter_vni_range),
+       [VXLAN_VNIFILTER_ENTRY_END] = NLA_POLICY_FULL_RANGE(NLA_U32,
+                                                           
&vni_filter_vni_range),
        [VXLAN_VNIFILTER_ENTRY_GROUP]   = 
NLA_POLICY_EXACT_LEN(sizeof_field(struct iphdr, daddr)),
        [VXLAN_VNIFILTER_ENTRY_GROUP6]  = NLA_POLICY_EXACT_LEN(sizeof(struct 
in6_addr)),
 };
@@ -814,7 +820,8 @@ static int vxlan_vni_add_del(struct vxlan_dev *vxlan, __u32 
start_vni,
                             int cmd, struct netlink_ext_ack *extack)
 {
        struct vxlan_vni_group *vg;
-       int v, err = 0;
+       int err = 0;
+       u32 v;
 
        vg = rtnl_dereference(vxlan->vnigrp);
 
-- 
2.53.0


Reply via email to