Skip to contentSkip to conversation

bootconfig: Fixes to bootconfig memory management

PATCH Superseded Masami Hiramatsu 3 participants 10 messages Sep 15, 2021 – Sep 16, 2021

Subsystems (3)

v3 of 4 Superseded Latest is v4 →

lore
Share & tools
lore

Masami Hiramatsu

author maintainer
#0 lore raw

v3 cover bootconfig: Fixes to bootconfig memory management

Hello,

Here are the series of patches to fix bootconfig memory management issues. In this version, I removed unneeded patches and add a patch to free xbc_data in xbc_destroy_all().

But still I'm thinking how I can move lib/bootconfig.c and bootconfig.h to share with tools, because those functions/data are __init and __initdata. At least I have to add a dummy macro for those in userspace. Thus the tools/bootconfig build error is still there. I'll fix that in another series.

Thank you,

---

Masami Hiramatsu (3):
bootconfig: init: Fix memblock leak in xbc_make_cmdline()
bootconfig: init: Fix memblock leak in setup_boot_config()
bootconfig: Free xbc_data in xbc_destroy_all()

 init/main.c      |    2 ++
 lib/bootconfig.c |    3 +++
 2 files changed, 5 insertions(+)
Signature · 1 line
Masami Hiramatsu (Linaro) <[email protected]>
author maintainer
#1 lore raw

PATCH v3 1/3 bootconfig: init: Fix memblock leak in xbc_make_cmdline()

Free unused memblock in a error case to fix memblock leak in xbc_make_cmdline().

Fixes 51887d03aca1 ("bootconfig: init: Allow admin to use bootconfig for kernel command line")
---
 init/main.c |    1 +
 1 file changed, 1 insertion(+)
init/main.c +1 -0
index 3f7216934441..0b054fff8e92 100644
@@ -382,6 +382,7 @@ static char * __init xbc_make_cmdline(const char *key)
 	ret = xbc_snprint_cmdline(new_cmdline, len + 1, root);
 	if (ret < 0 || ret > len) {
 		pr_err("Failed to print extra kernel cmdline.\n");
+		memblock_free_ptr(new_cmdline, len + 1);
 		return NULL;
 	}
 
author maintainer
#2 lore raw

PATCH v3 2/3 bootconfig: init: Fix memblock leak in setup_boot_config()

In reply to Masami Hiramatsu

Free unused memblock in a error case to fix memblock leak in setup_boot_config().

Fixes 7684b8582c24 ("bootconfig: Load boot config from the tail of initrd")
---
 init/main.c |    1 +
 1 file changed, 1 insertion(+)
init/main.c +1 -0
index 0b054fff8e92..4f059fde1df0 100644
@@ -459,6 +459,7 @@ static void __init setup_boot_config(void)
 		else
 			pr_err("Failed to parse bootconfig: %s at %d.\n",
 				msg, pos);
