diff options
| author | William A. Kennington III <william@wkennington.com> | 2026-04-23 00:46:52 -0700 |
|---|---|---|
| committer | Paolo Abeni <pabeni@redhat.com> | 2026-04-28 13:11:53 +0200 |
| commit | 4ca07b9239bd0478ae586632a2ed72be37ed8407 (patch) | |
| tree | 3c7827139d70c8e27aa954e2fbd697564cc522b0 /net | |
| parent | 0bb05e6adfa99a2ea1fee1125cc0953409f83ed8 (diff) | |
net: mctp i2c: check length before marking flow active
Currently, mctp_i2c_get_tx_flow_state() is called before the packet length
sanity check. This function marks a new flow as active in the MCTP core.
If the sanity check fails, mctp_i2c_xmit() returns early without calling
mctp_i2c_lock_nest(). This results in a mismatched locking state: the
flow is active, but the I2C bus lock was never acquired for it.
When the flow is later released, mctp_i2c_release_flow() will see the
active state and queue an unlock marker. The TX thread will then
decrement midev->i2c_lock_count from 0, causing it to underflow to -1.
This underflow permanently breaks the driver's locking logic, allowing
future transmissions to occur without holding the I2C bus lock, leading
to bus collisions and potential hardware hangs.
Move the mctp_i2c_get_tx_flow_state() call to after the length sanity
check to ensure we only transition the flow state if we are actually
going to proceed with the transmission and locking.
Fixes: f5b8abf9fc3d ("mctp i2c: MCTP I2C binding driver")
Signed-off-by: William A. Kennington III <william@wkennington.com>
Acked-by: Jeremy Kerr <jk@codeconstruct.com.au>
Link: https://patch.msgid.link/20260423074741.201460-1-william@wkennington.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Diffstat (limited to 'net')
| -rw-r--r-- | net/sched/cls_flower.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 88f8a32fab2b..b9672ea05747 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -556,6 +556,7 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, struct netlink_ext_ack *extack) { struct cls_fl_head *head = fl_head_dereference(tp); + struct fl_flow_mask *mask; *last = false; @@ -572,11 +573,12 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, list_del_rcu(&f->list); spin_unlock(&tp->lock); - *last = fl_mask_put(head, f->mask); + mask = f->mask; if (!tc_skip_hw(f->flags)) fl_hw_destroy_filter(tp, f, rtnl_held, extack); tcf_unbind_filter(tp, &f->res); __fl_put(f); + *last = fl_mask_put(head, mask); return 0; } |
