diff options
| author | Kees Cook <kees@kernel.org> | 2026-10-05 08:56:54 -0700 |
|---|---|---|
| committer | Kees Cook <kees@kernel.org> | 2026-10-11 21:57:29 -0700 |
| commit | 505a4aeea2c98ab9b09bc157e81e19cc0d4bf9cb (patch) | |
| tree | bb1288869e3bba189c3344eac59ed59b3701be72 /include | |
| parent | cc9d25b451196e1cdbea5891902cb65b03da1226 (diff) | |
| download | linux-next-505a4aeea2c98ab9b09bc157e81e19cc0d4bf9cb.tar.gz linux-next-505a4aeea2c98ab9b09bc157e81e19cc0d4bf9cb.zip | |
seq_buf: Copy what fits when seq_buf_puts() and seq_buf_putmem() overflow
When seq_buf_puts() or seq_buf_putmem() is given more than fits, it
copies nothing and only marks the seq_buf as overflowed. If seq_buf_str()
is used, it will terminate the buffer in its last byte, so every byte
between the end of the data and the end of the buffer becomes part of
the string, though the seq_buf never wrote them.
seq_buf_printf() does not have this problem, because vsnprintf() writes
as much of the output as fits, followed by a NUL. Repeat this behavior
in seq_buf_puts(), using strscpy(), and in seq_buf_putmem(), which also
covers seq_buf_putmem_hex(). seq_buf_putc() needs no change, as it can
only overflow when the buffer is already full.
Each writer now records the buffer as full once it has copied what fits,
so that what it wrote can be told apart from bytes nothing touched.
Of the callers that check the return value or test for overflow
afterward, only lpfc_rx_monitor_report() relied on a string that did not
fit being left out, and the previous patch has it drop such a record
itself. The others treat overflow as an error or report it. The callers
that ignore overflow use whatever the buffer holds, which now ends with
the part of the string that fit.
Update seq_buf_putmem_hex_overflow_test, which expected a hex group that
did not fit whole to be left out entirely, and add tests that overflow
seq_buf_puts(), seq_buf_putmem() and seq_buf_putmem_hex() with stale
bytes in the buffer.
The three partial-overflow tests check the buffer itself rather than
seq_buf_str(). Neither writer leaves the last byte of the buffer alone:
seq_buf_putmem() copies raw bytes and writes no NUL, and seq_buf_puts()
relies on strscpy() to write one. That byte is exactly where
seq_buf_str() writes its terminator, so asserting only on the string
would pass whether the copy stopped a byte early or dropped the NUL
entirely.
seq_buf_putmem() was not exported, 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>
Link: https://patch.msgid.link/20261005155708.1471260-4-kees@kernel.org
Signed-off-by: Kees Cook <kees@kernel.org>
Diffstat (limited to 'include')
| -rw-r--r-- | include/linux/seq_buf.h | 6 |
1 files changed, 6 insertions, 0 deletions
diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h index f5a350347bc5..77e76e283370 100644 --- a/include/linux/seq_buf.h +++ b/include/linux/seq_buf.h @@ -55,6 +55,12 @@ seq_buf_has_overflowed(struct seq_buf *s) return s->len > s->size; } +/* + * 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. + */ static inline void seq_buf_set_overflow(struct seq_buf *s) { |
