FAILED: patch "[PATCH] thunderbolt: property: Cap recursion depth in" failed to apply to 5.15-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x 928abe19fbf0127003abcb1ea69cabc1c897d0ab
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026060409-plot-clatter-8e2c@gregkh' --subject-prefix 'PATCH 5.15.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 928abe19fbf0127003abcb1ea69cabc1c897d0ab Mon Sep 17 00:00:00 2001
From: Michael Bommarito <[email protected]>
Date: Sun, 10 May 2026 19:16:58 -0400
Subject: [PATCH] thunderbolt: property: Cap recursion depth in
__tb_property_parse_dir()
A DIRECTORY entry's value field is used as the dir_offset for a recursive call into __tb_property_parse_dir() with no depth counter. A crafted peer that chains DIRECTORY entries into a back-reference loop drives the parser until the kernel stack is exhausted and the guard page fires. Any untrusted XDomain peer (cable, dock, in-line inspector, adjacent host) that reaches the PROPERTIES_REQUEST control-plane exchange can trigger this without authentication.
Thread a depth counter through tb_property_parse() and __tb_property_parse_dir(), and reject blocks that exceed TB_PROPERTY_MAX_DEPTH = 8. That is comfortably larger than any observed legitimate XDomain layout.
Operators who do not need XDomain host-to-host discovery can disable the path entirely with thunderbolt.xdomain=0 on the kernel command line.
drivers/thunderbolt/property.c +12 -6
@@ -35,10 +35,11 @@ struct tb_property_dir_entry { };#define TB_PROPERTY_ROOTDIR_MAGIC 0x55584401 +#define TB_PROPERTY_MAX_DEPTH 8static struct tb_property_dir *__tb_property_parse_dir (const u32 *block,size_t block_len,unsigned int dir_offset,size_t dir_len, -bool is_root); +bool is_root,unsigned int depth);static inline void parse_dwdata (void *dst,const void *src,size_t dwords) {
@@ -97,7 +98,8 @@ tb_property_alloc(const char *key, enum tb_property_type type) }static struct tb_property *tb_property_parse (const u32 *block,size_t block_len, -const struct tb_property_entry *entry) +const struct tb_property_entry *entry, +unsigned int depth) {char key[TB_PROPERTY_KEY_SIZE +1 ];struct tb_property *property;
@@ -118,7 +120,7 @@ static struct tb_property *tb_property_parse(const u32 *block, size_t block_len,switch (property->type) {case TB_PROPERTY_TYPE_DIRECTORY : dir =__tb_property_parse_dir (block, block_len, entry->value, - entry->length, false); + entry->length, false, depth +1 );if (!dir) {kfree (property);return NULL ;
@@ -163,13 +165,17 @@ static struct tb_property *tb_property_parse(const u32 *block, size_t block_len, }static struct tb_property_dir *__tb_property_parse_dir (const u32 *block, -size_t block_len,unsigned int dir_offset,size_t dir_len,bool is_root) +size_t block_len,unsigned int dir_offset,size_t dir_len,bool is_root, +unsigned int depth) {const struct tb_property_entry *entries;size_t i, content_len, nentries;unsigned int content_offset;struct tb_property_dir *dir; +if (depth >TB_PROPERTY_MAX_DEPTH ) +return NULL ; + dir =kzalloc_obj (*dir);if (!dir)return NULL ;
@@ -200,7 +206,7 @@ static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,for (i =0 ; i < nentries; i++) {struct tb_property *property; - property =tb_property_parse (block, block_len, &entries[i]); + property =tb_property_parse (block, block_len, &entries[i], depth);if (!property) {tb_property_free_dir (dir);return NULL ;
@@ -239,7 +245,7 @@ struct tb_property_dir *tb_property_parse_dir(const u32 *block,return NULL ;return __tb_property_parse_dir (block, block_len,0 , rootdir->length, - true); + true,0 ); }/**
Sasha Levin
maintainerPATCH 1/1 thunderbolt: property: Cap recursion depth in __tb_property_parse_dir()
From: Michael Bommarito <[email protected]>
[ Upstream commit 928abe19fbf0127003abcb1ea69cabc1c897d0ab ]
A DIRECTORY entry's value field is used as the dir_offset for a recursive call into __tb_property_parse_dir() with no depth counter. A crafted peer that chains DIRECTORY entries into a back-reference loop drives the parser until the kernel stack is exhausted and the guard page fires. Any untrusted XDomain peer (cable, dock, in-line inspector, adjacent host) that reaches the PROPERTIES_REQUEST control-plane exchange can trigger this without authentication.
Thread a depth counter through tb_property_parse() and __tb_property_parse_dir(), and reject blocks that exceed TB_PROPERTY_MAX_DEPTH = 8. That is comfortably larger than any observed legitimate XDomain layout.
Operators who do not need XDomain host-to-host discovery can disable the path entirely with thunderbolt.xdomain=0 on the kernel command line.
--- drivers/thunderbolt/property.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
drivers/thunderbolt/property.c +12 -6
@@ -34,10 +34,11 @@ struct tb_property_dir_entry { };#define TB_PROPERTY_ROOTDIR_MAGIC 0x55584401 +#define TB_PROPERTY_MAX_DEPTH 8static struct tb_property_dir *__tb_property_parse_dir (const u32 *block,size_t block_len,unsigned int dir_offset,size_t dir_len, -bool is_root); +bool is_root,unsigned int depth);static inline void parse_dwdata (void *dst,const void *src,size_t dwords) {
@@ -93,7 +94,8 @@ tb_property_alloc(const char *key, enum tb_property_type type) }static struct tb_property *tb_property_parse (const u32 *block,size_t block_len, -const struct tb_property_entry *entry) +const struct tb_property_entry *entry, +unsigned int depth) {char key[TB_PROPERTY_KEY_SIZE +1 ];struct tb_property *property;
@@ -114,7 +116,7 @@ static struct tb_property *tb_property_parse(const u32 *block, size_t block_len,switch (property->type) {case TB_PROPERTY_TYPE_DIRECTORY : dir =__tb_property_parse_dir (block, block_len, entry->value, - entry->length, false); + entry->length, false, depth +1 );if (!dir) {kfree (property);return NULL ;
@@ -159,13 +161,17 @@ static struct tb_property *tb_property_parse(const u32 *block, size_t block_len, }static struct tb_property_dir *__tb_property_parse_dir (const u32 *block, -size_t block_len,unsigned int dir_offset,size_t dir_len,bool is_root) +size_t block_len,unsigned int dir_offset,size_t dir_len,bool is_root, +unsigned int depth) {const struct tb_property_entry *entries;size_t i, content_len, nentries;unsigned int content_offset;struct tb_property_dir *dir; +if (depth >TB_PROPERTY_MAX_DEPTH ) +return NULL ; + dir =kzalloc (sizeof (*dir),GFP_KERNEL );if (!dir)return NULL ;
@@ -192,7 +198,7 @@ static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,for (i =0 ; i < nentries; i++) {struct tb_property *property; - property =tb_property_parse (block, block_len, &entries[i]); + property =tb_property_parse (block, block_len, &entries[i], depth);if (!property) {tb_property_free_dir (dir);return NULL ;
@@ -229,7 +235,7 @@ struct tb_property_dir *tb_property_parse_dir(const u32 *block,return NULL ;return __tb_property_parse_dir (block, block_len,0 , rootdir->length, - true); + true,0 ); }/**
Signature · 1 line
2.53.0