[Concept,12/14] extlinux: Add remove() to fix pxe_context leak

Message ID 20260322235719.1729267-13-sjg@u-boot.org
State New
Headers
Series bootstd: Infrastructure for multi-entry bootflow support |

Commit Message

Simon Glass March 22, 2026, 11:57 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

The extlinux and PXE drivers allocate a pxe_context in priv but never
free it on device removal, leaking the bootdir string and any parsed
menu.

Add extlinux_bootmeth_remove() which frees the context, shared by both
drivers. Move the VBE driver to use a pxe_context embedded in its own
abrec_priv, since extlinux_plat no longer contains it.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 boot/bootmeth_extlinux.c | 12 ++++++++++++
 boot/bootmeth_pxe.c      |  1 +
 boot/vbe_abrec.h         |  4 ++++
 boot/vbe_abrec_os.c      |  8 ++++----
 include/extlinux.h       | 10 ++++++++++
 5 files changed, 31 insertions(+), 4 deletions(-)
  

Patch

diff --git a/boot/bootmeth_extlinux.c b/boot/bootmeth_extlinux.c
index ad2f32ca8a5..ca9120c3f99 100644
--- a/boot/bootmeth_extlinux.c
+++ b/boot/bootmeth_extlinux.c
@@ -233,6 +233,17 @@  static int extlinux_local_read_all(struct udevice *dev, struct bootflow *bflow)
 }
 #endif
 
+int extlinux_bootmeth_remove(struct udevice *dev)
+{
+	struct extlinux_priv *priv = dev_get_priv(dev);
+
+	if (priv->ctx.cfg)
+		pxe_menu_uninit(priv->ctx.cfg);
+	pxe_destroy_ctx(&priv->ctx);
+
+	return 0;
+}
+
 static int extlinux_bootmeth_bind(struct udevice *dev)
 {
 	struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev);
@@ -267,6 +278,7 @@  U_BOOT_DRIVER(bootmeth_1extlinux) = {
 	.of_match	= extlinux_bootmeth_ids,
 	.ops		= &extlinux_bootmeth_ops,
 	.bind		= extlinux_bootmeth_bind,
+	.remove		= extlinux_bootmeth_remove,
 	.plat_auto	= sizeof(struct extlinux_plat),
 	.priv_auto	= sizeof(struct extlinux_priv),
 };
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c
index 55e7f60c5cd..772acc9107d 100644
--- a/boot/bootmeth_pxe.c
+++ b/boot/bootmeth_pxe.c
@@ -193,6 +193,7 @@  U_BOOT_DRIVER(bootmeth_zpxe) = {
 	.of_match	= extlinux_bootmeth_pxe_ids,
 	.ops		= &extlinux_bootmeth_pxe_ops,
 	.bind		= extlinux_bootmeth_pxe_bind,
+	.remove		= extlinux_bootmeth_remove,
 	.plat_auto	= sizeof(struct extlinux_plat),
 	.priv_auto	= sizeof(struct extlinux_priv),
 };
diff --git a/boot/vbe_abrec.h b/boot/vbe_abrec.h
index 590ad3cfacb..005e64af25f 100644
--- a/boot/vbe_abrec.h
+++ b/boot/vbe_abrec.h
@@ -9,6 +9,8 @@ 
 #ifndef __VBE_ABREC_H
 #define __VBE_ABREC_H
 
+#include <pxe_utils.h>
+
 #include <vbe.h>
 #include <dm/ofnode_decl.h>
 
@@ -34,6 +36,7 @@  struct udevice;
  * @version_size: Size of the version info
  * @storage: Storage device to use, in the form <uclass><devnum>, e.g. "mmc1"
  * @oem_devicetree: true if we should read an OEM devicetree
+ * @ctx: PXE context for extlinux boot/read_all
  */
 struct abrec_priv {
 	u32 area_start;
@@ -45,6 +48,7 @@  struct abrec_priv {
 	u32 version_size;
 	const char *storage;
 	bool oem_devicetree;
+	struct pxe_context ctx;
 };
 
 /** struct abrec_state - state information read from media
diff --git a/boot/vbe_abrec_os.c b/boot/vbe_abrec_os.c
index 7d5c9bc9dcb..9d0136b059b 100644
--- a/boot/vbe_abrec_os.c
+++ b/boot/vbe_abrec_os.c
@@ -204,7 +204,7 @@  err_buf:
 
 static int vbe_abrec_boot(struct udevice *dev, struct bootflow *bflow)
 {
-	struct extlinux_plat *plat = dev_get_plat(dev);
+	struct abrec_priv *priv = dev_get_priv(dev);
 	const struct bootflow_img *img;
 	int ret;
 
@@ -231,16 +231,16 @@  static int vbe_abrec_boot(struct udevice *dev, struct bootflow *bflow)
 
 	printf("Loading OS FIT%s\n", img ? " keeping existing FDT" : "");
 
-	return extlinux_boot(dev, bflow, &plat->ctx, vbe_abrec_getfile, true,
+	return extlinux_boot(dev, bflow, &priv->ctx, vbe_abrec_getfile, true,
 			     bflow->fname, img);
 }
 
 #if CONFIG_IS_ENABLED(BOOTSTD_FULL)
 static int vbe_abrec_read_all(struct udevice *dev, struct bootflow *bflow)
 {
-	struct extlinux_plat *plat = dev_get_plat(dev);
+	struct abrec_priv *priv = dev_get_priv(dev);
 
-	return extlinux_read_all(dev, bflow, &plat->ctx, vbe_abrec_getfile,
+	return extlinux_read_all(dev, bflow, &priv->ctx, vbe_abrec_getfile,
 				 true, bflow->fname);
 }
 #endif
diff --git a/include/extlinux.h b/include/extlinux.h
index 66500f4c8cf..8630a8e3dc7 100644
--- a/include/extlinux.h
+++ b/include/extlinux.h
@@ -42,6 +42,16 @@  struct extlinux_priv {
 	struct pxe_context ctx;
 };
 
+/**
+ * extlinux_bootmeth_remove() - Remove function for extlinux-based bootmeths
+ *
+ * Frees the PXE context. Shared by extlinux and PXE drivers.
+ *
+ * @dev: Bootmethod device
+ * Return: 0 if OK
+ */
+int extlinux_bootmeth_remove(struct udevice *dev);
+
 /**
  * extlinux_set_property() - set an extlinux property
  *