Commit 4ca07b92 authored by William A. Kennington III's avatar William A. Kennington III Committed by Paolo Abeni
Browse files

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: f5b8abf9 ("mctp i2c: MCTP I2C binding driver")
Signed-off-by: default avatarWilliam A. Kennington III <william@wkennington.com>
Acked-by: default avatarJeremy Kerr <jk@codeconstruct.com.au>
Link: https://patch.msgid.link/20260423074741.201460-1-william@wkennington.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 0bb05e6a
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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);
+3 −1
Original line number Diff line number Diff line
@@ -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;
}