Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

thunderbolt: xdomain: Avoid potential stack OOB read

tb_xdp_properties_changed_request() was calling tb_xdp_handle_error() with
a struct tb_xdp_properties_changed_response on the stack, which does not
have the "error" field present when cast to struct tb_xdp_error_response.
This was detected when building with -Warray-bounds:

drivers/thunderbolt/xdomain.c: In function 'tb_xdomain_properties_changed':
drivers/thunderbolt/xdomain.c:226:22: error: array subscript 'const struct tb_xdp_error_response[0]' is partly outside array bounds of 'struct tb_xdp_properties_changed_response[1]' [-Werror=array-bounds]
226 | switch (error->error) {
| ~~~~~^~~~~~~
drivers/thunderbolt/xdomain.c:448:51: note: while referencing 'res'
448 | struct tb_xdp_properties_changed_response res;
| ^~~

Add union containing struct tb_xdp_error_response to structures passed
to tb_xdp_handle_error(), so that the "error" field will be present.

Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>

authored by

Kees Cook and committed by
Mika Westerberg
19813551 0fcfb00b

+36 -27
+30 -17
drivers/thunderbolt/tb_msgs.h
··· 535 535 u32 type; 536 536 }; 537 537 538 + struct tb_xdp_error_response { 539 + struct tb_xdp_header hdr; 540 + u32 error; 541 + }; 542 + 538 543 struct tb_xdp_uuid { 539 544 struct tb_xdp_header hdr; 540 545 }; 541 546 542 547 struct tb_xdp_uuid_response { 543 - struct tb_xdp_header hdr; 544 - uuid_t src_uuid; 545 - u32 src_route_hi; 546 - u32 src_route_lo; 548 + union { 549 + struct tb_xdp_error_response err; 550 + struct { 551 + struct tb_xdp_header hdr; 552 + uuid_t src_uuid; 553 + u32 src_route_hi; 554 + u32 src_route_lo; 555 + }; 556 + }; 547 557 }; 548 558 549 559 struct tb_xdp_properties { ··· 565 555 }; 566 556 567 557 struct tb_xdp_properties_response { 568 - struct tb_xdp_header hdr; 569 - uuid_t src_uuid; 570 - uuid_t dst_uuid; 571 - u16 offset; 572 - u16 data_length; 573 - u32 generation; 574 - u32 data[0]; 558 + union { 559 + struct tb_xdp_error_response err; 560 + struct { 561 + struct tb_xdp_header hdr; 562 + uuid_t src_uuid; 563 + uuid_t dst_uuid; 564 + u16 offset; 565 + u16 data_length; 566 + u32 generation; 567 + u32 data[]; 568 + }; 569 + }; 575 570 }; 576 571 577 572 /* ··· 595 580 }; 596 581 597 582 struct tb_xdp_properties_changed_response { 598 - struct tb_xdp_header hdr; 583 + union { 584 + struct tb_xdp_error_response err; 585 + struct tb_xdp_header hdr; 586 + }; 599 587 }; 600 588 601 589 enum tb_xdp_error { ··· 607 589 ERROR_UNKNOWN_DOMAIN, 608 590 ERROR_NOT_SUPPORTED, 609 591 ERROR_NOT_READY, 610 - }; 611 - 612 - struct tb_xdp_error_response { 613 - struct tb_xdp_header hdr; 614 - u32 error; 615 592 }; 616 593 617 594 #endif
+6 -10
drivers/thunderbolt/xdomain.c
··· 214 214 memcpy(&hdr->uuid, &tb_xdp_uuid, sizeof(tb_xdp_uuid)); 215 215 } 216 216 217 - static int tb_xdp_handle_error(const struct tb_xdp_header *hdr) 217 + static int tb_xdp_handle_error(const struct tb_xdp_error_response *res) 218 218 { 219 - const struct tb_xdp_error_response *error; 220 - 221 - if (hdr->type != ERROR_RESPONSE) 219 + if (res->hdr.type != ERROR_RESPONSE) 222 220 return 0; 223 221 224 - error = (const struct tb_xdp_error_response *)hdr; 225 - 226 - switch (error->error) { 222 + switch (res->error) { 227 223 case ERROR_UNKNOWN_PACKET: 228 224 case ERROR_UNKNOWN_DOMAIN: 229 225 return -EIO; ··· 253 257 if (ret) 254 258 return ret; 255 259 256 - ret = tb_xdp_handle_error(&res.hdr); 260 + ret = tb_xdp_handle_error(&res.err); 257 261 if (ret) 258 262 return ret; 259 263 ··· 325 329 if (ret) 326 330 goto err; 327 331 328 - ret = tb_xdp_handle_error(&res->hdr); 332 + ret = tb_xdp_handle_error(&res->err); 329 333 if (ret) 330 334 goto err; 331 335 ··· 458 462 if (ret) 459 463 return ret; 460 464 461 - return tb_xdp_handle_error(&res.hdr); 465 + return tb_xdp_handle_error(&res.err); 462 466 } 463 467 464 468 static int