From: James Raphael Tiovalen Date: Sun, 5 Jul 2026 11:36:29 +0000 (+0800) Subject: macsec: fix promiscuity refcount leak in macsec_dev_open() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7410d11460eb90d6c9281162ccc6a128534d897d;p=thirdparty%2Fkernel%2Flinux.git macsec: fix promiscuity refcount leak in macsec_dev_open() When a MACsec interface with IFF_PROMISC set is brought up on top of a device that has hardware offload enabled, macsec_dev_open() first calls dev_set_promiscuity(real_dev, 1) and then propagates the open to the offload device. If that propagation fails, the error path jumps to the clear_allmulti label, which only reverts allmulti and the unicast address. The promiscuity taken on the lower device is never dropped, so real_dev is left permanently stuck in promiscuous mode. Its promiscuity count can no longer be balanced from software. Add a clear_promisc label that drops the promiscuity reference and route the two offload failure paths to it. The dev_set_promiscuity() failure itself still jumps to clear_allmulti, since on that failure the count was not incremented. Fixes: 3cf3227a21d1 ("net: macsec: hardware offloading infrastructure") Cc: stable@vger.kernel.org Signed-off-by: James Raphael Tiovalen Reviewed-by: Sabrina Dubroca Link: https://patch.msgid.link/20260705113629.187490-1-jamestiotio@gmail.com Signed-off-by: Paolo Abeni --- diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index dd89282f0179..ee0e2eb7dbc6 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -3615,19 +3615,22 @@ static int macsec_dev_open(struct net_device *dev) ops = macsec_get_ops(netdev_priv(dev), &ctx); if (!ops) { err = -EOPNOTSUPP; - goto clear_allmulti; + goto clear_promisc; } ctx.secy = &macsec->secy; err = macsec_offload(ops->mdo_dev_open, &ctx); if (err) - goto clear_allmulti; + goto clear_promisc; } if (netif_carrier_ok(real_dev)) netif_carrier_on(dev); return 0; +clear_promisc: + if (dev->flags & IFF_PROMISC) + dev_set_promiscuity(real_dev, -1); clear_allmulti: if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(real_dev, -1);