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>, Petr Mladek <pmladek@suse.com>,
Shuvam Pandey <shuvampandey1@gmail.com>,
Steven Rostedt <rostedt@goodmis.org>,
nikitash.mariiaw@gmail.com, linux-kernel@vger.kernel.org,
linux-hardening@vger.kernel.org
Subject: [PATCH v2 6/9] seq_buf: Add seq_buf_init_append()
Date: Fri, 18 Sep 2026 17:27:04 -0700 [thread overview]
Message-ID: <20260919002714.4060307-6-kees@kernel.org> (raw)
In-Reply-To: <20260919002658.stay.929-kees@kernel.org>
From: Bill Wendling <morbo@google.com>
Several strlcat() call sites being converted to seq_buf need behavior
seq_buf doesn't currently provide. The normal seq_buf_init() always
sets the new buffer size to 0 via seq_buf_clear(). Code migrating from
strlcat(buf, ...), which appends to whatever buf already contains,
can't use seq_buf_init() without discarding that existing content. Add
seq_buf_init_append(), which preserves the existing contents and positions
the seq_buf to append after it. Add KUnit tests for behavior coverage.
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.1.0.
Assisted-by: LLM
Signed-off-by: Bill Wendling <morbo@google.com>
Co-developed-by: Kees Cook <kees@kernel.org>
Signed-off-by: Kees Cook <kees@kernel.org>
---
Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: David Gow <david@davidgow.net>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Shuvam Pandey <shuvampandey1@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
---
include/linux/seq_buf.h | 20 +++++++++++++++
lib/tests/seq_buf_kunit.c | 53 +++++++++++++++++++++++++++++++++++++++
2 files changed, 73 insertions(+)
diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
index 7f025c7a68be..89d847d40626 100644
--- a/include/linux/seq_buf.h
+++ b/include/linux/seq_buf.h
@@ -46,6 +46,26 @@ seq_buf_init(struct seq_buf *s, char *buf, unsigned int size)
seq_buf_clear(s);
}
+/**
+ * seq_buf_init_append - initialize a seq_buf over a buffer that may
+ * already hold NUL-terminated content
+ * @s: the seq_buf handle
+ * @buf: pointer to the (possibly non-empty) buffer
+ * @size: total size of @buf
+ *
+ * Unlike seq_buf_init(), which always starts @buf at len=0, this
+ * preserves whatever NUL-terminated content @buf already holds and
+ * positions @s to append after it. Useful for converting code that used
+ * to append to an existing buffer with strlcat()/scnprintf() and friends.
+ */
+static inline void
+seq_buf_init_append(struct seq_buf *s, char *buf, unsigned int size)
+{
+ s->buffer = buf;
+ s->size = size;
+ s->len = strnlen(buf, size);
+}
+
/*
* seq_buf have a buffer that might overflow. When this happens
* len is set to be greater than size.
diff --git a/lib/tests/seq_buf_kunit.c b/lib/tests/seq_buf_kunit.c
index 0259c8506b89..f3058771d96c 100644
--- a/lib/tests/seq_buf_kunit.c
+++ b/lib/tests/seq_buf_kunit.c
@@ -29,6 +29,58 @@ static void seq_buf_init_test(struct kunit *test)
KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 0);
}
+static void seq_buf_init_append_test(struct kunit *test)
+{
+ char buf[32] = "hello";
+ struct seq_buf s;
+
+ /* Initial string contents match. */
+ seq_buf_init_append(&s, buf, sizeof(buf));
+ KUNIT_EXPECT_EQ(test, s.size, 32);
+ KUNIT_EXPECT_EQ(test, s.len, 5);
+ KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s));
+ KUNIT_EXPECT_EQ(test, seq_buf_buffer_left(&s), 32 - 5);
+ KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 5);
+ KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello");
+ KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 5);
+
+ /* Appending with space works. */
+ seq_buf_puts(&s, " world");
+ KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s));
+ KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 11);
+ KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello world");
+ KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 11);
+
+ /* No truncation when space for NUL is present. */
+ seq_buf_init_append(&s, buf, 12);
+ KUNIT_EXPECT_EQ(test, s.size, 12);
+ KUNIT_EXPECT_EQ(test, s.len, 11);
+ KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s));
+ KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 11);
+ KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello world");
+ KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 11);
+
+ /* Check for required truncation when full. */
+ seq_buf_init_append(&s, buf, 11);
+ KUNIT_EXPECT_EQ(test, s.size, 11);
+ KUNIT_EXPECT_EQ(test, s.len, 11);
+ KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s));
+ KUNIT_EXPECT_EQ(test, seq_buf_buffer_left(&s), 0);
+ KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 11);
+ KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hello worl");
+ KUNIT_EXPECT_EQ(test, seq_buf_strlen(&s), 10);
+
+ /*
+ * The size bounds the scan: the string reaches past it, so an
+ * unbounded strlen() would report 10 here and leave @s overflowed.
+ */
+ seq_buf_init_append(&s, buf, 5);
+ KUNIT_EXPECT_EQ(test, s.size, 5);
+ KUNIT_EXPECT_EQ(test, s.len, 5);
+ KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s));
+ KUNIT_EXPECT_EQ(test, seq_buf_buffer_left(&s), 0);
+ KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), "hell");
+}
static void seq_buf_declare_test(struct kunit *test)
{
@@ -621,6 +673,7 @@ static void seq_buf_strlen_embedded_nul_test(struct kunit *test)
static struct kunit_case seq_buf_test_cases[] = {
KUNIT_CASE(seq_buf_init_test),
+ KUNIT_CASE(seq_buf_init_append_test),
KUNIT_CASE(seq_buf_declare_test),
KUNIT_CASE(seq_buf_clear_test),
KUNIT_CASE(seq_buf_puts_test),
--
2.34.1
next prev parent reply other threads:[~2026-09-19 0:27 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-19 0:26 [PATCH v2 0/9] seq_buf: Add seq_buf_strlen() Kees Cook
2026-09-19 0:26 ` [PATCH v2 1/9] seq_buf: Do not print an empty line from an overflowed seq_buf_do_printk() Kees Cook
2026-09-19 0:27 ` [PATCH v2 2/9] seq_buf: Do not pop from an overflowed seq_buf Kees Cook
2026-09-19 0:34 ` sashiko-bot
2026-09-19 0:27 ` [PATCH v2 3/9] seq_buf: Copy what fits when seq_buf_puts() and seq_buf_putmem() overflow Kees Cook
2026-09-19 0:27 ` [PATCH v2 4/9] seq_buf: Clear what a writer did not claim when a seq_buf overflows Kees Cook
2026-09-19 0:27 ` [PATCH v2 5/9] seq_buf: Add seq_buf_strlen() Kees Cook
2026-09-19 7:38 ` Greg KH
2026-09-19 21:15 ` Kees Cook
2026-09-20 5:34 ` Greg KH
2026-09-20 8:58 ` David Laight
2026-09-30 2:28 ` Kees Cook
2026-09-21 9:46 ` Steven Rostedt
2026-09-30 2:31 ` Kees Cook
2026-09-19 0:27 ` Kees Cook [this message]
2026-09-19 0:27 ` [PATCH v2 7/9] powerpc/papr_scm: Return the string length from the sysfs show functions Kees Cook
2026-09-19 0:27 ` [PATCH v2 8/9] nvdimm: ndtest: Return the string length from flags_show() Kees Cook
2026-09-19 0:27 ` [PATCH v2 9/9] docs: core-api: Document the seq_buf API Kees Cook
2026-09-19 1:54 ` Randy Dunlap
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=20260919002714.4060307-6-kees@kernel.org \
--to=kees@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=andriy.shevchenko@linux.intel.com \
--cc=david@davidgow.net \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=morbo@google.com \
--cc=nikitash.mariiaw@gmail.com \
--cc=pmladek@suse.com \
--cc=rostedt@goodmis.org \
--cc=shuvampandey1@gmail.com \
--cc=willy@infradead.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.