From e3624f5eeac40e2f95e54e5ed684222438d56e23 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 18 Sep 2026 11:53:25 -0700 Subject: [PATCH 1/2] net: dsa: mv88e6xxx: check the port when reading back a policy rule chip->policies is one IDR for the whole switch, so the location an ETHTOOL_GRXCLSRULE caller supplies can name a rule belonging to any port. mv88e6xxx_get_rxnfc() copies it out without looking at policy->port, which lets a user on one user port read the MAC address and VID of a policy an admin installed on another. ETHTOOL_GRXCLSRULE needs no CAP_NET_ADMIN. The GRXCLSRLCNT and GRXCLSRLALL arms of the same switch statement already filter on policy->port, which makes the GRXCLSRULE omission look unintentional. Nonetheless, changing this does carry some regression risk. Signed-off-by: Jakub Kicinski Link: https://patch.msgid.link/20260918185326.3940857-2-kuba@kernel.org Signed-off-by: Paolo Abeni --- drivers/net/dsa/mv88e6xxx/chip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 8cf5681f5806..461167199a71 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2457,7 +2457,7 @@ static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port, case ETHTOOL_GRXCLSRULE: err = -ENOENT; policy = idr_find(&chip->policies, fs->location); - if (policy) { + if (policy && policy->port == port) { memcpy(fs, &policy->fs, sizeof(*fs)); err = 0; } From 242ebf4c51148d5202b9c57841082c44c4284082 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 18 Sep 2026 11:53:26 -0700 Subject: [PATCH 2/2] net: dsa: mv88e6xxx: check the port when deleting a policy rule ETHTOOL_SRXCLSRLDEL removes the policy the location names out of the switch-wide IDR without checking which port owns it, then hands it to mv88e6xxx_policy_apply() along with the port the request arrived on. Deleting another port's rule therefore purges an ATU entry on and clears the policy register of the requesting port, while the owning port keeps its hardware policy - and, with the software object freed, no longer has a location that can be used to remove it. Initially I thought that we're just able to delete a rule from one port using another port as a handle. But if the reading of the code outlined above is correct, this is just broken, not a "feature" someone could depend on. Signed-off-by: Jakub Kicinski Link: https://patch.msgid.link/20260918185326.3940857-3-kuba@kernel.org Signed-off-by: Paolo Abeni --- drivers/net/dsa/mv88e6xxx/chip.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 461167199a71..70411d147677 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2503,8 +2503,9 @@ static int mv88e6xxx_set_rxnfc(struct dsa_switch *ds, int port, break; case ETHTOOL_SRXCLSRLDEL: err = -ENOENT; - policy = idr_remove(&chip->policies, fs->location); - if (policy) { + policy = idr_find(&chip->policies, fs->location); + if (policy && policy->port == port) { + idr_remove(&chip->policies, fs->location); policy->action = MV88E6XXX_POLICY_ACTION_NORMAL; err = mv88e6xxx_policy_apply(chip, port, policy); devm_kfree(chip->dev, policy);