]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
thunderbolt: Validate XDomain request packet size before type cast
authorMichael Bommarito <michael.bommarito@gmail.com>
Mon, 25 May 2026 09:28:28 +0000 (05:28 -0400)
committerMika Westerberg <mika.westerberg@linux.intel.com>
Tue, 26 May 2026 13:18:29 +0000 (15:18 +0200)
tb_xdp_handle_request() casts the received packet buffer to
protocol-specific structs without verifying that the allocation
is large enough for the target type.  A peer can send a minimal
XDomain packet that passes the generic header length check but is
shorter than the struct accessed after the cast, causing out-of-
bounds reads from the kmemdup allocation.

Plumb the packet length through xdomain_request_work and validate
it against the expected struct size before each cast.

Fixes: 8e1de7042596 ("thunderbolt: Add support for XDomain lane bonding")
Fixes: cdae7c07e3e3 ("thunderbolt: Add support for XDomain properties")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
drivers/thunderbolt/xdomain.c

index 4099419c747952e1f29bdc7073ee625c3c8f90fb..9d54e3ccc827899da43a4a395851feb76316187d 100644 (file)
@@ -55,6 +55,7 @@ static const char * const state_names[] = {
 struct xdomain_request_work {
        struct work_struct work;
        struct tb_xdp_header *pkg;
+       size_t pkg_len;
        struct tb *tb;
 };
 
@@ -733,6 +734,7 @@ static void tb_xdp_handle_request(struct work_struct *work)
        struct xdomain_request_work *xw = container_of(work, typeof(*xw), work);
        const struct tb_xdp_header *pkg = xw->pkg;
        const struct tb_xdomain_header *xhdr = &pkg->xd_hdr;
+       size_t pkg_len = xw->pkg_len;
        struct tb *tb = xw->tb;
        struct tb_ctl *ctl = tb->ctl;
        struct tb_xdomain *xd;
@@ -764,7 +766,7 @@ static void tb_xdp_handle_request(struct work_struct *work)
        switch (pkg->type) {
        case PROPERTIES_REQUEST:
                tb_dbg(tb, "%llx: received XDomain properties request\n", route);
-               if (xd) {
+               if (xd && pkg_len >= sizeof(struct tb_xdp_properties)) {
                        ret = tb_xdp_properties_response(tb, ctl, xd, sequence,
                                (const struct tb_xdp_properties *)pkg);
                }
@@ -818,7 +820,8 @@ static void tb_xdp_handle_request(struct work_struct *work)
                tb_dbg(tb, "%llx: received XDomain link state change request\n",
                       route);
 
-               if (xd && xd->state == XDOMAIN_STATE_BONDING_UUID_HIGH) {
+               if (xd && xd->state == XDOMAIN_STATE_BONDING_UUID_HIGH &&
+                   pkg_len >= sizeof(struct tb_xdp_link_state_change)) {
                        const struct tb_xdp_link_state_change *lsc =
                                (const struct tb_xdp_link_state_change *)pkg;
 
@@ -870,6 +873,7 @@ tb_xdp_schedule_request(struct tb *tb, const struct tb_xdp_header *hdr,
                kfree(xw);
                return false;
        }
+       xw->pkg_len = size;
        xw->tb = tb_domain_get(tb);
 
        schedule_work(&xw->work);