mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +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:
parent
0bb05e6adf
commit
4ca07b9239
|
|
@ -496,8 +496,6 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)
|
||||||
u8 *pecp;
|
u8 *pecp;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
fs = mctp_i2c_get_tx_flow_state(midev, skb);
|
|
||||||
|
|
||||||
hdr = (void *)skb_mac_header(skb);
|
hdr = (void *)skb_mac_header(skb);
|
||||||
/* Sanity check that packet contents matches skb length,
|
/* Sanity check that packet contents matches skb length,
|
||||||
* and can't exceed MCTP_I2C_BUFSZ
|
* 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fs = mctp_i2c_get_tx_flow_state(midev, skb);
|
||||||
|
|
||||||
if (skb_tailroom(skb) >= 1) {
|
if (skb_tailroom(skb) >= 1) {
|
||||||
/* Linear case with space, we can just append the PEC */
|
/* Linear case with space, we can just append the PEC */
|
||||||
skb_put(skb, 1);
|
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 netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
struct cls_fl_head *head = fl_head_dereference(tp);
|
struct cls_fl_head *head = fl_head_dereference(tp);
|
||||||
|
struct fl_flow_mask *mask;
|
||||||
|
|
||||||
*last = false;
|
*last = false;
|
||||||
|
|
||||||
|
|
@ -572,11 +573,12 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
|
||||||
list_del_rcu(&f->list);
|
list_del_rcu(&f->list);
|
||||||
spin_unlock(&tp->lock);
|
spin_unlock(&tp->lock);
|
||||||
|
|
||||||
*last = fl_mask_put(head, f->mask);
|
mask = f->mask;
|
||||||
if (!tc_skip_hw(f->flags))
|
if (!tc_skip_hw(f->flags))
|
||||||
fl_hw_destroy_filter(tp, f, rtnl_held, extack);
|
fl_hw_destroy_filter(tp, f, rtnl_held, extack);
|
||||||
tcf_unbind_filter(tp, &f->res);
|
tcf_unbind_filter(tp, &f->res);
|
||||||
__fl_put(f);
|
__fl_put(f);
|
||||||
|
*last = fl_mask_put(head, mask);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user