From nobody Mon May 11 08:31:17 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 85241C433FE for ; Sun, 10 Apr 2022 21:08:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242543AbiDJVLD (ORCPT ); Sun, 10 Apr 2022 17:11:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53908 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238437AbiDJVK6 (ORCPT ); Sun, 10 Apr 2022 17:10:58 -0400 Received: from mail-qt1-x831.google.com (mail-qt1-x831.google.com [IPv6:2607:f8b0:4864:20::831]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AE7F438B5; Sun, 10 Apr 2022 14:08:45 -0700 (PDT) Received: by mail-qt1-x831.google.com with SMTP id a11so14854398qtb.12; Sun, 10 Apr 2022 14:08:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=UGOgmbV2CLj8jxKDcZFdYmxwAkEUAqPnFZxawLKIrm8=; b=RKiAvUofz1qqPGjlMc79ZwKPUQBcu/PESY9kOZ7xBH2MiQkgnmGbrni1x/E3uCzZnS JBtPGVeUoA03f+iCDvw6Z8k7JpMtbKnOxk23pdAbK6SIfGxDL+07POT5yyxsghrCLUdJ Ndnb3eBPpzw4XJ7heZGxyu9lvB+GCFqHYZ+wi6F9nDRG6TrCxra/kx66LNs0pykTGm07 V+049MERVlaKt/4HveG50op1slwTJ81Nt3lPk6Q17a8PcYXPXv7kdoYqyHFYzOM4NqQa rQwuBKDhDgu/+8dCTiUMwlDc2UE4hgKi7YPIhhRsO2d/vTw2fJ3+NidsVZyKBPb25EcX VYKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=UGOgmbV2CLj8jxKDcZFdYmxwAkEUAqPnFZxawLKIrm8=; b=bHCdW3g01/8fW3kZ871gGcWV17DiQeHGBWP/5v2IBapjTztZsmAn6h/kCJ9kuvS/OC u2KIApSUe0K2nRXXHUDP/ow9mZDlvmaCYTSZoWjrYhrtElM9eQszkkRr2zPtUeqUN/kw Tm3h5qwAJF4Run0Y8S4bjK5BRkoS7PiH9Vl615z6GHfdsFtS0wATEw+SkvEvp/gI/DCG b5IU1z9kTRXZYtJDOw0OUCJxN9m8PpFUJrIEbsAcnXGi+1HoEpWkrgrYQOcf/cDVuBtP q4CViXHC+Dv8g56nvjGnIixkDmukZ2f0weDgO6Glt6EJykLZtBiYv4AwHqpwg8vpi6BA LahQ== X-Gm-Message-State: AOAM5327BU42NKy0204Xg7i26hwKeAR3UiFacF2hdh2Mu4gTZ4gsgOdy 1lZrV9/fcilemmwn9qiz3LvVU4ZXt9Q= X-Google-Smtp-Source: ABdhPJwKUYMObRXAUYWzR1OfP0IelkXJeikqH0pz09FM+XxPDHn9lgcTMejxfZwu1iXwHWxG8/LpBQ== X-Received: by 2002:a05:622a:64a:b0:2e1:d8b4:c6a1 with SMTP id a10-20020a05622a064a00b002e1d8b4c6a1mr23705422qtb.0.1649624924745; Sun, 10 Apr 2022 14:08:44 -0700 (PDT) Received: from xps8900.attlocal.net ([2600:1700:2442:6db0:b84e:f99c:2a1b:100b]) by smtp.gmail.com with ESMTPSA id i68-20020a375447000000b006809e0adfffsm18438090qkb.25.2022.04.10.14.08.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 10 Apr 2022 14:08:44 -0700 (PDT) From: frowand.list@gmail.com To: Rob Herring , pantelis.antoniou@konsulko.com, Slawomir Stepien Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Slawomir Stepien , Geert Uytterhoeven , Alan Tull Subject: [PATCH v2 1/2] of: overlay: rename variables to be consistent Date: Sun, 10 Apr 2022 16:08:32 -0500 Message-Id: <20220410210833.441504-2-frowand.list@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220410210833.441504-1-frowand.list@gmail.com> References: <20220410210833.441504-1-frowand.list@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Frank Rowand Variables change name across function calls when there is not a good reason to do so. Fix by changing "fdt" to "new_fdt" and "tree" to "overlay_tree". The name disparity was confusing when creating the following commit. The name changes are in this separate commit to make review of the following commmit less complex. Signed-off-by: Frank Rowand Reviewed-by: Slawomir Stepien --- Changes since v1: - This patch is added to the series. drivers/of/overlay.c | 94 ++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index d80160cf34bb..f74aa9ff67aa 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -57,7 +57,7 @@ struct fragment { * struct overlay_changeset * @id: changeset identifier * @ovcs_list: list on which we are located - * @fdt: base of memory allocated to hold aligned FDT that was unflattene= d to create @overlay_tree + * @new_fdt: Memory allocated to hold unflattened aligned FDT * @overlay_tree: expanded device tree that contains the fragment nodes * @count: count of fragment structures * @fragments: fragment nodes in the overlay expanded device tree @@ -67,7 +67,7 @@ struct fragment { struct overlay_changeset { int id; struct list_head ovcs_list; - const void *fdt; + const void *new_fdt; struct device_node *overlay_tree; int count; struct fragment *fragments; @@ -718,19 +718,20 @@ static struct device_node *find_target(struct device_= node *info_node) =20 /** * init_overlay_changeset() - initialize overlay changeset from overlay tr= ee - * @ovcs: Overlay changeset to build - * @fdt: base of memory allocated to hold aligned FDT that was unflattened= to create @tree - * @tree: Contains the overlay fragments and overlay fixup nodes + * @ovcs: Overlay changeset to build + * @new_fdt: Memory allocated to hold unflattened aligned FDT + * @overlay_tree: Contains the overlay fragments and overlay fixup nodes * * Initialize @ovcs. Populate @ovcs->fragments with node information from - * the top level of @tree. The relevant top level nodes are the fragment - * nodes and the __symbols__ node. Any other top level node will be ignor= ed. + * the top level of @overlay_tree. The relevant top level nodes are the + * fragment nodes and the __symbols__ node. Any other top level node will + * be ignored. * * Return: 0 on success, -ENOMEM if memory allocation failure, -EINVAL if = error - * detected in @tree, or -ENOSPC if idr_alloc() error. + * detected in @overlay_tree, or -ENOSPC if idr_alloc() error. */ static int init_overlay_changeset(struct overlay_changeset *ovcs, - const void *fdt, struct device_node *tree) + const void *new_fdt, struct device_node *overlay_tree) { struct device_node *node, *overlay_node; struct fragment *fragment; @@ -741,17 +742,17 @@ static int init_overlay_changeset(struct overlay_chan= geset *ovcs, * Warn for some issues. Can not return -EINVAL for these until * of_unittest_apply_overlay() is fixed to pass these checks. */ - if (!of_node_check_flag(tree, OF_DYNAMIC)) - pr_debug("%s() tree is not dynamic\n", __func__); + if (!of_node_check_flag(overlay_tree, OF_DYNAMIC)) + pr_debug("%s() overlay_tree is not dynamic\n", __func__); =20 - if (!of_node_check_flag(tree, OF_DETACHED)) - pr_debug("%s() tree is not detached\n", __func__); + if (!of_node_check_flag(overlay_tree, OF_DETACHED)) + pr_debug("%s() overlay_tree is not detached\n", __func__); =20 - if (!of_node_is_root(tree)) - pr_debug("%s() tree is not root\n", __func__); + if (!of_node_is_root(overlay_tree)) + pr_debug("%s() overlay_tree is not root\n", __func__); =20 - ovcs->overlay_tree =3D tree; - ovcs->fdt =3D fdt; + ovcs->overlay_tree =3D overlay_tree; + ovcs->new_fdt =3D new_fdt; =20 INIT_LIST_HEAD(&ovcs->ovcs_list); =20 @@ -764,7 +765,7 @@ static int init_overlay_changeset(struct overlay_change= set *ovcs, cnt =3D 0; =20 /* fragment nodes */ - for_each_child_of_node(tree, node) { + for_each_child_of_node(overlay_tree, node) { overlay_node =3D of_get_child_by_name(node, "__overlay__"); if (overlay_node) { cnt++; @@ -772,7 +773,7 @@ static int init_overlay_changeset(struct overlay_change= set *ovcs, } } =20 - node =3D of_get_child_by_name(tree, "__symbols__"); + node =3D of_get_child_by_name(overlay_tree, "__symbols__"); if (node) { cnt++; of_node_put(node); @@ -785,7 +786,7 @@ static int init_overlay_changeset(struct overlay_change= set *ovcs, } =20 cnt =3D 0; - for_each_child_of_node(tree, node) { + for_each_child_of_node(overlay_tree, node) { overlay_node =3D of_get_child_by_name(node, "__overlay__"); if (!overlay_node) continue; @@ -807,7 +808,7 @@ static int init_overlay_changeset(struct overlay_change= set *ovcs, * if there is a symbols fragment in ovcs->fragments[i] it is * the final element in the array */ - node =3D of_get_child_by_name(tree, "__symbols__"); + node =3D of_get_child_by_name(overlay_tree, "__symbols__"); if (node) { ovcs->symbols_fragment =3D 1; fragment =3D &fragments[cnt]; @@ -862,11 +863,11 @@ static void free_overlay_changeset(struct overlay_cha= ngeset *ovcs) kfree(ovcs->fragments); /* * There should be no live pointers into ovcs->overlay_tree and - * ovcs->fdt due to the policy that overlay notifiers are not allowed - * to retain pointers into the overlay devicetree. + * ovcs->new_fdt due to the policy that overlay notifiers are not + * allowed to retain pointers into the overlay devicetree. */ kfree(ovcs->overlay_tree); - kfree(ovcs->fdt); + kfree(ovcs->new_fdt); kfree(ovcs); } =20 @@ -874,16 +875,15 @@ static void free_overlay_changeset(struct overlay_cha= ngeset *ovcs) * internal documentation * * of_overlay_apply() - Create and apply an overlay changeset - * @fdt: base of memory allocated to hold the aligned FDT - * @tree: Expanded overlay device tree - * @ovcs_id: Pointer to overlay changeset id + * @new_fdt: Memory allocated to hold the aligned FDT + * @overlay_tree: Expanded overlay device tree + * @ovcs_id: Pointer to overlay changeset id * * Creates and applies an overlay changeset. * * If an error occurs in a pre-apply notifier, then no changes are made * to the device tree. * - * A non-zero return value will not have created the changeset if error is= from: * - parameter checks * - building the changeset @@ -913,29 +913,29 @@ static void free_overlay_changeset(struct overlay_cha= ngeset *ovcs) * id is returned to *ovcs_id. */ =20 -static int of_overlay_apply(const void *fdt, struct device_node *tree, - int *ovcs_id) +static int of_overlay_apply(const void *new_fdt, + struct device_node *overlay_tree, int *ovcs_id) { struct overlay_changeset *ovcs; int ret =3D 0, ret_revert, ret_tmp; =20 /* - * As of this point, fdt and tree belong to the overlay changeset. - * overlay changeset code is responsible for freeing them. + * As of this point, new_fdt and overlay_tree belong to the overlay + * changeset. overlay changeset code is responsible for freeing them. */ =20 if (devicetree_corrupt()) { pr_err("devicetree state suspect, refuse to apply overlay\n"); - kfree(fdt); - kfree(tree); + kfree(new_fdt); + kfree(overlay_tree); ret =3D -EBUSY; goto out; } =20 ovcs =3D kzalloc(sizeof(*ovcs), GFP_KERNEL); if (!ovcs) { - kfree(fdt); - kfree(tree); + kfree(new_fdt); + kfree(overlay_tree); ret =3D -ENOMEM; goto out; } @@ -943,20 +943,20 @@ static int of_overlay_apply(const void *fdt, struct d= evice_node *tree, of_overlay_mutex_lock(); mutex_lock(&of_mutex); =20 - ret =3D of_resolve_phandles(tree); + ret =3D of_resolve_phandles(overlay_tree); if (ret) - goto err_free_tree; + goto err_free_overlay_tree; =20 - ret =3D init_overlay_changeset(ovcs, fdt, tree); + ret =3D init_overlay_changeset(ovcs, new_fdt, overlay_tree); if (ret) - goto err_free_tree; + goto err_free_overlay_tree; =20 /* * after overlay_notify(), ovcs->overlay_tree related pointers may have - * leaked to drivers, so can not kfree() tree, aka ovcs->overlay_tree; - * and can not free memory containing aligned fdt. The aligned fdt - * is contained within the memory at ovcs->fdt, possibly at an offset - * from ovcs->fdt. + * leaked to drivers, so can not kfree() overlay_tree, + * aka ovcs->overlay_tree; and can not free memory containing aligned + * fdt. The aligned fdt is contained within the memory at + * ovcs->new_fdt, possibly at an offset from ovcs->new_fdt. */ ret =3D overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY); if (ret) { @@ -997,9 +997,9 @@ static int of_overlay_apply(const void *fdt, struct dev= ice_node *tree, =20 goto out_unlock; =20 -err_free_tree: - kfree(fdt); - kfree(tree); +err_free_overlay_tree: + kfree(new_fdt); + kfree(overlay_tree); =20 err_free_overlay_changeset: free_overlay_changeset(ovcs); --=20 Frank Rowand From nobody Mon May 11 08:31:17 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0166CC433F5 for ; Sun, 10 Apr 2022 21:08:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243968AbiDJVLH (ORCPT ); Sun, 10 Apr 2022 17:11:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53910 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241593AbiDJVK7 (ORCPT ); Sun, 10 Apr 2022 17:10:59 -0400 Received: from mail-qt1-x82a.google.com (mail-qt1-x82a.google.com [IPv6:2607:f8b0:4864:20::82a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7F95338B7; Sun, 10 Apr 2022 14:08:46 -0700 (PDT) Received: by mail-qt1-x82a.google.com with SMTP id z19so14985239qtw.2; Sun, 10 Apr 2022 14:08:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=xWkr4DFlx01fPPCwi+Q0C0zXCNWMhK+7LCAOf/zv59o=; b=hJ0m1T3+AjPWa6fU/LEEtAbiTWaqrPvbbJueSG7J/oRmJZW9HhTK3zAcDUBW0ktk6d bCuUKmB691JBzFsC35fEiDAQzyHGMI4XpCaMKtj9PiFwCKAhKqVuns6O1Qc7zga4ir24 jGpYkJ38WQjv1CAA7H3EfTBKG8DcMCsdxvW1UmDEwHkXIaFGGst0RH2TceLOldC8SvRF 8sW58DYOAbrA4INOUGmBa1QO/3Y85TbHmR1wFGOOK9h1NiT5XXrBWYOi0LtOgubg+8RH +NCmGWten+WnZzq9r5BnjDxlJLBJ1MBVZXtJ6/bW8W/pkHUAnDCDlfpsUYDvVG7tXikK 5hIg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=xWkr4DFlx01fPPCwi+Q0C0zXCNWMhK+7LCAOf/zv59o=; b=XdQrF9pNdkgMbHF4b6+q7Akb628XQg5/8UeXxcJhbDAmKM2syFUTbp1MLays+1Fd3z uEG5xS1jEwcQlt6y4bWeUGmOq43Jz+Z6EBKtbwJoLZGfi7o6CnoQuvBx5nxyBihQ/48j zT3X4MOOk5QA8BLmB46wVfdX/V7Wx5wPIDzR+IxXDYdCu2YpAWkffN/D9MyEmv2pJZ4d mvhy+ksysPwM2JA/Oe95F/VWp02wdTVOwHbCJEg0n40zH/Ji3tLapNkAJfuuqNQBHIx1 5BBhev6mAMQfDnJXtb7ztoMq1ip7vt/wqNl73DB5X59LIm2sNIwS2CENIiS/cJtUyqGK 3dIQ== X-Gm-Message-State: AOAM533GIrt2xvgDOyxkOJIHtUBkjpsD5KnEwFEKFTI/+jlG5+rW5MDQ 4Hk7hSSyYk4+2szp2BpyCmg= X-Google-Smtp-Source: ABdhPJz1dSIp/hyQxUAgZaMClPy1NgpDU9exRGMwC/zrbB/B5rvSOM9xD3+YsMOUvRq6cyM449OP0A== X-Received: by 2002:a05:622a:1443:b0:2eb:b4b7:c3b with SMTP id v3-20020a05622a144300b002ebb4b70c3bmr23397702qtx.574.1649624925527; Sun, 10 Apr 2022 14:08:45 -0700 (PDT) Received: from xps8900.attlocal.net ([2600:1700:2442:6db0:b84e:f99c:2a1b:100b]) by smtp.gmail.com with ESMTPSA id i68-20020a375447000000b006809e0adfffsm18438090qkb.25.2022.04.10.14.08.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 10 Apr 2022 14:08:45 -0700 (PDT) From: frowand.list@gmail.com To: Rob Herring , pantelis.antoniou@konsulko.com, Slawomir Stepien Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Slawomir Stepien , Geert Uytterhoeven , Alan Tull Subject: [PATCH v2 2/2] of: overlay: rework overlay apply and remove kfree()s Date: Sun, 10 Apr 2022 16:08:33 -0500 Message-Id: <20220410210833.441504-3-frowand.list@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220410210833.441504-1-frowand.list@gmail.com> References: <20220410210833.441504-1-frowand.list@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Frank Rowand Fix various kfree() issues related to of_overlay_apply(). - Double kfree() of fdt and tree when init_overlay_changeset() returns an error. - free_overlay_changeset() free the root of the unflattened overlay (variable tree) instead of the memory that contains the unflattened overlay. - For the case of a failure during applying an overlay, move kfree() of new_fdt and overlay_mem into the function that allocated them. For the case of removing an overlay, the kfree() remains in free_overlay_changeset(). - Check return value of of_fdt_unflatten_tree() for error instead of checking the returnded value of overlay_root. More clearly document policy related to lifetime of pointers into overlay memory. Double kfree() Reported-by: Slawomir Stepien Signed-off-by: Frank Rowand Reviewed-by: Slawomir Stepien --- Changes since v1: - Move kfree()s from init_overlay_changeset() to of_overlay_fdt_apply() - Better document lifetime of pointers into overlay, both in overlay.c and Documentation/devicetree/overlay-notes.rst Documentation/devicetree/overlay-notes.rst | 23 +++- drivers/of/overlay.c | 127 ++++++++++++--------- 2 files changed, 91 insertions(+), 59 deletions(-) diff --git a/Documentation/devicetree/overlay-notes.rst b/Documentation/dev= icetree/overlay-notes.rst index b2b8db765b8c..7a6e85f75567 100644 --- a/Documentation/devicetree/overlay-notes.rst +++ b/Documentation/devicetree/overlay-notes.rst @@ -119,10 +119,25 @@ Finally, if you need to remove all overlays in one-go= , just call of_overlay_remove_all() which will remove every single one in the correct order. =20 -In addition, there is the option to register notifiers that get called on +There is the option to register notifiers that get called on overlay operations. See of_overlay_notifier_register/unregister and enum of_overlay_notify_action for details. =20 -Note that a notifier callback is not supposed to store pointers to a device -tree node or its content beyond OF_OVERLAY_POST_REMOVE corresponding to the -respective node it received. +A notifier callback for OF_OVERLAY_PRE_APPLY, OF_OVERLAY_POST_APPLY, or +OF_OVERLAY_PRE_REMOVE may store pointers to a device tree node in the over= lay +or its content but these pointers must not persist past the notifier callb= ack +for OF_OVERLAY_POST_REMOVE. The memory containing the overlay will be +kfree()ed after OF_OVERLAY_POST_REMOVE notifiers are called. Note that the +memory will be kfree()ed even if the notifier for OF_OVERLAY_POST_REMOVE +returns an error. + +The changeset notifiers in drivers/of/dynamic.c are a second type of notif= ier +that could be triggered by applying or removing an overlay. These notifie= rs +are not allowed to store pointers to a device tree node in the overlay +or its content. The overlay code does not protect against such pointers +remaining active when the memory containing the overlay is freed as a resu= lt +of removing the overlay. + +Any other code that retains a pointer to the overlay nodes or data is +considered to be a bug because after removing the overlay the pointer +will refer to freed memory. diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index f74aa9ff67aa..c8e999518f2f 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -58,6 +58,7 @@ struct fragment { * @id: changeset identifier * @ovcs_list: list on which we are located * @new_fdt: Memory allocated to hold unflattened aligned FDT + * @overlay_mem: the memory chunk that contains @overlay_tree * @overlay_tree: expanded device tree that contains the fragment nodes * @count: count of fragment structures * @fragments: fragment nodes in the overlay expanded device tree @@ -68,6 +69,7 @@ struct overlay_changeset { int id; struct list_head ovcs_list; const void *new_fdt; + const void *overlay_mem; struct device_node *overlay_tree; int count; struct fragment *fragments; @@ -720,18 +722,20 @@ static struct device_node *find_target(struct device_= node *info_node) * init_overlay_changeset() - initialize overlay changeset from overlay tr= ee * @ovcs: Overlay changeset to build * @new_fdt: Memory allocated to hold unflattened aligned FDT + * @tree_mem: Memory that contains @overlay_tree * @overlay_tree: Contains the overlay fragments and overlay fixup nodes * * Initialize @ovcs. Populate @ovcs->fragments with node information from * the top level of @overlay_tree. The relevant top level nodes are the * fragment nodes and the __symbols__ node. Any other top level node will - * be ignored. + * be ignored. Populate other @ovcs fields. * * Return: 0 on success, -ENOMEM if memory allocation failure, -EINVAL if = error * detected in @overlay_tree, or -ENOSPC if idr_alloc() error. */ static int init_overlay_changeset(struct overlay_changeset *ovcs, - const void *new_fdt, struct device_node *overlay_tree) + const void *new_fdt, const void *tree_mem, + struct device_node *overlay_tree) { struct device_node *node, *overlay_node; struct fragment *fragment; @@ -751,9 +755,6 @@ static int init_overlay_changeset(struct overlay_change= set *ovcs, if (!of_node_is_root(overlay_tree)) pr_debug("%s() overlay_tree is not root\n", __func__); =20 - ovcs->overlay_tree =3D overlay_tree; - ovcs->new_fdt =3D new_fdt; - INIT_LIST_HEAD(&ovcs->ovcs_list); =20 of_changeset_init(&ovcs->cset); @@ -832,6 +833,9 @@ static int init_overlay_changeset(struct overlay_change= set *ovcs, =20 ovcs->id =3D id; ovcs->count =3D cnt; + ovcs->new_fdt =3D new_fdt; + ovcs->overlay_mem =3D tree_mem; + ovcs->overlay_tree =3D overlay_tree; ovcs->fragments =3D fragments; =20 return 0; @@ -846,7 +850,7 @@ static int init_overlay_changeset(struct overlay_change= set *ovcs, return ret; } =20 -static void free_overlay_changeset(struct overlay_changeset *ovcs) +static void free_overlay_changeset_contents(struct overlay_changeset *ovcs) { int i; =20 @@ -861,12 +865,20 @@ static void free_overlay_changeset(struct overlay_cha= ngeset *ovcs) of_node_put(ovcs->fragments[i].overlay); } kfree(ovcs->fragments); +} +static void free_overlay_changeset(struct overlay_changeset *ovcs) +{ + + free_overlay_changeset_contents(ovcs); + /* - * There should be no live pointers into ovcs->overlay_tree and + * There should be no live pointers into ovcs->overlay_mem and * ovcs->new_fdt due to the policy that overlay notifiers are not - * allowed to retain pointers into the overlay devicetree. + * allowed to retain pointers into the overlay devicetree other + * than the window between OF_OVERLAY_PRE_APPLY overlay notifiers + * and the OF_OVERLAY_POST_REMOVE overlay notifiers. */ - kfree(ovcs->overlay_tree); + kfree(ovcs->overlay_mem); kfree(ovcs->new_fdt); kfree(ovcs); } @@ -876,8 +888,10 @@ static void free_overlay_changeset(struct overlay_chan= geset *ovcs) * * of_overlay_apply() - Create and apply an overlay changeset * @new_fdt: Memory allocated to hold the aligned FDT + * @tree_mem: Memory that contains @overlay_tree * @overlay_tree: Expanded overlay device tree * @ovcs_id: Pointer to overlay changeset id + * @kfree_unsafe: Pointer to flag to not kfree() @new_fdt and @overlay_tree * * Creates and applies an overlay changeset. * @@ -910,34 +924,25 @@ static void free_overlay_changeset(struct overlay_cha= ngeset *ovcs) * refused. * * Returns 0 on success, or a negative error number. Overlay changeset - * id is returned to *ovcs_id. + * id is returned to *ovcs_id. When references to @new_fdt and @overlay_t= ree + * may exist, *kfree_unsafe is set to true. */ =20 -static int of_overlay_apply(const void *new_fdt, - struct device_node *overlay_tree, int *ovcs_id) +static int of_overlay_apply(const void *new_fdt, void *tree_mem, + struct device_node *overlay_tree, int *ovcs_id, + bool *kfree_unsafe) { struct overlay_changeset *ovcs; int ret =3D 0, ret_revert, ret_tmp; =20 - /* - * As of this point, new_fdt and overlay_tree belong to the overlay - * changeset. overlay changeset code is responsible for freeing them. - */ - if (devicetree_corrupt()) { pr_err("devicetree state suspect, refuse to apply overlay\n"); - kfree(new_fdt); - kfree(overlay_tree); - ret =3D -EBUSY; - goto out; + return -EBUSY; } =20 ovcs =3D kzalloc(sizeof(*ovcs), GFP_KERNEL); if (!ovcs) { - kfree(new_fdt); - kfree(overlay_tree); - ret =3D -ENOMEM; - goto out; + return -ENOMEM; } =20 of_overlay_mutex_lock(); @@ -945,28 +950,27 @@ static int of_overlay_apply(const void *new_fdt, =20 ret =3D of_resolve_phandles(overlay_tree); if (ret) - goto err_free_overlay_tree; + goto err_free_ovcs; =20 - ret =3D init_overlay_changeset(ovcs, new_fdt, overlay_tree); + ret =3D init_overlay_changeset(ovcs, new_fdt, tree_mem, overlay_tree); if (ret) - goto err_free_overlay_tree; + goto err_free_ovcs_contents; =20 /* - * after overlay_notify(), ovcs->overlay_tree related pointers may have - * leaked to drivers, so can not kfree() overlay_tree, - * aka ovcs->overlay_tree; and can not free memory containing aligned - * fdt. The aligned fdt is contained within the memory at - * ovcs->new_fdt, possibly at an offset from ovcs->new_fdt. + * After overlay_notify(), ovcs->overlay_tree related pointers may have + * leaked to drivers, so can not kfree() ovcs->overlay_mem and + * ovcs->new_fdt until after OF_OVERLAY_POST_REMOVE notifiers. */ + *kfree_unsafe =3D true; ret =3D overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY); if (ret) { pr_err("overlay changeset pre-apply notify error %d\n", ret); - goto err_free_overlay_changeset; + goto err_free_ovcs_contents; } =20 ret =3D build_changeset(ovcs); if (ret) - goto err_free_overlay_changeset; + goto err_free_ovcs_contents; =20 ret_revert =3D 0; ret =3D __of_changeset_apply_entries(&ovcs->cset, &ret_revert); @@ -976,7 +980,7 @@ static int of_overlay_apply(const void *new_fdt, ret_revert); devicetree_state_flags |=3D DTSF_APPLY_FAIL; } - goto err_free_overlay_changeset; + goto err_free_ovcs_contents; } =20 ret =3D __of_changeset_apply_notify(&ovcs->cset); @@ -997,18 +1001,16 @@ static int of_overlay_apply(const void *new_fdt, =20 goto out_unlock; =20 -err_free_overlay_tree: - kfree(new_fdt); - kfree(overlay_tree); +err_free_ovcs_contents: + free_overlay_changeset_contents(ovcs); =20 -err_free_overlay_changeset: - free_overlay_changeset(ovcs); +err_free_ovcs: + kfree(ovcs); =20 out_unlock: mutex_unlock(&of_mutex); of_overlay_mutex_unlock(); =20 -out: pr_debug("%s() err=3D%d\n", __func__, ret); =20 return ret; @@ -1019,11 +1021,14 @@ int of_overlay_fdt_apply(const void *overlay_fdt, u= 32 overlay_fdt_size, { void *new_fdt; void *new_fdt_align; + void *overlay_mem; + bool kfree_unsafe; int ret; u32 size; struct device_node *overlay_root =3D NULL; =20 *ovcs_id =3D 0; + kfree_unsafe =3D false; =20 if (overlay_fdt_size < sizeof(struct fdt_header) || fdt_check_header(overlay_fdt)) { @@ -1046,30 +1051,37 @@ int of_overlay_fdt_apply(const void *overlay_fdt, u= 32 overlay_fdt_size, new_fdt_align =3D PTR_ALIGN(new_fdt, FDT_ALIGN_SIZE); memcpy(new_fdt_align, overlay_fdt, size); =20 - of_fdt_unflatten_tree(new_fdt_align, NULL, &overlay_root); - if (!overlay_root) { + overlay_mem =3D of_fdt_unflatten_tree(new_fdt_align, NULL, &overlay_root); + if (!overlay_mem) { pr_err("unable to unflatten overlay_fdt\n"); ret =3D -EINVAL; goto out_free_new_fdt; } =20 - ret =3D of_overlay_apply(new_fdt, overlay_root, ovcs_id); - if (ret < 0) { - /* - * new_fdt and overlay_root now belong to the overlay - * changeset. - * overlay changeset code is responsible for freeing them. - */ - goto out; - } + ret =3D of_overlay_apply(new_fdt, overlay_mem, overlay_root, ovcs_id, + &kfree_unsafe); + if (ret < 0) + goto out_free_overlay_mem; =20 + /* + * new_fdt and overlay_mem now belong to the overlay changeset. + * free_overlay_changeset() is responsible for freeing them. + */ return 0; =20 + /* + * After overlay_notify(), ovcs->overlay_tree related pointers may have + * leaked to drivers, so can not kfree() overlay_mem and new_fdt. This + * will result in a memory leak. + */ +out_free_overlay_mem: + if (!kfree_unsafe) + kfree(overlay_mem); =20 out_free_new_fdt: - kfree(new_fdt); + if (!kfree_unsafe) + kfree(new_fdt); =20 -out: return ret; } EXPORT_SYMBOL_GPL(of_overlay_fdt_apply); @@ -1237,6 +1249,11 @@ int of_overlay_remove(int *ovcs_id) =20 *ovcs_id =3D 0; =20 + /* + * Note that the overlay memory will be kfree()ed by + * free_overlay_changeset() even if the notifier for + * OF_OVERLAY_POST_REMOVE returns an error. + */ ret_tmp =3D overlay_notify(ovcs, OF_OVERLAY_POST_REMOVE); if (ret_tmp) { pr_err("overlay changeset post-remove notify error %d\n", --=20 Frank Rowand