]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: mscc: ocelot: validate netdev belongs to switch in .netdev_to_port()
authorDavid Yang <mmyangfl@gmail.com>
Sat, 6 Jun 2026 12:52:44 +0000 (20:52 +0800)
committerJakub Kicinski <kuba@kernel.org>
Wed, 10 Jun 2026 00:54:34 +0000 (17:54 -0700)
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 <mmyangfl@gmail.com>
Link: https://patch.msgid.link/20260606125247.305167-1-mmyangfl@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/dsa/ocelot/felix.c
drivers/net/dsa/ocelot/felix.h
drivers/net/ethernet/mscc/ocelot.h
drivers/net/ethernet/mscc/ocelot_flower.c
drivers/net/ethernet/mscc/ocelot_net.c
include/soc/mscc/ocelot.h

index 4272ea6e9ca84372afbf167bcbb167b73c97103a..84a95007825f75e5b8c767b1efb3b8463013f4ed 100644 (file)
@@ -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;
index a657b190c5d7b39b06dd0aa9a90e509dc33e49e1..19addcfd62bec3c0574df15f7334ff4843e98a89 100644 (file)
@@ -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
index e50be508c16633e79e2c44643647a55dc9fcac6c..42d2c456f71289c2668cb359c783525974938d39 100644 (file)
@@ -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);
index 844292eb74220c68008d4cb245f0fe0b4b6f7f4a..c5983c56a5440b54d4ac81cf18157b8462a7df80 100644 (file)
@@ -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");
index 1b82693204640d32abece97ade4710ad1a0c355d..4d45e136f08f5e7a9747220b73612ecfb4298325 100644 (file)
@@ -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;
 }
index 48d6deb3efd7151493e014c4fbbfa3358c78c29e..05a8191b148e93311558e6cf358c21c26702f551 100644 (file)
@@ -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);