summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2026-09-02 20:26:10 -0700
committerJakub Kicinski <kuba@kernel.org>2026-09-04 15:19:57 -0700
commitb1fffc273112e7284c5b705e186b43b5770cd3d5 (patch)
tree6e6c3173dc4bf3cef280c1c806e083a0a7cd8aa9
parent108bb2142e3a12c9ad625ad662973127a113ddc6 (diff)
downloadlinux-next-b1fffc273112e7284c5b705e186b43b5770cd3d5.tar.gz
linux-next-b1fffc273112e7284c5b705e186b43b5770cd3d5.zip
net: dsa: mv88e6xxx: bound the policy rule dump by the caller's buffer size
mv88e6xxx_get_rxnfc() uses rxnfc->rule_cnt as the write index while dumping the policy IDR, clobbering the input value before it has been looked at. That input is the number of entries the caller had room for. ETHTOOL_GRXCLSRLALL requires no CAP_NET_ADMIN and the ioctl sizes the buffer from the rule_cnt userspace passes in, so once an admin has installed policy rules any user can ask for fewer slots than there are rules and run off the end of the allocation. A rule_cnt of 0 leaves the buffer pointer NULL and the walk dereferences it. Count into a local so the caller's limit survives the walk, and stop with -EMSGSIZE once it is reached. Fixes: da7dc8755304 ("net: dsa: mv88e6xxx: add RXNFC support") Reviewed-by: Joe Damato <joe@dama.to> Link: https://patch.msgid.link/20260903032611.3000029-5-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 80b877c74513..7f68a0c55802 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2438,6 +2438,7 @@ static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port,
struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
struct mv88e6xxx_chip *chip = ds->priv;
struct mv88e6xxx_policy *policy;
+ u32 cnt = 0;
int err;
int id;
@@ -2463,11 +2464,18 @@ static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port,
break;
case ETHTOOL_GRXCLSRLALL:
rxnfc->data = 0;
- rxnfc->rule_cnt = 0;
- idr_for_each_entry(&chip->policies, policy, id)
- if (policy->port == port)
- rule_locs[rxnfc->rule_cnt++] = id;
err = 0;
+ idr_for_each_entry(&chip->policies, policy, id) {
+ if (policy->port != port)
+ continue;
+ if (cnt == rxnfc->rule_cnt) {
+ err = -EMSGSIZE;
+ break;
+ }
+ rule_locs[cnt++] = id;
+ }
+ if (!err)
+ rxnfc->rule_cnt = cnt;
break;
default:
err = -EOPNOTSUPP;