[PATCH] kernel/panic: increase buffer size for verbose taint logging

Rio posted 1 patch 1 month, 1 week ago
kernel/panic.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
[PATCH] kernel/panic: increase buffer size for verbose taint logging
Posted by Rio 1 month, 1 week ago
The verbose 'Tainted: ...' string in print_tainted_seq
can total to 327 characters while the buffer defined in
_print_tainted is 320 bytes. Increase its size to 350
characters to hold all flags, along with some headroom.

Signed-off-by: Rio <rioo.tsukatsukii@gmail.com>
---
 kernel/panic.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/kernel/panic.c b/kernel/panic.c
index c78600212b6c..42b03fdd6ffa 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -854,10 +854,12 @@ static void print_tainted_seq(struct seq_buf *s, bool verbose)
 	}
 }
 
+/* 350 can accomadate all taint flags in verbose mode, with some headroom */
+#define TAINT_BUF_MAX 350
+
 static const char *_print_tainted(bool verbose)
 {
-	/* FIXME: what should the size be? */
-	static char buf[sizeof(taint_flags)];
+	static char buf[TAINT_BUF_MAX];
 	struct seq_buf s;
 
 	BUILD_BUG_ON(ARRAY_SIZE(taint_flags) != TAINT_FLAGS_COUNT);
-- 
2.52.0
Re: [PATCH] kernel/panic: increase buffer size for verbose taint logging
Posted by Andrew Morton 1 month, 1 week ago
On Fri, 20 Feb 2026 20:45:00 +0530 Rio <rioo.tsukatsukii@gmail.com> wrote:

> The verbose 'Tainted: ...' string in print_tainted_seq
> can total to 327 characters while the buffer defined in
> _print_tainted is 320 bytes. Increase its size to 350
> characters to hold all flags, along with some headroom.
> 
> ...
>
> --- a/kernel/panic.c
> +++ b/kernel/panic.c
> @@ -854,10 +854,12 @@ static void print_tainted_seq(struct seq_buf *s, bool verbose)
>  	}
>  }
>  
> +/* 350 can accomadate all taint flags in verbose mode, with some headroom */

"accommodate".  I'll fix this.

