From: David Yang Date: Sat, 6 Jun 2026 12:52:44 +0000 (+0800) Subject: net: mscc: ocelot: validate netdev belongs to switch in .netdev_to_port() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ea07514700f7a5125db67c9d1cbfb06e65c30a07;p=thirdparty%2Flinux.git net: mscc: ocelot: validate netdev belongs to switch in .netdev_to_port() The .netdev_to_port() currently takes only a net_device and returns the port index, without verifying the netdev actually belongs to the switch being operated on. This can cause flower rule parsing to silently resolve to a wrong port on the local hardware. Update both implementations felix_netdev_to_port() and ocelot_netdev_to_port() to validate ownership. Also update the callers in ocelot_flower.c to pass through the ocelot context. Signed-off-by: David Yang Link: https://patch.msgid.link/20260606125247.305167-1-mmyangfl@gmail.com Signed-off-by: Jakub Kicinski --- diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 4272ea6e9ca84..84a95007825f7 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -2446,12 +2446,14 @@ struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port) } EXPORT_SYMBOL_GPL(felix_port_to_netdev); -int felix_netdev_to_port(struct net_device *dev) +int felix_netdev_to_port(struct ocelot *ocelot, struct net_device *dev) { + struct felix *felix = ocelot_to_felix(ocelot); + struct dsa_switch *ds = felix->ds; struct dsa_port *dp; dp = dsa_port_from_netdev(dev); - if (IS_ERR(dp)) + if (IS_ERR(dp) || dp->ds != ds) return -EINVAL; return dp->index; diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h index a657b190c5d7b..19addcfd62bec 100644 --- a/drivers/net/dsa/ocelot/felix.h +++ b/drivers/net/dsa/ocelot/felix.h @@ -104,6 +104,6 @@ int felix_register_switch(struct device *dev, resource_size_t switch_base, enum dsa_tag_protocol init_tag_proto, const struct felix_info *info); struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port); -int felix_netdev_to_port(struct net_device *dev); +int felix_netdev_to_port(struct ocelot *ocelot, struct net_device *dev); #endif diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index e50be508c1663..42d2c456f7128 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -92,7 +92,7 @@ int ocelot_mact_learn(struct ocelot *ocelot, int port, int ocelot_mact_forget(struct ocelot *ocelot, const unsigned char mac[ETH_ALEN], unsigned int vid); struct net_device *ocelot_port_to_netdev(struct ocelot *ocelot, int port); -int ocelot_netdev_to_port(struct net_device *dev); +int ocelot_netdev_to_port(struct ocelot *ocelot, struct net_device *dev); int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target, struct device_node *portnp); diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c index 844292eb74220..c5983c56a5440 100644 --- a/drivers/net/ethernet/mscc/ocelot_flower.c +++ b/drivers/net/ethernet/mscc/ocelot_flower.c @@ -233,8 +233,8 @@ ocelot_flower_parse_egress_port(struct ocelot *ocelot, struct flow_cls_offload * const struct flow_action_entry *a, bool mirror, struct netlink_ext_ack *extack) { + int egress_port = ocelot->ops->netdev_to_port(ocelot, a->dev); const char *act_string = mirror ? "mirror" : "redirect"; - int egress_port = ocelot->ops->netdev_to_port(a->dev); enum flow_action_id offloadable_act_id; offloadable_act_id = mirror ? FLOW_ACTION_MIRRED : FLOW_ACTION_REDIRECT; @@ -580,7 +580,7 @@ static int ocelot_flower_parse_indev(struct ocelot *ocelot, int port, return -ENOENT; } - ingress_port = ocelot->ops->netdev_to_port(indev); + ingress_port = ocelot->ops->netdev_to_port(ocelot, indev); if (ingress_port < 0) { NL_SET_ERR_MSG_MOD(extack, "Can only offload an ocelot ingress port"); diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c index 1b82693204640..4d45e136f08f5 100644 --- a/drivers/net/ethernet/mscc/ocelot_net.c +++ b/drivers/net/ethernet/mscc/ocelot_net.c @@ -984,7 +984,7 @@ static bool ocelot_netdevice_dev_check(const struct net_device *dev) return dev->netdev_ops == &ocelot_port_netdev_ops; } -int ocelot_netdev_to_port(struct net_device *dev) +int ocelot_netdev_to_port(struct ocelot *ocelot, struct net_device *dev) { struct ocelot_port_private *priv; @@ -992,6 +992,8 @@ int ocelot_netdev_to_port(struct net_device *dev) return -EINVAL; priv = netdev_priv(dev); + if (priv->port.ocelot != ocelot) + return -EINVAL; return priv->port.index; } diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index 48d6deb3efd71..05a8191b148e9 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -650,7 +650,7 @@ struct device_node; struct ocelot_ops { struct net_device *(*port_to_netdev)(struct ocelot *ocelot, int port); - int (*netdev_to_port)(struct net_device *dev); + int (*netdev_to_port)(struct ocelot *ocelot, struct net_device *dev); int (*reset)(struct ocelot *ocelot); u16 (*wm_enc)(u16 value); u16 (*wm_dec)(u16 value);