From: Kees Cook <kees@kernel.org>
To: Bill Wendling <morbo@google.com>
Cc: "Kees Cook" <kees@kernel.org>,
"Matthew Wilcox (Oracle)" <willy@infradead.org>,
"Andrew Morton" <akpm@linux-foundation.org>,
"Andy Shevchenko" <andriy.shevchenko@linux.intel.com>,
"David Gow" <david@davidgow.net>,
"Jiri Kosina" <jikos@kernel.org>,
"Petr Mladek" <pmladek@suse.com>,
"Shuvam Pandey" <shuvampandey1@gmail.com>,
"Steven Rostedt" <rostedt@goodmis.org>,
"Jonathan Corbet" <corbet@lwn.net>,
"Sergey Senozhatsky" <senozhatsky@chromium.org>,
"Günther Noack" <gnoack@google.com>,
"Mickaël Salaün" <mic@digikod.net>,
"Masami Hiramatsu" <mhiramat@kernel.org>,
"Mathieu Desnoyers" <mathieu.desnoyers@efficios.com>,
"Alexei Starovoitov" <ast@kernel.org>,
"Daniel Borkmann" <daniel@iogearbox.net>,
"Andrii Nakryiko" <andrii@kernel.org>,
"Eduard Zingerman" <eddyz87@gmail.com>,
"Kumar Kartikeya Dwivedi" <memxor@gmail.com>,
"Martin KaFai Lau" <martin.lau@linux.dev>,
"Song Liu" <song@kernel.org>,
"Yonghong Song" <yonghong.song@linux.dev>,
"Jiri Olsa" <jolsa@kernel.org>,
"Emil Tsalapatis" <emil@etsalapatis.com>,
"Ihor Solodrai" <ihor.solodrai@linux.dev>,
"Christophe Leroy (CS GROUP)" <chleroy@kernel.org>,
"Uwe Kleine-König" <u.kleine-koenig@baylibre.com>,
"Madhavan Srinivasan" <maddy@linux.ibm.com>,
"Michael Ellerman" <mpe@ellerman.id.au>,
"Nicholas Piggin" <npiggin@gmail.com>,
"Shivaprasad G Bhat" <sbhat@linux.ibm.com>,
"Thorsten Blum" <blum@kernel.org>,
"Alison Schofield" <alison.schofield@intel.com>,
"Dave Jiang" <dave.jiang@intel.com>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Guangshuo Li" <lgs201920130244@gmail.com>,
"Ira Weiny" <iweiny@kernel.org>,
"Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>,
"Vishal Verma" <vishal.l.verma@intel.com>,
"Randy Dunlap" <rdunlap@infradead.org>,
"Shuah Khan" <skhan@linuxfoundation.org>,
linux-kernel@vger.kernel.org, bpf@vger.kernel.org,
linux-security-module@vger.kernel.org,
linux-trace-kernel@vger.kernel.org,
linuxppc-dev@lists.ozlabs.org, nvdimm@lists.linux.dev,
linux-doc@vger.kernel.org, linux-hardening@vger.kernel.org
Subject: [PATCH v4 04/11] seq_buf: Clear what a writer did not claim when a seq_buf overflows
Date: Fri, 2 Oct 2026 20:59:09 -0700 [thread overview]
Message-ID: <20261003035921.1918874-4-kees@kernel.org> (raw)
In-Reply-To: <20261003035906.too.263-kees@kernel.org>
Using seq_buf_set_overflow() would leave the bytes between "len"
and "size" untouched, so if seq_buf_str() is used on an overflowed
seq_buf, those bytes may be exposed. For any paths that don't claim
partially written bytes, by setting "len = size" before calling
seq_buf_set_overflow(), wipe the unclaimed bytes. The seq_buf_puts()
and related APIs already claim those bytes now, so only the unclaimed
cases remain. A specific example of this was seq_buf_path() which uses
d_path() and would write to the tail before discovering it was out
of space, and would correctly mark a seq_buf as overflowed, but the
path fragment would be left over.
Clear from len to the end of the buffer in seq_buf_set_overflow(), which
every overflow goes through, including seq_buf_commit() with a negative
count.
Add a test that fills a seq_buf, leaves it too little room for a path, and
checks that nothing of the path is left in the buffer. The tests run before
anything writable is mounted, so it takes its file from shmem.
seq_buf_path() was never exported, unlike the other writers, so the
test failed to link as a module. Export it.
Tests passed under qemu on ARCH=x86_64 with GCC 16.2.0 and CONFIG_KASAN=y,
and on big-endian ARCH=s390 with GCC s390x-linux-gnu 16.2.0, and the
test builds as a module (CONFIG_SEQ_BUF_KUNIT_TEST=m).
Assisted-by: LLM
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Kees Cook <kees@kernel.org>
---
include/linux/seq_buf.h | 8 +++++--
lib/seq_buf.c | 5 +++++
lib/tests/seq_buf_kunit.c | 45 +++++++++++++++++++++++++++++++++++++++
3 files changed, 56 insertions(+), 2 deletions(-)
diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
index 77e76e283370..0c0a0db04b09 100644
--- a/include/linux/seq_buf.h
+++ b/include/linux/seq_buf.h
@@ -5,6 +5,7 @@
#include <linux/bug.h>
#include <linux/minmax.h>
#include <linux/seq_file.h>
+#include <linux/string.h>
#include <linux/types.h>
/*
@@ -58,12 +59,15 @@ seq_buf_has_overflowed(struct seq_buf *s)
/*
* Mark @s as overflowed, which discards the length of what it holds. The
* bytes up to its last one are the string from then on, as that is where
- * seq_buf_str() terminates it, so a caller that could not fill the buffer
- * has to NUL them itself before calling this.
+ * seq_buf_str() terminates it, so clear whatever was not written: a writer
+ * sets len to how much it filled, and anything past that was never adopted.
*/
static inline void
seq_buf_set_overflow(struct seq_buf *s)
{
+ if (s->len < s->size)
+ memset(s->buffer + s->len, 0, s->size - s->len);
+
s->len = s->size + 1;
}
diff --git a/lib/seq_buf.c b/lib/seq_buf.c
index 60e9eadb3ef7..8da2e9447adf 100644
--- a/lib/seq_buf.c
+++ b/lib/seq_buf.c
@@ -76,6 +76,8 @@ int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)
s->len += len;
return 0;
}
+ /* vsnprintf() wrote as much as fits, so none of it is stale */
+ s->len = s->size;
}
seq_buf_set_overflow(s);
return -1;
@@ -164,6 +166,8 @@ int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary)
s->len += ret;
return 0;
}
+ /* bstr_printf() wrote as much as fits, so none of it is stale */
+ s->len = s->size;
}
seq_buf_set_overflow(s);
return -1;
@@ -343,6 +347,7 @@ int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc)
return res;
}
+EXPORT_SYMBOL_GPL(seq_buf_path);
/**
* seq_buf_to_user - copy the sequence buffer to user space
diff --git a/lib/tests/seq_buf_kunit.c b/lib/tests/seq_buf_kunit.c
index 046614100c77..d5b819fc0ff3 100644
--- a/lib/tests/seq_buf_kunit.c
+++ b/lib/tests/seq_buf_kunit.c
@@ -6,6 +6,9 @@
*/
#include <kunit/test.h>
+#include <linux/fs.h>
+#include <linux/seq_buf.h>
+#include <linux/shmem_fs.h>
#include <linux/console.h>
#include <linux/seq_buf.h>
#include <linux/string.h>
@@ -466,6 +469,47 @@ static void seq_buf_do_printk_test(struct kunit *test)
KUNIT_EXPECT_EQ(test, seq_buf_printk_empty, 0);
}
+/* Long enough that it cannot fit in the room the test leaves for it. */
+#define SEQ_BUF_TEST_PATH "/seq_buf_kunit_path_name"
+
+static void seq_buf_path_overflow_test(struct kunit *test)
+{
+ DECLARE_SEQ_BUF(s, 32);
+ const char *expected = "keep:xxxxxxxxxxxxxxxxxxxxxxx";
+ struct file *file;
+ size_t len;
+ int i;
+
+ /*
+ * The tests run before anything writable is mounted, so take the file
+ * whose path gets printed from shmem, which needs no mount of its own.
+ */
+ file = shmem_file_setup(SEQ_BUF_TEST_PATH, 0, EMPTY_VMA_FLAGS);
+ if (IS_ERR(file))
+ kunit_skip(test, "cannot create a file to print the path of");
+
+ /* Leave less room than the path needs, so d_path() cannot fit it. */
+ seq_buf_puts(&s, "keep:");
+ len = seq_buf_used(&s);
+ for (i = len; i < 28; i++)
+ seq_buf_putc(&s, 'x');
+
+ KUNIT_EXPECT_EQ(test, seq_buf_path(&s, &file->f_path, "\n"), -1);
+ fput(file);
+
+ KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s));
+
+ /*
+ * d_path() keeps as much of the path as fits when it does not fit
+ * whole, and seq_buf_str() would hand out that fragment, as it ends
+ * the string at the last byte of an overflowed buffer.
+ */
+ for (i = 28; i < 32; i++)
+ KUNIT_EXPECT_EQ_MSG(test, s.buffer[i], '\0',
+ "byte %d past the data is not cleared", i);
+ KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), expected);
+}
+
static struct kunit_case seq_buf_test_cases[] = {
KUNIT_CASE(seq_buf_init_test),
KUNIT_CASE(seq_buf_declare_test),
@@ -482,6 +526,7 @@ static struct kunit_case seq_buf_test_cases[] = {
KUNIT_CASE(seq_buf_puts_partial_overflow_test),
KUNIT_CASE(seq_buf_putmem_partial_overflow_test),
KUNIT_CASE(seq_buf_putmem_hex_partial_overflow_test),
+ KUNIT_CASE(seq_buf_path_overflow_test),
KUNIT_CASE(seq_buf_do_printk_test),
{}
};
--
2.55.0
next prev parent reply other threads:[~2026-10-03 3:59 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-03 3:59 [PATCH v4 00/11] seq_buf: Add seq_buf_strlen() Kees Cook
2026-10-03 3:59 ` [PATCH v4 01/11] seq_buf: Do not print an empty line from an overflowed seq_buf_do_printk() Kees Cook
2026-10-03 4:50 ` bot+bpf-ci
2026-10-03 3:59 ` [PATCH v4 02/11] seq_buf: Do not pop from an overflowed seq_buf Kees Cook
2026-10-03 3:59 ` [PATCH v4 03/11] seq_buf: Copy what fits when seq_buf_puts() and seq_buf_putmem() overflow Kees Cook
2026-10-03 4:50 ` bot+bpf-ci
2026-10-03 3:59 ` Kees Cook [this message]
2026-10-03 4:50 ` [PATCH v4 04/11] seq_buf: Clear what a writer did not claim when a seq_buf overflows bot+bpf-ci
2026-10-03 3:59 ` [PATCH v4 05/11] seq_buf: Add seq_buf_strlen() Kees Cook
2026-10-03 15:36 ` Andy Shevchenko
2026-10-04 7:26 ` Kees Cook
2026-10-04 8:34 ` Andy Shevchenko
2026-10-03 3:59 ` [PATCH v4 06/11] seq_buf: Add seq_buf_terminate() Kees Cook
2026-10-03 3:59 ` [PATCH v4 07/11] bpf: Remove dead newline stripping from format_disasm_line() Kees Cook
2026-10-03 3:59 ` [PATCH v4 08/11] seq_buf: Add seq_buf_init_append() Kees Cook
2026-10-03 4:33 ` bot+bpf-ci
2026-10-03 10:31 ` Kees Cook
2026-10-03 3:59 ` [PATCH v4 09/11] powerpc/papr_scm: Return the string length from the sysfs show functions Kees Cook
2026-10-03 3:59 ` [PATCH v4 10/11] nvdimm: ndtest: Return the string length from flags_show() Kees Cook
2026-10-03 3:59 ` [PATCH v4 11/11] docs: core-api: Document the seq_buf API Kees Cook
2026-10-03 6:32 ` [PATCH v4 00/11] seq_buf: Add seq_buf_strlen() Alexei Starovoitov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261003035921.1918874-4-kees@kernel.org \
--to=kees@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=alison.schofield@intel.com \
--cc=andrii@kernel.org \
--cc=andriy.shevchenko@linux.intel.com \
--cc=ast@kernel.org \
--cc=blum@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=chleroy@kernel.org \
--cc=corbet@lwn.net \
--cc=daniel@iogearbox.net \
--cc=dave.jiang@intel.com \
--cc=david@davidgow.net \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=gnoack@google.com \
--cc=gregkh@linuxfoundation.org \
--cc=ihor.solodrai@linux.dev \
--cc=iweiny@kernel.org \
--cc=jikos@kernel.org \
--cc=jolsa@kernel.org \
--cc=lgs201920130244@gmail.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=maddy@linux.ibm.com \
--cc=martin.lau@linux.dev \
--cc=mathieu.desnoyers@efficios.com \
--cc=memxor@gmail.com \
--cc=mhiramat@kernel.org \
--cc=mic@digikod.net \
--cc=morbo@google.com \
--cc=mpe@ellerman.id.au \
--cc=npiggin@gmail.com \
--cc=nvdimm@lists.linux.dev \
--cc=pmladek@suse.com \
--cc=rdunlap@infradead.org \
--cc=rostedt@goodmis.org \
--cc=sbhat@linux.ibm.com \
--cc=senozhatsky@chromium.org \
--cc=shuvampandey1@gmail.com \
--cc=skhan@linuxfoundation.org \
--cc=song@kernel.org \
--cc=u.kleine-koenig@baylibre.com \
--cc=u.kleine-koenig@pengutronix.de \
--cc=vishal.l.verma@intel.com \
--cc=willy@infradead.org \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®