+		memblock_free_ptr(copy, size + 1);
 	} else {
 		pr_info("Load bootconfig: %d bytes %d nodes\n", size, ret);
 		/* keys starting with "kernel." are passed via cmdline */
author maintainer
#3 lore raw

PATCH v3 3/3 bootconfig: Free xbc_data in xbc_destroy_all()

In reply to Masami Hiramatsu

Free xbc_data memory in xbc_destroy_all() with other data. Note that this changes the ownership of the passed bootconfig data.

---
 lib/bootconfig.c |    3 +++
 1 file changed, 3 insertions(+)
lib/bootconfig.c +3 -0
index 5ae248b29373..2ba7d945adc9 100644
@@ -789,6 +789,7 @@ static int __init xbc_verify_tree(void)
  */
 void __init xbc_destroy_all(void)
 {
+	memblock_free_ptr(xbc_data, xbc_data_size);
 	xbc_data = NULL;
 	xbc_data_size = 0;
 	xbc_node_num = 0;
@@ -810,6 +811,8 @@ void __init xbc_destroy_all(void)
  * In error cases, @emsg will be updated with an error message and
  * @epos will be updated with the error position which is the byte offset
  * of @buf. If the error is not a parser error, @epos will be -1.
+ * Note that the @buf ownership is transferred, so it will be freed
+ * in xbc_destroy_all().
  */
 int __init xbc_init(char *buf, const char **emsg, int *epos)
 {
#4 lore raw

Re: [PATCH v3 3/3] bootconfig: Free xbc_data in xbc_destroy_all()

lib/bootconfig.c void __init xbc_destroy_all(void) · line 818

Quoted 9 lines · On Wed, 15 Sep 2021 22:19:52 +0900 Masami Hiramatsu <[email protected]> wrote:
lib/bootconfig.c +2 -0
@@ -810,6 +811,8 @@ void __init xbc_destroy_all(void)
  * In error cases, @emsg will be updated with an error message and
  * @epos will be updated with the error position which is the byte offset
  * of @buf. If the error is not a parser error, @epos will be -1.
+ * Note that the @buf ownership is transferred, so it will be freed
+ * in xbc_destroy_all().
  */
 int __init xbc_init(char *buf, const char **emsg, int *epos)
 {

I hate this "ownership transfer". Looking at the use case here:

init/main.c:

	copy = memblock_alloc(size + 1, SMP_CACHE_BYTES);
	if (!copy) {
		pr_err("Failed to allocate memory for bootconfig\n");
		return;
	}

	memcpy(copy, data, size);
	copy[size] = '\0';

	ret = xbc_init(copy, &msg, &pos);
	if (ret < 0) {

Instead of having xbc_init() return the node count on success, how about having it allocate the buffer to use and then return it?

That is, move the:

	copy = memblock_alloc(size + 1, SMP_CACHE_BYTES);
	if (!copy) {
		pr_err("Failed to allocate memory for bootconfig\n");
		return;
	}

	memcpy(copy, data, size);
	copy[size] = '\0';

into xbc_init(), and have data, and size be passed to it.

Then, have it return the pointer of "copy" or NULL on error?

This will keep the semantics of xbc_* owning the buffer that gets freed by the destroy.

The xbc_init() could also do the pr_info() that prints the bytes and node count. There's no other reason to pass that node count to the caller, is there?

-- Steve

author maintainer
#5 lore raw

Re: [PATCH v3 3/3] bootconfig: Free xbc_data in xbc_destroy_all()

Quoted 43 lines · On Wed, 15 Sep 2021 10:23:54 -0400 Steven Rostedt <[email protected]> wrote:

lib/bootconfig.c void __init xbc_destroy_all(void) · line 818

Quoted 9 lines · On Wed, 15 Sep 2021 22:19:52 +0900 Masami Hiramatsu <[email protected]> wrote:
lib/bootconfig.c +2 -0
@@ -810,6 +811,8 @@ void __init xbc_destroy_all(void)
  * In error cases, @emsg will be updated with an error message and
  * @epos will be updated with the error position which is the byte offset
  * of @buf. If the error is not a parser error, @epos will be -1.
+ * Note that the @buf ownership is transferred, so it will be freed
+ * in xbc_destroy_all().
  */
 int __init xbc_init(char *buf, const char **emsg, int *epos)
 {

I hate this "ownership transfer". Looking at the use case here:

init/main.c:

	copy = memblock_alloc(size + 1, SMP_CACHE_BYTES);
	if (!copy) {
		pr_err("Failed to allocate memory for bootconfig\n");
		return;
	}

	memcpy(copy, data, size);
	copy[size] = '\0';

	ret = xbc_init(copy, &msg, &pos);
	if (ret < 0) {

Instead of having xbc_init() return the node count on success, how about having it allocate the buffer to use and then return it?

That is, move the:

	copy = memblock_alloc(size + 1, SMP_CACHE_BYTES);
	if (!copy) {
		pr_err("Failed to allocate memory for bootconfig\n");
		return;
	}

	memcpy(copy, data, size);
	copy[size] = '\0';
Quoted 3 lines

into xbc_init(), and have data, and size be passed to it.

Then, have it return the pointer of "copy" or NULL on error?

Thanks for pointing it out, that is also good to me. Let me update it.

Quoted 7 lines

This will keep the semantics of xbc_* owning the buffer that gets freed by the destroy.

The xbc_init() could also do the pr_info() that prints the bytes and node count. There's no other reason to pass that node count to the caller, is there?

Ah, it is my policy that the error or information message is shown by caller (since caller can also ignore that, e.g. passing the testing data), not from the library code.
I learned that from perf-probe and ftrace, sometimes the library code reused in unexpected way. So I decided to decouple the generating error message and showing it.

Thank you,

Quoted 2 lines

-- Steve

Signature · 1 line
Masami Hiramatsu <[email protected]>
#6 lore raw

Re: [PATCH v3 3/3] bootconfig: Free xbc_data in xbc_destroy_all()

Quoted 6 lines · On Thu, 16 Sep 2021 09:05:03 +0900 Masami Hiramatsu <[email protected]> wrote:

Ah, it is my policy that the error or information message is shown by caller (since caller can also ignore that, e.g. passing the testing data), not from the library code.
I learned that from perf-probe and ftrace, sometimes the library code reused in unexpected way. So I decided to decouple the generating error message and showing it.

OK, then we can just pass the number of nodes allocated via a pointer to an integer.

Thanks!

-- Steve

#7 lore raw
In reply to Masami Hiramatsu
Quoted 2 lines · Masami Hiramatsu

But still I'm thinking how I can move lib/bootconfig.c and bootconfig.h

So having slept on it, I think the solution for now is "it's been a problem only this once, let's ignore it for now"

IOW, I'll apply your trivial fixup for the bootconfig copy of memblock.h, and forget about it, and then if we end up having more problems with it later, we can look at a bigger fix.

Linus

#8 lore raw
Quoted 4 lines · Linus Torvalds

IOW, I'll apply your trivial fixup for the bootconfig copy of memblock.h, and forget about it, and then if we end up having more problems with it later, we can look at a bigger fix.

Just to clarify - I applied that build fix directly to my tree, but this series of leak fixes I'll leave for the tracing tree.

Linus

author maintainer
#9 lore raw
Quoted 6 lines · On Wed, 15 Sep 2021 09:51:15 -0700 Linus Torvalds…
Quoted 4 lines · Linus Torvalds

IOW, I'll apply your trivial fixup for the bootconfig copy of memblock.h, and forget about it, and then if we end up having more problems with it later, we can look at a bigger fix.

Thanks, and OK, I'll try to solve this issue.

Quoted 3 lines

Just to clarify - I applied that build fix directly to my tree, but this series of leak fixes I'll leave for the tracing tree.

OK, I got it.

Thank you,

Quoted 2 lines

Linus

Signature · 1 line
Masami Hiramatsu <[email protected]>