6.6-stable review patch. If anyone has any objections, please let me know. ------------------ From: Takashi Sakamoto [ Upstream commit 05bfb1327dc5fb61528bab31cd8f0c1e4bddec23 ] In the error path of build_tree(), node instances can remain in the local linked list when the function returns. Whenever an invalid value is detected in the self ID sequence, each allocated node instance is either an entry in the linked list or an entry in the ports array of its parent node. Therefore, the allocate node instances can be safely released by traversing the linked list from its head. Release the remaining node instances with for_each_fw_node() before returning to the caller. Fixes: 3038e353cfaf ("firewire: Add core firewire stack.") Reported-by: Abdun Nihaal Link: https://lore.kernel.org/all/20260727095955.104972-1-nihaal@cse.iitm.ac.in/ Link: https://lore.kernel.org/r/20260811120928.700577-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto Signed-off-by: Sasha Levin --- drivers/firewire/core-topology.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c index f40c815343812..99a2fc88ccd2e 100644 --- a/drivers/firewire/core-topology.c +++ b/drivers/firewire/core-topology.c @@ -161,6 +161,17 @@ static inline struct fw_node *fw_node(struct list_head *l) return list_entry(l, struct fw_node, link); } +typedef void (*fw_node_callback_t)(struct fw_card *card, struct fw_node *node, + struct fw_node *parent); + +static void for_each_fw_node(struct fw_card *card, struct fw_node *root, + fw_node_callback_t callback); + +static void free_fw_node(struct fw_card *card, struct fw_node *node, struct fw_node *parent) +{ + fw_node_put(node); +} + /* * This function builds the tree representation of the topology given * by the self IDs from the latest bus reset. During the construction @@ -193,19 +204,19 @@ static struct fw_node *build_tree(struct fw_card *card, if (next_sid == NULL) { fw_err(card, "inconsistent extended self IDs\n"); - return NULL; + goto error; } q = *sid; if (phy_id != SELF_ID_PHY_ID(q)) { fw_err(card, "PHY ID mismatch in self ID: %d != %d\n", phy_id, SELF_ID_PHY_ID(q)); - return NULL; + goto error; } if (child_port_count > stack_depth) { fw_err(card, "topology stack underflow\n"); - return NULL; + goto error; } /* @@ -223,7 +234,7 @@ static struct fw_node *build_tree(struct fw_card *card, node = fw_node_create(q, port_count, card->color); if (node == NULL) { fw_err(card, "out of memory while building topology\n"); - return NULL; + goto error; } if (phy_id == (card->node_id & 0x3f)) @@ -273,7 +284,7 @@ static struct fw_node *build_tree(struct fw_card *card, (next_sid < end && parent_count != 1)) { fw_err(card, "parent port inconsistency for node %d: " "parent_count=%d\n", phy_id, parent_count); - return NULL; + goto error; } /* Pop the child nodes off the stack and push the new node. */ @@ -304,12 +315,13 @@ static struct fw_node *build_tree(struct fw_card *card, card->beta_repeaters_present = beta_repeaters_present; return local_node; +error: + ++card->color; + list_for_each_entry_safe(node, child, &stack, link) + for_each_fw_node(card, node, free_fw_node); + return NULL; } -typedef void (*fw_node_callback_t)(struct fw_card * card, - struct fw_node * node, - struct fw_node * parent); - static void for_each_fw_node(struct fw_card *card, struct fw_node *root, fw_node_callback_t callback) { -- 2.53.0