* [PATCHv3 net 1/3] hsr: use rtnl lock when iterating over ports
2025-09-05 9:15 [PATCHv3 net 0/3] hsr: fix lock warnings Hangbin Liu
@ 2025-09-05 9:15 ` Hangbin Liu
2025-09-10 17:06 ` Simon Horman
2025-09-05 9:15 ` [PATCHv3 net 2/3] hsr: use hsr_for_each_port_rtnl in hsr_port_get_hsr Hangbin Liu
` (2 subsequent siblings)
3 siblings, 1 reply; 8+ messages in thread
From: Hangbin Liu @ 2025-09-05 9:15 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, MD Danish Anwar, Alexander Lobakin,
Jaakko Karrenpalo, Fernando Fernandez Mancera, Murali Karicheri,
WingMan Kwok, Stanislav Fomichev, Xiao Liang, Kuniyuki Iwashima,
Johannes Berg, Hangbin Liu
hsr_for_each_port is called in many places without holding the RCU read
lock, this may trigger warnings on debug kernels. Most of the callers
are actually hold rtnl lock. So add a new helper hsr_for_each_port_rtnl
to allow callers in suitable contexts to iterate ports safely without
explicit RCU locking.
This patch only fixed the callers that is hold rtnl lock. Other caller
issues will be fixed in later patches.
Fixes: c5a759117210 ("net/hsr: Use list_head (and rcu) instead of array for slave devices.")
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
---
net/hsr/hsr_device.c | 18 +++++++++---------
net/hsr/hsr_main.c | 2 +-
net/hsr/hsr_main.h | 3 +++
3 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
index 88657255fec1..bce7b4061ce0 100644
--- a/net/hsr/hsr_device.c
+++ b/net/hsr/hsr_device.c
@@ -49,7 +49,7 @@ static bool hsr_check_carrier(struct hsr_port *master)
ASSERT_RTNL();
- hsr_for_each_port(master->hsr, port) {
+ hsr_for_each_port_rtnl(master->hsr, port) {
if (port->type != HSR_PT_MASTER && is_slave_up(port->dev)) {
netif_carrier_on(master->dev);
return true;
@@ -105,7 +105,7 @@ int hsr_get_max_mtu(struct hsr_priv *hsr)
struct hsr_port *port;
mtu_max = ETH_DATA_LEN;
- hsr_for_each_port(hsr, port)
+ hsr_for_each_port_rtnl(hsr, port)
if (port->type != HSR_PT_MASTER)
mtu_max = min(port->dev->mtu, mtu_max);
@@ -139,7 +139,7 @@ static int hsr_dev_open(struct net_device *dev)
hsr = netdev_priv(dev);
- hsr_for_each_port(hsr, port) {
+ hsr_for_each_port_rtnl(hsr, port) {
if (port->type == HSR_PT_MASTER)
continue;
switch (port->type) {
@@ -172,7 +172,7 @@ static int hsr_dev_close(struct net_device *dev)
struct hsr_priv *hsr;
hsr = netdev_priv(dev);
- hsr_for_each_port(hsr, port) {
+ hsr_for_each_port_rtnl(hsr, port) {
if (port->type == HSR_PT_MASTER)
continue;
switch (port->type) {
@@ -205,7 +205,7 @@ static netdev_features_t hsr_features_recompute(struct hsr_priv *hsr,
* may become enabled.
*/
features &= ~NETIF_F_ONE_FOR_ALL;
- hsr_for_each_port(hsr, port)
+ hsr_for_each_port_rtnl(hsr, port)
features = netdev_increment_features(features,
port->dev->features,
mask);
@@ -484,7 +484,7 @@ static void hsr_set_rx_mode(struct net_device *dev)
hsr = netdev_priv(dev);
- hsr_for_each_port(hsr, port) {
+ hsr_for_each_port_rtnl(hsr, port) {
if (port->type == HSR_PT_MASTER)
continue;
switch (port->type) {
@@ -506,7 +506,7 @@ static void hsr_change_rx_flags(struct net_device *dev, int change)
hsr = netdev_priv(dev);
- hsr_for_each_port(hsr, port) {
+ hsr_for_each_port_rtnl(hsr, port) {
if (port->type == HSR_PT_MASTER)
continue;
switch (port->type) {
@@ -534,7 +534,7 @@ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
hsr = netdev_priv(dev);
- hsr_for_each_port(hsr, port) {
+ hsr_for_each_port_rtnl(hsr, port) {
if (port->type == HSR_PT_MASTER ||
port->type == HSR_PT_INTERLINK)
continue;
@@ -580,7 +580,7 @@ static int hsr_ndo_vlan_rx_kill_vid(struct net_device *dev,
hsr = netdev_priv(dev);
- hsr_for_each_port(hsr, port) {
+ hsr_for_each_port_rtnl(hsr, port) {
switch (port->type) {
case HSR_PT_SLAVE_A:
case HSR_PT_SLAVE_B:
diff --git a/net/hsr/hsr_main.c b/net/hsr/hsr_main.c
index 192893c3f2ec..ac1eb1db1a52 100644
--- a/net/hsr/hsr_main.c
+++ b/net/hsr/hsr_main.c
@@ -22,7 +22,7 @@ static bool hsr_slave_empty(struct hsr_priv *hsr)
{
struct hsr_port *port;
- hsr_for_each_port(hsr, port)
+ hsr_for_each_port_rtnl(hsr, port)
if (port->type != HSR_PT_MASTER)
return false;
return true;
diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h
index 135ec5fce019..33b0d2460c9b 100644
--- a/net/hsr/hsr_main.h
+++ b/net/hsr/hsr_main.h
@@ -224,6 +224,9 @@ struct hsr_priv {
#define hsr_for_each_port(hsr, port) \
list_for_each_entry_rcu((port), &(hsr)->ports, port_list)
+#define hsr_for_each_port_rtnl(hsr, port) \
+ list_for_each_entry_rcu((port), &(hsr)->ports, port_list, lockdep_rtnl_is_held())
+
struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt);
/* Caller must ensure skb is a valid HSR frame */
--
2.50.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCHv3 net 1/3] hsr: use rtnl lock when iterating over ports
2025-09-05 9:15 ` [PATCHv3 net 1/3] hsr: use rtnl lock when iterating over ports Hangbin Liu
@ 2025-09-10 17:06 ` Simon Horman
0 siblings, 0 replies; 8+ messages in thread
From: Simon Horman @ 2025-09-10 17:06 UTC (permalink / raw)
To: Hangbin Liu
Cc: netdev, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, MD Danish Anwar, Alexander Lobakin,
Jaakko Karrenpalo, Fernando Fernandez Mancera, Murali Karicheri,
WingMan Kwok, Stanislav Fomichev, Xiao Liang, Kuniyuki Iwashima,
Johannes Berg
On Fri, Sep 05, 2025 at 09:15:31AM +0000, Hangbin Liu wrote:
> hsr_for_each_port is called in many places without holding the RCU read
> lock, this may trigger warnings on debug kernels. Most of the callers
> are actually hold rtnl lock. So add a new helper hsr_for_each_port_rtnl
> to allow callers in suitable contexts to iterate ports safely without
> explicit RCU locking.
>
> This patch only fixed the callers that is hold rtnl lock. Other caller
> issues will be fixed in later patches.
>
> Fixes: c5a759117210 ("net/hsr: Use list_head (and rcu) instead of array for slave devices.")
> Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
> ---
> net/hsr/hsr_device.c | 18 +++++++++---------
> net/hsr/hsr_main.c | 2 +-
> net/hsr/hsr_main.h | 3 +++
> 3 files changed, 13 insertions(+), 10 deletions(-)
Thanks,
I've done a once over all the callers of these functions
(which was quite a task) and I believe they all hold
either RTNL or rcu_read_lock.
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCHv3 net 2/3] hsr: use hsr_for_each_port_rtnl in hsr_port_get_hsr
2025-09-05 9:15 [PATCHv3 net 0/3] hsr: fix lock warnings Hangbin Liu
2025-09-05 9:15 ` [PATCHv3 net 1/3] hsr: use rtnl lock when iterating over ports Hangbin Liu
@ 2025-09-05 9:15 ` Hangbin Liu
2025-09-10 17:07 ` Simon Horman
2025-09-05 9:15 ` [PATCHv3 net 3/3] hsr: hold rcu and dev lock for hsr_get_port_ndev Hangbin Liu
2025-09-11 10:00 ` [PATCHv3 net 0/3] hsr: fix lock warnings patchwork-bot+netdevbpf
3 siblings, 1 reply; 8+ messages in thread
From: Hangbin Liu @ 2025-09-05 9:15 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, MD Danish Anwar, Alexander Lobakin,
Jaakko Karrenpalo, Fernando Fernandez Mancera, Murali Karicheri,
WingMan Kwok, Stanislav Fomichev, Xiao Liang, Kuniyuki Iwashima,
Johannes Berg, Hangbin Liu
hsr_port_get_hsr() iterates over ports using hsr_for_each_port(),
but many of its callers do not hold the required RCU lock.
Switch to hsr_for_each_port_rtnl(), since most callers already hold
the rtnl lock. After review, all callers are covered by either the rtnl
lock or the RCU lock, except hsr_dev_xmit(). Fix this by adding an
RCU read lock there.
Fixes: c5a759117210 ("net/hsr: Use list_head (and rcu) instead of array for slave devices.")
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
---
net/hsr/hsr_device.c | 3 +++
net/hsr/hsr_main.c | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
index bce7b4061ce0..702da1f9aaa9 100644
--- a/net/hsr/hsr_device.c
+++ b/net/hsr/hsr_device.c
@@ -226,6 +226,7 @@ static netdev_tx_t hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev)
struct hsr_priv *hsr = netdev_priv(dev);
struct hsr_port *master;
+ rcu_read_lock();
master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
if (master) {
skb->dev = master->dev;
@@ -238,6 +239,8 @@ static netdev_tx_t hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev)
dev_core_stats_tx_dropped_inc(dev);
dev_kfree_skb_any(skb);
}
+ rcu_read_unlock();
+
return NETDEV_TX_OK;
}
diff --git a/net/hsr/hsr_main.c b/net/hsr/hsr_main.c
index ac1eb1db1a52..bc94b07101d8 100644
--- a/net/hsr/hsr_main.c
+++ b/net/hsr/hsr_main.c
@@ -134,7 +134,7 @@ struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt)
{
struct hsr_port *port;
- hsr_for_each_port(hsr, port)
+ hsr_for_each_port_rtnl(hsr, port)
if (port->type == pt)
return port;
return NULL;
--
2.50.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCHv3 net 2/3] hsr: use hsr_for_each_port_rtnl in hsr_port_get_hsr
2025-09-05 9:15 ` [PATCHv3 net 2/3] hsr: use hsr_for_each_port_rtnl in hsr_port_get_hsr Hangbin Liu
@ 2025-09-10 17:07 ` Simon Horman
0 siblings, 0 replies; 8+ messages in thread
From: Simon Horman @ 2025-09-10 17:07 UTC (permalink / raw)
To: Hangbin Liu
Cc: netdev, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, MD Danish Anwar, Alexander Lobakin,
Jaakko Karrenpalo, Fernando Fernandez Mancera, Murali Karicheri,
WingMan Kwok, Stanislav Fomichev, Xiao Liang, Kuniyuki Iwashima,
Johannes Berg
On Fri, Sep 05, 2025 at 09:15:32AM +0000, Hangbin Liu wrote:
> hsr_port_get_hsr() iterates over ports using hsr_for_each_port(),
> but many of its callers do not hold the required RCU lock.
>
> Switch to hsr_for_each_port_rtnl(), since most callers already hold
> the rtnl lock. After review, all callers are covered by either the rtnl
> lock or the RCU lock, except hsr_dev_xmit(). Fix this by adding an
> RCU read lock there.
>
> Fixes: c5a759117210 ("net/hsr: Use list_head (and rcu) instead of array for slave devices.")
> Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
Thanks,
I agree with your analysis.
Reviewed-by: Simon Horman <horms@kernel.org>
...
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCHv3 net 3/3] hsr: hold rcu and dev lock for hsr_get_port_ndev
2025-09-05 9:15 [PATCHv3 net 0/3] hsr: fix lock warnings Hangbin Liu
2025-09-05 9:15 ` [PATCHv3 net 1/3] hsr: use rtnl lock when iterating over ports Hangbin Liu
2025-09-05 9:15 ` [PATCHv3 net 2/3] hsr: use hsr_for_each_port_rtnl in hsr_port_get_hsr Hangbin Liu
@ 2025-09-05 9:15 ` Hangbin Liu
2025-09-10 17:09 ` Simon Horman
2025-09-11 10:00 ` [PATCHv3 net 0/3] hsr: fix lock warnings patchwork-bot+netdevbpf
3 siblings, 1 reply; 8+ messages in thread
From: Hangbin Liu @ 2025-09-05 9:15 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, MD Danish Anwar, Alexander Lobakin,
Jaakko Karrenpalo, Fernando Fernandez Mancera, Murali Karicheri,
WingMan Kwok, Stanislav Fomichev, Xiao Liang, Kuniyuki Iwashima,
Johannes Berg, Hangbin Liu
hsr_get_port_ndev calls hsr_for_each_port, which need to hold rcu lock.
On the other hand, before return the port device, we need to hold the
device reference to avoid UaF in the caller function.
Suggested-by: Paolo Abeni <pabeni@redhat.com>
Fixes: 9c10dd8eed74 ("net: hsr: Create and export hsr_get_port_ndev()")
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
---
drivers/net/ethernet/ti/icssg/icssg_prueth.c | 20 ++++++++++++++------
net/hsr/hsr_device.c | 7 ++++++-
2 files changed, 20 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
index dadce6009791..e42d0fdefee1 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
@@ -654,7 +654,7 @@ static void icssg_prueth_hsr_fdb_add_del(struct prueth_emac *emac,
static int icssg_prueth_hsr_add_mcast(struct net_device *ndev, const u8 *addr)
{
- struct net_device *real_dev;
+ struct net_device *real_dev, *port_dev;
struct prueth_emac *emac;
u8 vlan_id, i;
@@ -663,11 +663,15 @@ static int icssg_prueth_hsr_add_mcast(struct net_device *ndev, const u8 *addr)
if (is_hsr_master(real_dev)) {
for (i = HSR_PT_SLAVE_A; i < HSR_PT_INTERLINK; i++) {
- emac = netdev_priv(hsr_get_port_ndev(real_dev, i));
- if (!emac)
+ port_dev = hsr_get_port_ndev(real_dev, i);
+ emac = netdev_priv(port_dev);
+ if (!emac) {
+ dev_put(port_dev);
return -EINVAL;
+ }
icssg_prueth_hsr_fdb_add_del(emac, addr, vlan_id,
true);
+ dev_put(port_dev);
}
} else {
emac = netdev_priv(real_dev);
@@ -679,7 +683,7 @@ static int icssg_prueth_hsr_add_mcast(struct net_device *ndev, const u8 *addr)
static int icssg_prueth_hsr_del_mcast(struct net_device *ndev, const u8 *addr)
{
- struct net_device *real_dev;
+ struct net_device *real_dev, *port_dev;
struct prueth_emac *emac;
u8 vlan_id, i;
@@ -688,11 +692,15 @@ static int icssg_prueth_hsr_del_mcast(struct net_device *ndev, const u8 *addr)
if (is_hsr_master(real_dev)) {
for (i = HSR_PT_SLAVE_A; i < HSR_PT_INTERLINK; i++) {
- emac = netdev_priv(hsr_get_port_ndev(real_dev, i));
- if (!emac)
+ port_dev = hsr_get_port_ndev(real_dev, i);
+ emac = netdev_priv(port_dev);
+ if (!emac) {
+ dev_put(port_dev);
return -EINVAL;
+ }
icssg_prueth_hsr_fdb_add_del(emac, addr, vlan_id,
false);
+ dev_put(port_dev);
}
} else {
emac = netdev_priv(real_dev);
diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
index 702da1f9aaa9..fbbc3ccf9df6 100644
--- a/net/hsr/hsr_device.c
+++ b/net/hsr/hsr_device.c
@@ -675,9 +675,14 @@ struct net_device *hsr_get_port_ndev(struct net_device *ndev,
struct hsr_priv *hsr = netdev_priv(ndev);
struct hsr_port *port;
+ rcu_read_lock();
hsr_for_each_port(hsr, port)
- if (port->type == pt)
+ if (port->type == pt) {
+ dev_hold(port->dev);
+ rcu_read_unlock();
return port->dev;
+ }
+ rcu_read_unlock();
return NULL;
}
EXPORT_SYMBOL(hsr_get_port_ndev);
--
2.50.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCHv3 net 3/3] hsr: hold rcu and dev lock for hsr_get_port_ndev
2025-09-05 9:15 ` [PATCHv3 net 3/3] hsr: hold rcu and dev lock for hsr_get_port_ndev Hangbin Liu
@ 2025-09-10 17:09 ` Simon Horman
0 siblings, 0 replies; 8+ messages in thread
From: Simon Horman @ 2025-09-10 17:09 UTC (permalink / raw)
To: Hangbin Liu
Cc: netdev, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, MD Danish Anwar, Alexander Lobakin,
Jaakko Karrenpalo, Fernando Fernandez Mancera, Murali Karicheri,
WingMan Kwok, Stanislav Fomichev, Xiao Liang, Kuniyuki Iwashima,
Johannes Berg
On Fri, Sep 05, 2025 at 09:15:33AM +0000, Hangbin Liu wrote:
> hsr_get_port_ndev calls hsr_for_each_port, which need to hold rcu lock.
> On the other hand, before return the port device, we need to hold the
> device reference to avoid UaF in the caller function.
>
> Suggested-by: Paolo Abeni <pabeni@redhat.com>
> Fixes: 9c10dd8eed74 ("net: hsr: Create and export hsr_get_port_ndev()")
> Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
Thanks.
I agree with your analysis.
And I see that this addresses Paolo's review over v2.
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCHv3 net 0/3] hsr: fix lock warnings
2025-09-05 9:15 [PATCHv3 net 0/3] hsr: fix lock warnings Hangbin Liu
` (2 preceding siblings ...)
2025-09-05 9:15 ` [PATCHv3 net 3/3] hsr: hold rcu and dev lock for hsr_get_port_ndev Hangbin Liu
@ 2025-09-11 10:00 ` patchwork-bot+netdevbpf
3 siblings, 0 replies; 8+ messages in thread
From: patchwork-bot+netdevbpf @ 2025-09-11 10:00 UTC (permalink / raw)
To: Hangbin Liu
Cc: netdev, davem, edumazet, kuba, pabeni, horms, danishanwar,
aleksander.lobakin, jkarrenpalo, ffmancera, m-karicheri2, w-kwok2,
sdf, shaw.leon, kuniyu, johannes.berg
Hello:
This series was applied to netdev/net.git (main)
by Paolo Abeni <pabeni@redhat.com>:
On Fri, 5 Sep 2025 09:15:30 +0000 you wrote:
> hsr_for_each_port is called in many places without holding the RCU read
> lock, this may trigger warnings on debug kernels like:
>
> [ 40.457015] [ T201] WARNING: suspicious RCU usage
> [ 40.457020] [ T201] 6.17.0-rc2-virtme #1 Not tainted
> [ 40.457025] [ T201] -----------------------------
> [ 40.457029] [ T201] net/hsr/hsr_main.c:137 RCU-list traversed in non-reader section!!
> [ 40.457036] [ T201]
> other info that might help us debug this:
>
> [...]
Here is the summary with links:
- [PATCHv3,net,1/3] hsr: use rtnl lock when iterating over ports
https://git.kernel.org/netdev/net/c/8884c6939913
- [PATCHv3,net,2/3] hsr: use hsr_for_each_port_rtnl in hsr_port_get_hsr
https://git.kernel.org/netdev/net/c/393c841fe433
- [PATCHv3,net,3/3] hsr: hold rcu and dev lock for hsr_get_port_ndev
https://git.kernel.org/netdev/net/c/847748fc66d0
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 8+ messages in thread