Received: by 2002:a05:7412:b995:b0:f9:9502:5bb8 with SMTP id it21csp4466259rdb; Fri, 29 Dec 2023 02:55:02 -0800 (PST) X-Google-Smtp-Source: AGHT+IEx5hqvhGbqhVxMyjKsxHy9inWBB49Cnfeu2o/xAfKJkdD87wBsxikYTCjkwdPUvbppXQsm X-Received: by 2002:ad4:50ce:0:b0:67f:e014:278d with SMTP id e14-20020ad450ce000000b0067fe014278dmr7790153qvq.81.1703847302635; Fri, 29 Dec 2023 02:55:02 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1703847302; cv=none; d=google.com; s=arc-20160816; b=Z4f9eiaRT4vB3MWISXhu8auEmYU4CRRXPMt8NEvd0xeBptJTt6AQ7xRoSfkNzv+/AY ekNf18wPpwDv1fxj+dTvsj2OezVkhYPHYfre9Z5jzFGiHRKFp5tFDVrxNU3kParbbFZ9 Lh9CIo181pVfinn0y8OaMW8XbjAl2B8c4JgohX5iqTu+PeRbPG5+KB+XR1FVy4fYDF1+ yvS19N24wEhl52A0zimIBgHO21paT283KD/ZQRpkEcfgMxSGLj2bLz65pepcMws5qdqh 13TkNC1S8WTsgqZxLcyt7is4wvEx0Klefsk+X6/YP4fjoytWTgIn2XgvvpdAz/xbK/1t qsOg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:message-id:date:subject:cc:to :from; bh=xDQeo09mfwITDCXGCIusjJXLBsPF/n8d1m2rVQ/3jzQ=; fh=doHb74d47P4sKsmuiL7Edc4iE1FsHLwjN+J1Q4uZNJ8=; b=Fw5zMdf7ldqkIssPhT6aVcH3hnD1ffFMY44wwyfm3JPKsEjMO7afjXjlwwlhGUJhTn 8Zpl/+0ZrEz08kUbBIpKM/0ERZG/NFcLSyGPkZFiu2YCNBlHMqahwTUjd5MDEzjh1S3c LhXakm7/qsC+U2KSavocTczlYpMN9tC4+TSGw37HNhVJIFeToOuUsbnzQMXiflUrJ19j R+s2WJFCJEiYmdT9e9drkD6zdU8ssZFfFbi1l3w/aYvHQA1sU3w6N9Q2M3CKNG74hofb 5apXZ9DVUhh17YP3Cu+edoZ5NGEVaFb6IQRXdxx7iiFmxvFXyMSMeMXV64GZIW/QZlOB 39DA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel+bounces-13049-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-13049-linux.lists.archive=gmail.com@vger.kernel.org" Return-Path: Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [147.75.199.223]) by mx.google.com with ESMTPS id b13-20020a0cc98d000000b0067f2120275dsi19784185qvk.542.2023.12.29.02.55.02 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 29 Dec 2023 02:55:02 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-13049-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) client-ip=147.75.199.223; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel+bounces-13049-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-13049-linux.lists.archive=gmail.com@vger.kernel.org" Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 151CE1C21784 for ; Fri, 29 Dec 2023 10:55:02 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id EFC2010A3A; Fri, 29 Dec 2023 10:54:53 +0000 (UTC) X-Original-To: linux-kernel@vger.kernel.org Received: from cae.in-ulm.de (cae.in-ulm.de [217.10.14.231]) by smtp.subspace.kernel.org (Postfix) with ESMTP id BD35C10A1A; Fri, 29 Dec 2023 10:54:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=c--e.de Received: by cae.in-ulm.de (Postfix, from userid 1000) id 0D6F71402B9; Fri, 29 Dec 2023 11:54:42 +0100 (CET) From: "Christian A. Ehrhardt" To: devicetree@vger.kernel.org Cc: "Christian A. Ehrhardt" , Stephen Boyd , Rob Herring , Frank Rowand , linux-kernel@vger.kernel.org Subject: [PATCH] of: Fix double free in of_parse_phandle_with_args_map Date: Fri, 29 Dec 2023 11:54:11 +0100 Message-Id: <20231229105411.1603434-1-lk@c--e.de> X-Mailer: git-send-email 2.30.2 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit In of_parse_phandle_with_args_map() the inner loop that iterates through the map entries calls of_node_put(new) to free the reference acquired by the previous iteration of the inner loop. This assumes that the value of "new" is NULL on the first iteration of the inner loop. Make sure that this is true in all iterations of the outer loop by setting "new" to NULL after its value is assigned to "cur". Extend the unittest to detect the double free and add an additional test case that actually triggers this path. Fixes: bd6f2fd5a1 ("of: Support parsing phandle argument lists through a nexus node") Cc: Stephen Boyd Signed-off-by: Christian A. Ehrhardt --- drivers/of/base.c | 1 + drivers/of/unittest-data/tests-phandle.dtsi | 10 ++- drivers/of/unittest.c | 74 ++++++++++++--------- 3 files changed, 53 insertions(+), 32 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index 8d93cb6ea9cd..b0ad8fc06e80 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1464,6 +1464,7 @@ int of_parse_phandle_with_args_map(const struct device_node *np, out_args->np = new; of_node_put(cur); cur = new; + new = NULL; } put: of_node_put(cur); diff --git a/drivers/of/unittest-data/tests-phandle.dtsi b/drivers/of/unittest-data/tests-phandle.dtsi index d01f92f0f0db..554a996b2ef1 100644 --- a/drivers/of/unittest-data/tests-phandle.dtsi +++ b/drivers/of/unittest-data/tests-phandle.dtsi @@ -40,6 +40,13 @@ provider4: provider4 { phandle-map-pass-thru = <0x0 0xf0>; }; + provider5: provider5 { + #phandle-cells = <2>; + phandle-map = <2 7 &provider4 2 3>; + phandle-map-mask = <0xff 0xf>; + phandle-map-pass-thru = <0x0 0xf0>; + }; + consumer-a { phandle-list = <&provider1 1>, <&provider2 2 0>, @@ -66,7 +73,8 @@ consumer-b { <&provider4 4 0x100>, <&provider4 0 0x61>, <&provider0>, - <&provider4 19 0x20>; + <&provider4 19 0x20>, + <&provider5 2 7>; phandle-list-bad-phandle = <12345678 0 0>; phandle-list-bad-args = <&provider2 1 0>, <&provider4 0>; diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index e9e90e96600e..45bd0d28c717 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -456,6 +456,9 @@ static void __init of_unittest_parse_phandle_with_args(void) unittest(passed, "index %i - data error on node %pOF rc=%i\n", i, args.np, rc); + + if (rc == 0) + of_node_put(args.np); } /* Check for missing list property */ @@ -545,8 +548,9 @@ static void __init of_unittest_parse_phandle_with_args(void) static void __init of_unittest_parse_phandle_with_args_map(void) { - struct device_node *np, *p0, *p1, *p2, *p3; + struct device_node *np, *p[6] = {}; struct of_phandle_args args; + unsigned int prefs[6]; int i, rc; np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-b"); @@ -555,34 +559,24 @@ static void __init of_unittest_parse_phandle_with_args_map(void) return; } - p0 = of_find_node_by_path("/testcase-data/phandle-tests/provider0"); - if (!p0) { - pr_err("missing testcase data\n"); - return; - } - - p1 = of_find_node_by_path("/testcase-data/phandle-tests/provider1"); - if (!p1) { - pr_err("missing testcase data\n"); - return; - } - - p2 = of_find_node_by_path("/testcase-data/phandle-tests/provider2"); - if (!p2) { - pr_err("missing testcase data\n"); - return; - } - - p3 = of_find_node_by_path("/testcase-data/phandle-tests/provider3"); - if (!p3) { - pr_err("missing testcase data\n"); - return; + p[0] = of_find_node_by_path("/testcase-data/phandle-tests/provider0"); + p[1] = of_find_node_by_path("/testcase-data/phandle-tests/provider1"); + p[2] = of_find_node_by_path("/testcase-data/phandle-tests/provider2"); + p[3] = of_find_node_by_path("/testcase-data/phandle-tests/provider3"); + p[4] = of_find_node_by_path("/testcase-data/phandle-tests/provider4"); + p[5] = of_find_node_by_path("/testcase-data/phandle-tests/provider5"); + for (i = 0; i < ARRAY_SIZE(p); ++i) { + if (!p[i]) { + pr_err("missing testcase data\n"); + return; + } + prefs[i] = kref_read(&p[i]->kobj.kref); } rc = of_count_phandle_with_args(np, "phandle-list", "#phandle-cells"); - unittest(rc == 7, "of_count_phandle_with_args() returned %i, expected 7\n", rc); + unittest(rc == 8, "of_count_phandle_with_args() returned %i, expected 7\n", rc); - for (i = 0; i < 8; i++) { + for (i = 0; i < 9; i++) { bool passed = true; memset(&args, 0, sizeof(args)); @@ -593,13 +587,13 @@ static void __init of_unittest_parse_phandle_with_args_map(void) switch (i) { case 0: passed &= !rc; - passed &= (args.np == p1); + passed &= (args.np == p[1]); passed &= (args.args_count == 1); passed &= (args.args[0] == 1); break; case 1: passed &= !rc; - passed &= (args.np == p3); + passed &= (args.np == p[3]); passed &= (args.args_count == 3); passed &= (args.args[0] == 2); passed &= (args.args[1] == 5); @@ -610,28 +604,36 @@ static void __init of_unittest_parse_phandle_with_args_map(void) break; case 3: passed &= !rc; - passed &= (args.np == p0); + passed &= (args.np == p[0]); passed &= (args.args_count == 0); break; case 4: passed &= !rc; - passed &= (args.np == p1); + passed &= (args.np == p[1]); passed &= (args.args_count == 1); passed &= (args.args[0] == 3); break; case 5: passed &= !rc; - passed &= (args.np == p0); + passed &= (args.np == p[0]); passed &= (args.args_count == 0); break; case 6: passed &= !rc; - passed &= (args.np == p2); + passed &= (args.np == p[2]); passed &= (args.args_count == 2); passed &= (args.args[0] == 15); passed &= (args.args[1] == 0x20); break; case 7: + passed &= !rc; + passed &= (args.np == p[3]); + passed &= (args.args_count == 3); + passed &= (args.args[0] == 2); + passed &= (args.args[1] == 5); + passed &= (args.args[2] == 3); + break; + case 8: passed &= (rc == -ENOENT); break; default: @@ -640,6 +642,9 @@ static void __init of_unittest_parse_phandle_with_args_map(void) unittest(passed, "index %i - data error on node %s rc=%i\n", i, args.np->full_name, rc); + + if (rc == 0) + of_node_put(args.np); } /* Check for missing list property */ @@ -686,6 +691,13 @@ static void __init of_unittest_parse_phandle_with_args_map(void) "OF: /testcase-data/phandle-tests/consumer-b: #phandle-cells = 2 found 1"); unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); + + for (i = 0; i < ARRAY_SIZE(p); ++i) { + unittest(prefs[i] == kref_read(&p[i]->kobj.kref), + "provider%d: expected:%d got:%d\n", + i, prefs[i], kref_read(&p[i]->kobj.kref)); + of_node_put(p[i]); + } } static void __init of_unittest_property_string(void) -- 2.40.1