> +#define TAINT_BUF_MAX 350
> +
>  static const char *_print_tainted(bool verbose)
>  {
> -	/* FIXME: what should the size be? */
> -	static char buf[sizeof(taint_flags)];

Well that was weird.

> +	static char buf[TAINT_BUF_MAX];

Can you think of a way to do this more flexibly?  Something which
scales as we add more flags?

Probably not, as it's dependent upon the length of the various
taint_flags.desc strings.


>  	struct seq_buf s;
>  
>  	BUILD_BUG_ON(ARRAY_SIZE(taint_flags) != TAINT_FLAGS_COUNT);

How does this look?

--- a/kernel/panic.c~kernel-panic-increase-buffer-size-for-verbose-taint-logging-fix
+++ a/kernel/panic.c
@@ -801,6 +801,8 @@ EXPORT_SYMBOL(panic);
  * Documentation/admin-guide/tainted-kernels.rst, including its
  * small shell script that prints the TAINT_FLAGS_COUNT bits of
  * /proc/sys/kernel/tainted.
+ *
+ * Also, update TAINT_BUF_MAX below.
  */
 const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {
 	TAINT_FLAG(PROPRIETARY_MODULE,		'P', 'G'),
@@ -854,7 +856,7 @@ static void print_tainted_seq(struct seq
 	}
 }
 
-/* 350 can accomadate all taint flags in verbose mode, with some headroom */
+/* 350 can accommodate all taint flags in verbose mode, with some headroom */
 #define TAINT_BUF_MAX 350
 
 static const char *_print_tainted(bool verbose)
_
Re: [PATCH] kernel/panic: increase buffer size for verbose taint logging
Posted by Rio 1 month, 1 week ago
> "accommodate".  I'll fix this.

Thanks

> How does this look?

> + *
> + * Also, update TAINT_BUF_MAX below.
>   */
> ...
> -/* 350 can accomadate all taint flags in verbose mode, with some headroom */
> +/* 350 can accommodate all taint flags in verbose mode, with some headroom */
>  #define TAINT_BUF_MAX 350

Looks good, though it might help future maintainers if we document the current
maximum length of the verbose string (excluding the trailing NULL). Happy to
send a small follow-up patch if needed.
Re: [PATCH] kernel/panic: increase buffer size for verbose taint logging
Posted by Andrew Morton 1 month, 1 week ago
On Sat, 21 Feb 2026 12:26:03 +0530 Rio <rioo.tsukatsukii@gmail.com> wrote:

> > "accommodate".  I'll fix this.
> 
> Thanks
> 
> > How does this look?
> 
> > + *
> > + * Also, update TAINT_BUF_MAX below.
> >   */
> > ...
> > -/* 350 can accomadate all taint flags in verbose mode, with some headroom */
> > +/* 350 can accommodate all taint flags in verbose mode, with some headroom */
> >  #define TAINT_BUF_MAX 350
> 
> Looks good, though it might help future maintainers if we document the current
> maximum length of the verbose string (excluding the trailing NULL). Happy to
> send a small follow-up patch if needed.

OK, how about this idea.

- Allocating static storage is annoying: dynamic allocation is better

- Now knowing how large to make the storage is also annoying.

So:

- define a static buffer, mark it __initdata so it gets released
  later in boot.  Make print_tainted() use that, initially, so
  print_tainted() is available at initial bootup time.

- write a new __init function which adds up all string lengths in
  taint_flags[] and calculates the precise maximum needed buffer size.

  Allocate that much memory (kmalloc) and switch print_tainted() over
  to using that buffer.

- When __init data gets released, the initial static buffer and the
  new __init function get thrown away.
[PATCHv2] kernel/panic: allocate taint string buffer dynamically
Posted by Rio 1 month, 1 week ago
The buffer used to hold the taint string is statically allocated, which
requires updating whenever a new taint flag is added.

Instead, allocate the exact required length at boot once the allocator is
available in an init function. The allocation sums the string lengths in
taint_flags[], along with space for separators and formatting.
print_tainted() is switched to use this dynamically allocated buffer.

If allocation fails, print_tainted() warns about the failure and continues
to use the original static buffer as a fallback.

Signed-off-by: Rio <rioo.tsukatsukii@gmail.com>
---
V1 -> V2: Allocate taint string buffer dynamically during init

v1: https://lore.kernel.org/all/20260220151500.13585-1-rioo.tsukatsukii@gmail.com/

 kernel/panic.c | 51 +++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 46 insertions(+), 5 deletions(-)

diff --git a/kernel/panic.c b/kernel/panic.c
index 75368738d32d..5d498ff8a18b 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -802,7 +802,7 @@ EXPORT_SYMBOL(panic);
  * small shell script that prints the TAINT_FLAGS_COUNT bits of
  * /proc/sys/kernel/tainted.
  *
- * Also, update TAINT_BUF_MAX below.
+ * Also, update INIT_TAINT_BUF_MAX below.
  */
 const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {
 	TAINT_FLAG(PROPRIETARY_MODULE,		'P', 'G'),
@@ -856,17 +856,58 @@ static void print_tainted_seq(struct seq_buf *s, bool verbose)
 	}
 }
 
