From c96fc14322cee45cdf751cb4ae62c9eab25bc643 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sun, 7 Jun 2026 22:05:42 -0700 Subject: [PATCH 1/4] interconnect: qcom: add COMPILE_TEST Allow non-ARM to build this. Signed-off-by: Rosen Penev Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260608050542.6167-1-rosenp@gmail.com Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig index 5b8a094ca4ed..e6a65ca611a0 100644 --- a/drivers/interconnect/qcom/Kconfig +++ b/drivers/interconnect/qcom/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config INTERCONNECT_QCOM tristate "Qualcomm Network-on-Chip interconnect drivers" - depends on ARCH_QCOM + depends on ARCH_QCOM || COMPILE_TEST help Support for Qualcomm's Network-on-Chip interconnect hardware. From bd8a131fbe4989b8e57aa74fdc974900460ac387 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 9 Jun 2026 15:24:54 -0700 Subject: [PATCH 2/4] interconnect: qcom: simplify allocation Use a flexible array member to reduce allocation by 1. Add __counted_by for extra runtime analysis. Move counting variable assignment after allocation before any array access. Signed-off-by: Rosen Penev Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://patch.msgid.link/20260609222454.37352-1-rosenp@gmail.com Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/icc-rpm.c | 7 ++----- drivers/interconnect/qcom/icc-rpm.h | 8 ++++---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c index 23a1d116e79a..ca4c8a944755 100644 --- a/drivers/interconnect/qcom/icc-rpm.c +++ b/drivers/interconnect/qcom/icc-rpm.c @@ -479,13 +479,11 @@ int qnoc_probe(struct platform_device *pdev) cd_num = 0; } - qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL); + qp = devm_kzalloc(dev, struct_size(qp, intf_clks, cd_num), GFP_KERNEL); if (!qp) return -ENOMEM; - qp->intf_clks = devm_kcalloc(dev, cd_num, sizeof(*qp->intf_clks), GFP_KERNEL); - if (!qp->intf_clks) - return -ENOMEM; + qp->num_intf_clks = cd_num; if (desc->bus_clk_desc) { qp->bus_clk_desc = devm_kzalloc(dev, sizeof(*qp->bus_clk_desc), @@ -507,7 +505,6 @@ int qnoc_probe(struct platform_device *pdev) return -ENOMEM; data->num_nodes = num_nodes; - qp->num_intf_clks = cd_num; for (i = 0; i < cd_num; i++) qp->intf_clks[i].id = cds[i]; diff --git a/drivers/interconnect/qcom/icc-rpm.h b/drivers/interconnect/qcom/icc-rpm.h index 7d1cb2efa9ee..cdd5f444b152 100644 --- a/drivers/interconnect/qcom/icc-rpm.h +++ b/drivers/interconnect/qcom/icc-rpm.h @@ -40,7 +40,6 @@ struct rpm_clk_resource { /** * struct qcom_icc_provider - Qualcomm specific interconnect provider * @provider: generic interconnect provider - * @num_intf_clks: the total number of intf_clks clk_bulk_data entries * @type: the ICC provider type * @regmap: regmap for QoS registers read/write access * @qos_offset: offset to QoS registers @@ -49,13 +48,13 @@ struct rpm_clk_resource { * @bus_clk_rate: bus clock rate in Hz * @bus_clk_desc: a pointer to a rpm_clk_resource description of bus clocks * @bus_clk: a pointer to a HLOS-owned bus clock - * @intf_clks: a clk_bulk_data array of interface clocks * @keep_alive: whether to always keep a minimum vote on the bus clocks * @ignore_enxio: whether to ignore ENXIO errors (for MSM8974) + * @num_intf_clks: the total number of intf_clks clk_bulk_data entries + * @intf_clks: a clk_bulk_data array of interface clocks */ struct qcom_icc_provider { struct icc_provider provider; - int num_intf_clks; enum qcom_icc_type type; struct regmap *regmap; unsigned int qos_offset; @@ -64,9 +63,10 @@ struct qcom_icc_provider { u32 bus_clk_rate[QCOM_SMD_RPM_STATE_NUM]; const struct rpm_clk_resource *bus_clk_desc; struct clk *bus_clk; - struct clk_bulk_data *intf_clks; bool keep_alive; bool ignore_enxio; + int num_intf_clks; + struct clk_bulk_data intf_clks[] __counted_by(num_intf_clks); }; /** From ecf20a5e15f9c81a97b1249c979b9c439e777592 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Tue, 2 Jun 2026 18:31:20 +0800 Subject: [PATCH 3/4] interconnect: debugfs-client: add NULL check for platform_device_alloc platform_device_alloc() may return NULL when memory allocation fails. Add proper error handling to prevent a potential NULL pointer dereference when calling platform_device_add() with a NULL pointer. Signed-off-by: Li Jun Link: https://patch.msgid.link/20260602103120.2966458-1-lijun01@kylinos.cn Signed-off-by: Georgi Djakov --- drivers/interconnect/debugfs-client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/interconnect/debugfs-client.c b/drivers/interconnect/debugfs-client.c index 08df9188ef94..91f86d9237a6 100644 --- a/drivers/interconnect/debugfs-client.c +++ b/drivers/interconnect/debugfs-client.c @@ -142,6 +142,8 @@ int icc_debugfs_client_init(struct dentry *icc_dir) int ret; pdev = platform_device_alloc("icc-debugfs-client", PLATFORM_DEVID_NONE); + if (!pdev) + return -ENOMEM; ret = platform_device_add(pdev); if (ret) { From 25c7e242aca084fdc1098248194032317dca625d Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Thu, 16 Apr 2026 19:08:40 +0000 Subject: [PATCH 4/4] interconnect: Fix use after free in icc_get() and of_icc_get_by_index() In of_icc_get_by_index() and icc_get(), if the dynamic allocation for path->name fails via kasprintf(), the error handling path directly calls kfree(path) to free the path object and returns an error. However, prior to this point, path_find() calls path_init(), which already links the path's requests into the req_list of the respective interconnect nodes via hlist_add_head(). Directly invoking kfree(path) leaves dangling pointers in the hlist. A subsequent call to icc_get() or icc_set_bw() will traverse or modify these corrupted lists, triggering a slab use afterfree. KASAN report showing the vulnerability when reproducing via debugfs: BUG: KASAN: slab-use-after-free in path_find+0x6f8/0xcfc Write of size 8 at addr fff000000d43f748 by task sh/1 ... Call trace: kasan_report+0xac/0xfc path_find+0x6f8/0xcfc icc_get+0x148/0x380 icc_get_set+0xf8/0x2d0 ... Freed by task 1: kfree+0x1a0/0x4a4 icc_get+0x2cc/0x380 icc_get_set+0xf8/0x2d0 Fix this by replacing kfree(path) with the proper teardown function, icc_put(path), which safely removes the requests from the req_list using hlist_del() and drops the provider usage references before freeing the memory. Additionally, in icc_get(), ensure that the icc_lock mutex is released prior to calling icc_put(path) to avoid a deadlock, as icc_put() internally acquires the same lock. Fixes: 3791163602f7 ("interconnect: Handle memory allocation errors") Cc: stable@vger.kernel.org Signed-off-by: Kuan-Wei Chiu Link: https://patch.msgid.link/20260416190840.1753468-1-visitorckw@gmail.com Signed-off-by: Georgi Djakov --- drivers/interconnect/core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c index 73a9db2c7537..4aa991a54101 100644 --- a/drivers/interconnect/core.c +++ b/drivers/interconnect/core.c @@ -548,7 +548,7 @@ struct icc_path *of_icc_get_by_index(struct device *dev, int idx) path->name = kasprintf(GFP_KERNEL, "%s-%s", src_data->node->name, dst_data->node->name); if (!path->name) { - kfree(path); + icc_put(path); path = ERR_PTR(-ENOMEM); } @@ -646,8 +646,9 @@ struct icc_path *icc_get(struct device *dev, const char *src, const char *dst) path->name = kasprintf(GFP_KERNEL, "%s-%s", src_node->name, dst_node->name); if (!path->name) { - kfree(path); - path = ERR_PTR(-ENOMEM); + mutex_unlock(&icc_lock); + icc_put(path); + return ERR_PTR(-ENOMEM); } out: mutex_unlock(&icc_lock);