Skip to content

Commit be19356

Browse files
committed
Merge branch 'net-hsr-fixes-for-prp-duplication-and-vlan-unwind'
Luka Gejak says: ==================== net: hsr: fixes for PRP duplication and VLAN unwind This series addresses two logic bugs in the HSR/PRP implementation identified during a protocol audit. These are targeted for the 'net' tree as they fix potential memory corruption and state inconsistency. The primary change resolves a race condition in the node merging path by implementing address-based lock ordering. This ensures that concurrent mutations of sequence blocks do not lead to state corruption or deadlocks. An additional fix corrects asymmetric VLAN error unwinding by implementing a centralized unwind path on slave errors. ==================== Link: https://patch.msgid.link/20260401092243.52121-1-luka.gejak@linux.dev Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents b18c833 + 2e3514e commit be19356

2 files changed

Lines changed: 53 additions & 17 deletions

File tree

net/hsr/hsr_device.c

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -532,8 +532,8 @@ static void hsr_change_rx_flags(struct net_device *dev, int change)
532532
static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
533533
__be16 proto, u16 vid)
534534
{
535-
bool is_slave_a_added = false;
536-
bool is_slave_b_added = false;
535+
struct net_device *slave_a_dev = NULL;
536+
struct net_device *slave_b_dev = NULL;
537537
struct hsr_port *port;
538538
struct hsr_priv *hsr;
539539
int ret = 0;
@@ -549,33 +549,35 @@ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
549549
switch (port->type) {
550550
case HSR_PT_SLAVE_A:
551551
if (ret) {
552-
/* clean up Slave-B */
553552
netdev_err(dev, "add vid failed for Slave-A\n");
554-
if (is_slave_b_added)
555-
vlan_vid_del(port->dev, proto, vid);
556-
return ret;
553+
goto unwind;
557554
}
558-
559-
is_slave_a_added = true;
555+
slave_a_dev = port->dev;
560556
break;
561-
562557
case HSR_PT_SLAVE_B:
563558
if (ret) {
564-
/* clean up Slave-A */
565559
netdev_err(dev, "add vid failed for Slave-B\n");
566-
if (is_slave_a_added)
567-
vlan_vid_del(port->dev, proto, vid);
568-
return ret;
560+
goto unwind;
569561
}
570-
571-
is_slave_b_added = true;
562+
slave_b_dev = port->dev;
572563
break;
573564
default:
565+
if (ret)
566+
goto unwind;
574567
break;
575568
}
576569
}
577570

578571
return 0;
572+
573+
unwind:
574+
if (slave_a_dev)
575+
vlan_vid_del(slave_a_dev, proto, vid);
576+
577+
if (slave_b_dev)
578+
vlan_vid_del(slave_b_dev, proto, vid);
579+
580+
return ret;
579581
}
580582

581583
static int hsr_ndo_vlan_rx_kill_vid(struct net_device *dev,

net/hsr/hsr_framereg.c

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,40 @@ static void hsr_free_node_rcu(struct rcu_head *rn)
123123
hsr_free_node(node);
124124
}
125125

126+
static void hsr_lock_seq_out_pair(struct hsr_node *node_a,
127+
struct hsr_node *node_b)
128+
{
129+
if (node_a == node_b) {
130+
spin_lock_bh(&node_a->seq_out_lock);
131+
return;
132+
}
133+
134+
if (node_a < node_b) {
135+
spin_lock_bh(&node_a->seq_out_lock);
136+
spin_lock_nested(&node_b->seq_out_lock, SINGLE_DEPTH_NESTING);
137+
} else {
138+
spin_lock_bh(&node_b->seq_out_lock);
139+
spin_lock_nested(&node_a->seq_out_lock, SINGLE_DEPTH_NESTING);
140+
}
141+
}
142+
143+
static void hsr_unlock_seq_out_pair(struct hsr_node *node_a,
144+
struct hsr_node *node_b)
145+
{
146+
if (node_a == node_b) {
147+
spin_unlock_bh(&node_a->seq_out_lock);
148+
return;
149+
}
150+
151+
if (node_a < node_b) {
152+
spin_unlock(&node_b->seq_out_lock);
153+
spin_unlock_bh(&node_a->seq_out_lock);
154+
} else {
155+
spin_unlock(&node_a->seq_out_lock);
156+
spin_unlock_bh(&node_b->seq_out_lock);
157+
}
158+
}
159+
126160
void hsr_del_nodes(struct list_head *node_db)
127161
{
128162
struct hsr_node *node;
@@ -432,7 +466,7 @@ void hsr_handle_sup_frame(struct hsr_frame_info *frame)
432466
}
433467

434468
ether_addr_copy(node_real->macaddress_B, ethhdr->h_source);
435-
spin_lock_bh(&node_real->seq_out_lock);
469+
hsr_lock_seq_out_pair(node_real, node_curr);
436470
for (i = 0; i < HSR_PT_PORTS; i++) {
437471
if (!node_curr->time_in_stale[i] &&
438472
time_after(node_curr->time_in[i], node_real->time_in[i])) {
@@ -455,7 +489,7 @@ void hsr_handle_sup_frame(struct hsr_frame_info *frame)
455489
src_blk->seq_nrs[i], HSR_SEQ_BLOCK_SIZE);
456490
}
457491
}
458-
spin_unlock_bh(&node_real->seq_out_lock);
492+
hsr_unlock_seq_out_pair(node_real, node_curr);
459493
node_real->addr_B_port = port_rcv->type;
460494

461495
spin_lock_bh(&hsr->list_lock);

0 commit comments

Comments
 (0)