-/* 350 can accommodate all taint flags in verbose mode, with some headroom */
-#define TAINT_BUF_MAX 350
+/* The initial buffer can accommodate all taint flags in verbose
+ * mode, with some headroom. Once the allocator is available, the
+ * exact size is allocated dynamically; the initial buffer remains
+ * as a fallback if allocation fails.
+ *
+ * The verbose taint string currently requires up to 327 characters.
+ */
+#define INIT_TAINT_BUF_MAX 350
+
+static char init_taint_buf[INIT_TAINT_BUF_MAX];
+static char *taint_buf = init_taint_buf;
+static size_t taint_buf_size = INIT_TAINT_BUF_MAX;
+
+static __init int alloc_taint_buf(void)
+{
+	int i;
+	char *buf;
+	size_t size = 0;
+
+	size += sizeof("Tainted: ") - 1;
+	for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
+		size += 2; /* For ", " */
+		size += 4; /* For "[%c]=" */
+		size += strlen(taint_flags[i].desc);
+	}
+
+	size += 1; /* For NULL terminator */
+
+	buf = kmalloc(size, GFP_KERNEL);
+
+	if (!buf) {
+		/* Allocation may fail; this warning explains possibly
+		 * truncated taint strings
+		 */
+		pr_warn_once("taint string buffer allocation failed, using fallback buffer\n");
+		return 0;
+	}
+
+	taint_buf = buf;
+	taint_buf_size = size;
+
+	return 0;
+}
+postcore_initcall(alloc_taint_buf);
 
 static const char *_print_tainted(bool verbose)
 {
-	static char buf[TAINT_BUF_MAX];
 	struct seq_buf s;
 
 	BUILD_BUG_ON(ARRAY_SIZE(taint_flags) != TAINT_FLAGS_COUNT);
 
-	seq_buf_init(&s, buf, sizeof(buf));
+	seq_buf_init(&s, taint_buf, taint_buf_size);
 
 	print_tainted_seq(&s, verbose);
 
-- 
2.52.0
Re: [PATCHv2] kernel/panic: allocate taint string buffer dynamically
Posted by Andrew Morton 1 month, 1 week ago
On Sun, 22 Feb 2026 19:38:04 +0530 Rio <rioo.tsukatsukii@gmail.com> wrote:

> The buffer used to hold the taint string is statically allocated, which
> requires updating whenever a new taint flag is added.
> 
> Instead, allocate the exact required length at boot once the allocator is
> available in an init function. The allocation sums the string lengths in
> taint_flags[], along with space for separators and formatting.
> print_tainted() is switched to use this dynamically allocated buffer.
> 
> If allocation fails, print_tainted() warns about the failure and continues
> to use the original static buffer as a fallback.
> 

Lovely, thanks.

> 
> --- a/kernel/panic.c
> +++ b/kernel/panic.c
> @@ -802,7 +802,7 @@ EXPORT_SYMBOL(panic);
>   * small shell script that prints the TAINT_FLAGS_COUNT bits of
>   * /proc/sys/kernel/tainted.
>   *
> - * Also, update TAINT_BUF_MAX below.
> + * Also, update INIT_TAINT_BUF_MAX below.
>   */
>  const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {
>  	TAINT_FLAG(PROPRIETARY_MODULE,		'P', 'G'),
> @@ -856,17 +856,58 @@ static void print_tainted_seq(struct seq_buf *s, bool verbose)
>  	}
>  }
>  
> -/* 350 can accommodate all taint flags in verbose mode, with some headroom */
> -#define TAINT_BUF_MAX 350
> +/* The initial buffer can accommodate all taint flags in verbose
> + * mode, with some headroom. Once the allocator is available, the
> + * exact size is allocated dynamically; the initial buffer remains
> + * as a fallback if allocation fails.
> + *
> + * The verbose taint string currently requires up to 327 characters.
> + */
> +#define INIT_TAINT_BUF_MAX 350
> +
> +static char init_taint_buf[INIT_TAINT_BUF_MAX];

OK, this cannot be __initdata because

> +static char *taint_buf = init_taint_buf;
> +static size_t taint_buf_size = INIT_TAINT_BUF_MAX;
> +
> +static __init int alloc_taint_buf(void)
> +{
> +	int i;
> +	char *buf;
> +	size_t size = 0;
> +
> +	size += sizeof("Tainted: ") - 1;
> +	for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
> +		size += 2; /* For ", " */
> +		size += 4; /* For "[%c]=" */
> +		size += strlen(taint_flags[i].desc);
> +	}
> +
> +	size += 1; /* For NULL terminator */
> +
> +	buf = kmalloc(size, GFP_KERNEL);
> +
> +	if (!buf) {
> +		/* Allocation may fail; this warning explains possibly
> +		 * truncated taint strings
> +		 */
> +		pr_warn_once("taint string buffer allocation failed, using fallback buffer\n");
> +		return 0;

We may end up using it after boot time.

> +	}
> +
> +	taint_buf = buf;
> +	taint_buf_size = size;
> +
> +	return 0;
> +}
> +postcore_initcall(alloc_taint_buf);

