mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-05-05 09:57:21 +02:00
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: f5b8abf9fc ("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>
This commit is contained in:
committed by
Paolo Abeni
parent
0bb05e6adf
commit
4ca07b9239
@@ -496,8 +496,6 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)
|
||||
u8 *pecp;
|
||||
int rc;
|
||||
|
||||
fs = mctp_i2c_get_tx_flow_state(midev, skb);
|
||||
|
||||
hdr = (void *)skb_mac_header(skb);
|
||||
/* Sanity check that packet contents matches skb length,
|
||||
* and can't exceed MCTP_I2C_BUFSZ
|
||||
@@ -509,6 +507,8 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)
|
||||
return;
|
||||
}
|
||||
|
||||
fs = mctp_i2c_get_tx_flow_state(midev, skb);
|
||||
|
||||
if (skb_tailroom(skb) >= 1) {
|
||||
/* Linear case with space, we can just append the PEC */
|
||||
skb_put(skb, 1);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user