* [PATCH 0/2] thunderbolt: Validate router-provided port numbers
@ 2026-09-09 3:50 Daehyeon Ko
2026-09-09 3:50 ` [PATCH 1/2] thunderbolt: Validate DP bandwidth notification port Daehyeon Ko
2026-09-09 3:50 ` [PATCH 2/2] thunderbolt: Validate output ports while discovering paths Daehyeon Ko
0 siblings, 2 replies; 5+ messages in thread
From: Daehyeon Ko @ 2026-09-09 3:50 UTC (permalink / raw)
To: Mika Westerberg; +Cc: Andreas Noever, Yehezkel Bernat, linux-usb, linux-kernel
Two six-bit port numbers received from a router are used to index the
router's sw->ports array without first comparing them with
max_port_number. The array contains only max_port_number + 1 entries.
Patch 1 validates the port in a DP bandwidth notification before
tb_handle_dp_bandwidth_request() calls tb_port_is_dpin(). Patch 2
validates HOPS out_port at all three path-discovery sites and performs
the construction-pass check before allocating an input HopID.
I tested a private synthetic KUnit reproducer on current mainline
893e11787f78. It allocates ports 0 through 12 and supplies port 63. On
x86_64, struct tb_port is 200 bytes, so the requested allocation is
2,600 bytes and the selected object starts at offset 12,600.
The unmodified accesses produced:
- a four-byte KASAN slab-out-of-bounds read in
tb_port_is_dpin(), 3/3 boots;
- an eight-byte KASAN slab-out-of-bounds read of
out_port->remote, 3/3 boots.
With this series, both controls pass 3/3 with no KASAN report and the
complete Thunderbolt KUnit suite passes 47/47. drivers/thunderbolt/tb.o
and path.o also build with W=1 without warnings.
I have not performed hardware control-channel or HOPS injection. The DP
notification index is used before tunnel lookup or bandwidth-mode
validation. The HOPS sites are used to discover already enabled preboot
tunnels and during resume discovery; ordinary hotplug path construction
uses tb_path_alloc() instead.
The private reproducer is available to the maintainers on request and is
not included in this public series.
Daehyeon Ko (2):
thunderbolt: Validate DP bandwidth notification port
thunderbolt: Validate output ports while discovering paths
drivers/thunderbolt/path.c | 27 ++++++++++++++++++++++-----
drivers/thunderbolt/tb.c | 5 +++++
2 files changed, 27 insertions(+), 5 deletions(-)
base-commit: 893e11787f78e43b534e252249ac3fff4d1333f8
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH 1/2] thunderbolt: Validate DP bandwidth notification port 2026-09-09 3:50 [PATCH 0/2] thunderbolt: Validate router-provided port numbers Daehyeon Ko @ 2026-09-09 3:50 ` Daehyeon Ko 2026-09-10 8:05 ` Mika Westerberg 2026-09-09 3:50 ` [PATCH 2/2] thunderbolt: Validate output ports while discovering paths Daehyeon Ko 1 sibling, 1 reply; 5+ messages in thread From: Daehyeon Ko @ 2026-09-09 3:50 UTC (permalink / raw) To: Mika Westerberg; +Cc: Andreas Noever, Yehezkel Bernat, linux-usb, linux-kernel The port number in a DP bandwidth notification is six bits wide and comes from the router. A router whose maximum port number is smaller can therefore make tb_handle_dp_bandwidth_request() index beyond the max_port_number + 1 entries allocated for sw->ports. The first tb_port_is_dpin() check then reads the out-of-bounds object. Reject notifications that refer to a non-existent adapter before dereferencing the port. Fixes: 6ce3563520be ("thunderbolt: Add support for DisplayPort bandwidth allocation mode") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> --- drivers/thunderbolt/tb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 47753a5c0f2eb..8551dafe98c8e 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -2756,6 +2756,11 @@ static void tb_handle_dp_bandwidth_request(struct work_struct *work) goto unlock; } + if (ev->port > sw->config.max_port_number) { + tb_sw_warn(sw, "bandwidth request from non-existent port %u\n", + ev->port); + goto put_sw; + } in = &sw->ports[ev->port]; if (!tb_port_is_dpin(in)) { tb_port_warn(in, "bandwidth request to non-DP IN adapter\n"); -- 2.55.0 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] thunderbolt: Validate DP bandwidth notification port 2026-09-09 3:50 ` [PATCH 1/2] thunderbolt: Validate DP bandwidth notification port Daehyeon Ko @ 2026-09-10 8:05 ` Mika Westerberg 0 siblings, 0 replies; 5+ messages in thread From: Mika Westerberg @ 2026-09-10 8:05 UTC (permalink / raw) To: Daehyeon Ko Cc: Mika Westerberg, Andreas Noever, Yehezkel Bernat, linux-usb, linux-kernel Hi, On Wed, Sep 09, 2026 at 12:50:39PM +0900, Daehyeon Ko wrote: > The port number in a DP bandwidth notification is six bits wide and > comes from the router. A router whose maximum port number is smaller can > therefore make tb_handle_dp_bandwidth_request() index beyond the > max_port_number + 1 entries allocated for sw->ports. The first > tb_port_is_dpin() check then reads the out-of-bounds object. > > Reject notifications that refer to a non-existent adapter before > dereferencing the port. > > Fixes: 6ce3563520be ("thunderbolt: Add support for DisplayPort bandwidth allocation mode") > Cc: stable@vger.kernel.org > Assisted-by: LLM > Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> > --- > drivers/thunderbolt/tb.c | 5 +++++ > 1 file changed, 5 insertions(+) > > diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c > index 47753a5c0f2eb..8551dafe98c8e 100644 > --- a/drivers/thunderbolt/tb.c > +++ b/drivers/thunderbolt/tb.c > @@ -2756,6 +2756,11 @@ static void tb_handle_dp_bandwidth_request(struct work_struct *work) > goto unlock; > } > > + if (ev->port > sw->config.max_port_number) { > + tb_sw_warn(sw, "bandwidth request from non-existent port %u\n", > + ev->port); > + goto put_sw; For this can you make a helper function tb_switch_port(sw, ev->port) that issues a warning and then replace the direct access sw->ports[] with that? > + } > in = &sw->ports[ev->port]; > if (!tb_port_is_dpin(in)) { > tb_port_warn(in, "bandwidth request to non-DP IN adapter\n"); > -- > 2.55.0 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/2] thunderbolt: Validate output ports while discovering paths 2026-09-09 3:50 [PATCH 0/2] thunderbolt: Validate router-provided port numbers Daehyeon Ko 2026-09-09 3:50 ` [PATCH 1/2] thunderbolt: Validate DP bandwidth notification port Daehyeon Ko @ 2026-09-09 3:50 ` Daehyeon Ko 2026-09-09 12:21 ` Mika Westerberg 1 sibling, 1 reply; 5+ messages in thread From: Daehyeon Ko @ 2026-09-09 3:50 UTC (permalink / raw) To: Mika Westerberg; +Cc: Andreas Noever, Yehezkel Bernat, linux-usb, linux-kernel Path discovery reads the six-bit output port number from router HOPS configuration space and uses it to index sw->ports at three sites. A router can return a number larger than max_port_number and make the connection manager read an out-of-bounds tb_port, retain the invalid pointer in a path, or pass its embedded HopID allocator to IDA. Resolve each output port through a bounded helper. In the construction pass, validate the output port before allocating the input HopID so a rejected entry needs no additional unwind. Fixes: 0414bec5f39a ("thunderbolt: Discover preboot PCIe paths the boot firmware established") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> --- drivers/thunderbolt/path.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/thunderbolt/path.c b/drivers/thunderbolt/path.c index b2c322e76b8ad..ea72153690dd3 100644 --- a/drivers/thunderbolt/path.c +++ b/drivers/thunderbolt/path.c @@ -31,6 +31,17 @@ static void tb_dump_hop(const struct tb_path_hop *hop, const struct tb_regs_hop regs->unknown1, regs->unknown2, regs->unknown3); } +static struct tb_port *tb_path_hop_out_port(struct tb_switch *sw, + const struct tb_regs_hop *hop) +{ + if (hop->out_port > sw->config.max_port_number) { + tb_sw_warn(sw, "hop refers to non-existent port %u\n", + hop->out_port); + return NULL; + } + return &sw->ports[hop->out_port]; +} + static struct tb_port *tb_path_find_dst_port(struct tb_port *src, int src_hopid, int dst_hopid) { @@ -54,7 +65,9 @@ static struct tb_port *tb_path_find_dst_port(struct tb_port *src, int src_hopid, if (!hop.enable) return NULL; - out_port = &sw->ports[hop.out_port]; + out_port = tb_path_hop_out_port(sw, &hop); + if (!out_port) + return NULL; hopid = hop.next_hop; port = out_port->remote; } @@ -141,7 +154,9 @@ struct tb_path *tb_path_discover(struct tb_port *src, int src_hopid, if (!hop.enable) break; - out_port = &sw->ports[hop.out_port]; + out_port = tb_path_hop_out_port(sw, &hop); + if (!out_port) + return NULL; if (last) *last = out_port; @@ -178,12 +193,14 @@ struct tb_path *tb_path_discover(struct tb_port *src, int src_hopid, goto err; } - if (alloc_hopid && tb_port_alloc_in_hopid(p, h, h) < 0) + out_port = tb_path_hop_out_port(sw, &hop); + if (!out_port) goto err; - - out_port = &sw->ports[hop.out_port]; next_hop = hop.next_hop; + if (alloc_hopid && tb_port_alloc_in_hopid(p, h, h) < 0) + goto err; + if (alloc_hopid && tb_port_alloc_out_hopid(out_port, next_hop, next_hop) < 0) { tb_port_release_in_hopid(p, h); -- 2.55.0 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] thunderbolt: Validate output ports while discovering paths 2026-09-09 3:50 ` [PATCH 2/2] thunderbolt: Validate output ports while discovering paths Daehyeon Ko @ 2026-09-09 12:21 ` Mika Westerberg 0 siblings, 0 replies; 5+ messages in thread From: Mika Westerberg @ 2026-09-09 12:21 UTC (permalink / raw) To: Daehyeon Ko Cc: Mika Westerberg, Andreas Noever, Yehezkel Bernat, linux-usb, linux-kernel Hi, On Wed, Sep 09, 2026 at 12:50:40PM +0900, Daehyeon Ko wrote: > Path discovery reads the six-bit output port number from router HOPS > configuration space and uses it to index sw->ports at three sites. A > router can return a number larger than max_port_number and make the > connection manager read an out-of-bounds tb_port, retain the invalid > pointer in a path, or pass its embedded HopID allocator to IDA. > > Resolve each output port through a bounded helper. In the construction > pass, validate the output port before allocating the input HopID so a > rejected entry needs no additional unwind. If a router deliberately provides wrong information it can do much worse things than just mess up with the CM. We should outright deny that thing from even connecting not trying to fix every possible place where things can go wrong. Second thing is that this is path discovery which is now pretty much debugging tool rather than the default so a regular user never hits this anyway. > Fixes: 0414bec5f39a ("thunderbolt: Discover preboot PCIe paths the boot firmware established") > Cc: stable@vger.kernel.org > Assisted-by: LLM > Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> > --- > drivers/thunderbolt/path.c | 27 ++++++++++++++++++++++----- > 1 file changed, 22 insertions(+), 5 deletions(-) > > diff --git a/drivers/thunderbolt/path.c b/drivers/thunderbolt/path.c > index b2c322e76b8ad..ea72153690dd3 100644 > --- a/drivers/thunderbolt/path.c > +++ b/drivers/thunderbolt/path.c > @@ -31,6 +31,17 @@ static void tb_dump_hop(const struct tb_path_hop *hop, const struct tb_regs_hop > regs->unknown1, regs->unknown2, regs->unknown3); > } > > +static struct tb_port *tb_path_hop_out_port(struct tb_switch *sw, > + const struct tb_regs_hop *hop) > +{ > + if (hop->out_port > sw->config.max_port_number) { > + tb_sw_warn(sw, "hop refers to non-existent port %u\n", > + hop->out_port); > + return NULL; > + } > + return &sw->ports[hop->out_port]; > +} > + > static struct tb_port *tb_path_find_dst_port(struct tb_port *src, int src_hopid, > int dst_hopid) > { > @@ -54,7 +65,9 @@ static struct tb_port *tb_path_find_dst_port(struct tb_port *src, int src_hopid, > if (!hop.enable) > return NULL; > > - out_port = &sw->ports[hop.out_port]; > + out_port = tb_path_hop_out_port(sw, &hop); > + if (!out_port) > + return NULL; > hopid = hop.next_hop; > port = out_port->remote; > } > @@ -141,7 +154,9 @@ struct tb_path *tb_path_discover(struct tb_port *src, int src_hopid, > if (!hop.enable) > break; > > - out_port = &sw->ports[hop.out_port]; > + out_port = tb_path_hop_out_port(sw, &hop); > + if (!out_port) > + return NULL; > if (last) > *last = out_port; > > @@ -178,12 +193,14 @@ struct tb_path *tb_path_discover(struct tb_port *src, int src_hopid, > goto err; > } > > - if (alloc_hopid && tb_port_alloc_in_hopid(p, h, h) < 0) > + out_port = tb_path_hop_out_port(sw, &hop); > + if (!out_port) > goto err; > - > - out_port = &sw->ports[hop.out_port]; > next_hop = hop.next_hop; > > + if (alloc_hopid && tb_port_alloc_in_hopid(p, h, h) < 0) > + goto err; > + > if (alloc_hopid && > tb_port_alloc_out_hopid(out_port, next_hop, next_hop) < 0) { > tb_port_release_in_hopid(p, h); > -- > 2.55.0 ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-10 8:05 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-09-09 3:50 [PATCH 0/2] thunderbolt: Validate router-provided port numbers Daehyeon Ko 2026-09-09 3:50 ` [PATCH 1/2] thunderbolt: Validate DP bandwidth notification port Daehyeon Ko 2026-09-10 8:05 ` Mika Westerberg 2026-09-09 3:50 ` [PATCH 2/2] thunderbolt: Validate output ports while discovering paths Daehyeon Ko 2026-09-09 12:21 ` Mika Westerberg
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®