However there's a convention of assuming that __init-time allocations
cannot fail.  Because if a kmalloc() were to fail at this time, the
kernel is hopelessly messed up anyway.

So we could simply panic() if that kmalloc failed, then make that
350-byte buffer __initdata.

That saves about $100 per machine with current DRAM prices ;)
Re: [PATCHv2] kernel/panic: allocate taint string buffer dynamically
Posted by Rio 1 month, 1 week ago
This follow-up provides some tradeoffs between v1 and v2

- v1 used a fixed-size static buffer, requiring manual updates whenever
new strings are added to taint_flags[].
- v2 uses a fixed-size static buffer only for initial boot. Once kmalloc
is available, it allocates a dynamically sized buffer based on the total
length of strings in taint_flags[].

- v1 needs an update every time taint_flags[] is updated.
- v2 relies on the initial buffer as a fallback mechanism in case kmalloc
fails. The initial buffer is currently large enough for all taint strings,
but future updates to taint_flags[] may require adjustments.

- v1 is more predictable, but requires more manual maintenance.
- v2 is more convenient, but introduces subtle edge cases and potential
allocation issues.
[PATCHv3] kernel/panic: mark init_taint_buf as __initdata and panic instead of warning in alloc_taint_buf()
Posted by Rio 1 month, 1 week ago
On Sun, Feb 22, 2026 at 11:25:52AM -0800, Andrew Morton wrote:

> However there's a convention of assuming that __init-time allocations
> cannot fail.  Because if a kmalloc() were to fail at this time, the
> kernel is hopelessly messed up anyway.
> So we could simply panic() if that kmalloc failed, then make that
> 350-byte buffer __initdata.

Ah, got it. I made it __initdata, and replaced the warn with panic.

> That saves about $100 per machine with current DRAM prices ;)

Haha, saving every bit counts huh

Signed-off-by: Rio <rioo.tsukatsukii@gmail.com>
---
V2 -> V3: Mark initial buffer as __initdata and panic if allocation
fails
V1 -> V2: Allocate taint string buffer dynamically during init

v2: https://lore.kernel.org/all/20260222140804.22225-1-rioo.tsukatsukii@gmail.com/
v1: https://lore.kernel.org/all/20260220151500.13585-1-rioo.tsukatsukii@gmail.com/

 kernel/panic.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/kernel/panic.c b/kernel/panic.c
index 5d498ff8a18b..20feada5319d 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -865,8 +865,8 @@ static void print_tainted_seq(struct seq_buf *s, bool verbose)
  */
 #define INIT_TAINT_BUF_MAX 350
 
-static char init_taint_buf[INIT_TAINT_BUF_MAX];
-static char *taint_buf = init_taint_buf;
+static char init_taint_buf[INIT_TAINT_BUF_MAX] __initdata;
+static char *taint_buf __refdata = init_taint_buf;
 static size_t taint_buf_size = INIT_TAINT_BUF_MAX;
 
 static __init int alloc_taint_buf(void)
@@ -887,11 +887,7 @@ static __init int alloc_taint_buf(void)
 	buf = kmalloc(size, GFP_KERNEL);
 
 	if (!buf) {
-		/* Allocation may fail; this warning explains possibly
-		 * truncated taint strings
-		 */
-		pr_warn_once("taint string buffer allocation failed, using fallback buffer\n");
-		return 0;
+		panic("Failed to allocate taint string buffer");
 	}
 
 	taint_buf = buf;
-- 
2.52.0