• Vladimir Oltean's avatar
    net: dsa: fix db type confusion in host fdb/mdb add/del · eb1ab765
    Vladimir Oltean authored
    We have the following code paths:
    
    Host FDB (unicast RX filtering):
    
    dsa_port_standalone_host_fdb_add()   dsa_port_bridge_host_fdb_add()
                   |                                     |
                   +--------------+         +------------+
                                  |         |
                                  v         v
                             dsa_port_host_fdb_add()
    
    dsa_port_standalone_host_fdb_del()   dsa_port_bridge_host_fdb_del()
                   |                                     |
                   +--------------+         +------------+
                                  |         |
                                  v         v
                             dsa_port_host_fdb_del()
    
    Host MDB (multicast RX filtering):
    
    dsa_port_standalone_host_mdb_add()   dsa_port_bridge_host_mdb_add()
                   |                                     |
                   +--------------+         +------------+
                                  |         |
                                  v         v
                             dsa_port_host_mdb_add()
    
    dsa_port_standalone_host_mdb_del()   dsa_port_bridge_host_mdb_del()
                   |                                     |
                   +--------------+         +------------+
                                  |         |
                                  v         v
                             dsa_port_host_mdb_del()
    
    The logic added by commit 5e8a1e03 ("net: dsa: install secondary
    unicast and multicast addresses as host FDB/MDB") zeroes out
    db.bridge.num if the switch doesn't support ds->fdb_isolation
    (the majority doesn't). This is done for a reason explained in commit
    c2693363 ("net: dsa: request drivers to perform FDB isolation").
    
    Taking a single code path as example - dsa_port_host_fdb_add() - the
    others are similar - the problem is that this function handles:
    - DSA_DB_PORT databases, when called from
      dsa_port_standalone_host_fdb_add()
    - DSA_DB_BRIDGE databases, when called from
      dsa_port_bridge_host_fdb_add()
    
    So, if dsa_port_host_fdb_add() were to make any change on the
    "bridge.num" attribute of the database, this would only be correct for a
    DSA_DB_BRIDGE, and a type confusion for a DSA_DB_PORT bridge.
    
    However, this bug is without consequences, for 2 reasons:
    
    - dsa_port_standalone_host_fdb_add() is only called from code which is
      (in)directly guarded by dsa_switch_supports_uc_filtering(ds), and that
      function only returns true if ds->fdb_isolation is set. So, the code
      only executed for DSA_DB_BRIDGE databases.
    
    - Even if the code was not dead for DSA_DB_PORT, we have the following
      memory layout:
    
    struct dsa_bridge {
    	struct net_device *dev;
    	unsigned int num;
    	bool tx_fwd_offload;
    	refcount_t refcount;
    };
    
    struct dsa_db {
    	enum dsa_db_type type;
    
    	union {
    		const struct dsa_port *dp; // DSA_DB_PORT
    		struct dsa_lag lag;
    		struct dsa_bridge bridge; // DSA_DB_BRIDGE
    	};
    };
    
    So, the zeroization of dsa_db :: bridge :: num on a dsa_db structure of
    type DSA_DB_PORT would access memory which is unused, because we only
    use dsa_db :: dp for DSA_DB_PORT, and this is mapped at the same address
    with dsa_db :: dev for DSA_DB_BRIDGE, thanks to the union definition.
    
    It is correct to fix up dsa_db :: bridge :: num only from code paths
    that come from the bridge / switchdev, so move these there.
    Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
    Reviewed-by: default avatarSimon Horman <simon.horman@corigine.com>
    Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
    Link: https://lore.kernel.org/r/20230329133819.697642-1-vladimir.oltean@nxp.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
    eb1ab765
port.c 49.9 KB