]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: mctp i2c: check length before marking flow active
authorWilliam A. Kennington III <william@wkennington.com>
Thu, 23 Apr 2026 07:46:52 +0000 (00:46 -0700)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 28 Apr 2026 11:11:53 +0000 (13:11 +0200)
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>
drivers/net/mctp/mctp-i2c.c
net/sched/cls_flower.c

index 15fe4d1163c1cd665ccd01c1f1f429d931564a61..ee2913758e54ed48b5e2bd4a9fa8263737f22784 100644 (file)
@@ -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);
index 88f8a32fab2b404c22bbdcf9320a2a409525027a..b9672ea05747702a3afefadf2e07428b24a19746 100644 (file)
@@ -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;
 }