Thread (38 messages) 38 messages, 7 authors, 16h ago

Re: [PATCH v4 03/11] seq_buf: Copy what fits when seq_buf_puts() and seq_buf_putmem() overflow

From: bot+bpf-ci@kernel.org
Date: 2026-10-03 04:51:00
Also in: bpf, linux-doc, linux-hardening, linuxppc-dev, lkml, nvdimm

seq_buf: Copy what fits when seq_buf_puts() and seq_buf_putmem() overflow
TL;DR: seq_buf_puts() now copies a partial string on overflow, which may break
lpfc_rx_monitor_report(), which relies on whole-record drops. Debugfs output
could then end in a truncated record followed by a duplicate.
quoted hunk ↗ jump to hunk
diff --git a/lib/seq_buf.c b/lib/seq_buf.c
index 35a5964370b4..60e9eadb3ef7 100644
--- a/lib/seq_buf.c
+++ b/lib/seq_buf.c
[ ... ]
quoted hunk ↗ jump to hunk
@@ -194,6 +196,11 @@ int seq_buf_puts(struct seq_buf *s, const char *str)
 		s->len += len - 1;
 		return 0;
 	}
+	/* Copy what fits, so the buffer never holds stale bytes */
+	if (s->len < s->size) {
+		strscpy(s->buffer + s->len, str, s->size - s->len);
+		s->len = s->size;
+	}
 	seq_buf_set_overflow(s);
 	return -1;
 }
Can this break callers that rely on seq_buf_puts() dropping a string whole
when it does not fit?

lpfc_rx_monitor_report() in drivers/scsi/lpfc/lpfc_sli.c was converted to
seq_buf in 22d4cbf6f750 ("scsi: lpfc: Replace strlcat() with seq_buf in
lpfc_rx_monitor_report()"), and that changelog says seq_buf_puts() "appends
it only when it fits whole, so the output keeps ending at the last complete
record".  The code still documents this:

	/*
	 * Drop a record whole if it does not fit, without
	 * consuming its ring entry.
	 */
	scnprintf(tmp, sizeof(tmp), "%03d:\t%-16llu...", ...);

	if (seq_buf_puts(&s, tmp) < 0)
		break;

With this patch, a record that does not fit is now copied up to
buf[buf_len - 2] and NUL-terminated at buf[buf_len - 1] before the loop
breaks.

lpfc_rx_monitor_read() then returns strlen(buffer) bytes through
simple_read_from_buffer(), so the debugfs output ends in a truncated record
with no newline.

Since the loop breaks before *head_idx is advanced, the same ring entry is
printed again in full at the start of the next read, so the reader sees a
partial copy followed by a duplicate.

Both the old strlcat() code ("if ((strlen(buf) + strlen(tmp)) >= buf_len)
break;") and the seq_buf version before this patch dropped the record whole.

Getting there needs the 800 rows to average more than about 128 bytes in the
128 * LPFC_MAX_RXMONITOR_ENTRY buffer, which can happen when the u64/u32
counters (cmf_info, max_read_cnt, avg_io_latency, timer_utilization, ...)
are wider than their %-8/%-16 columns.

The commit message does not mention auditing seq_buf_puts() callers that
rely on the old semantics, and nothing later in the series changes lpfc.

Would it make sense to have lpfc_rx_monitor_report() check
strlen(tmp) < seq_buf_buffer_left(&s) before calling seq_buf_puts()?

The other callers I checked (setup_trace_event(), the usbhid name building,
the partition pp_buf users, string_stream_get_string(), dynevent_str_add()
and the hist command builders) either treat overflow as an error or used
strlcat() before, which also copied a partial string.


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/37096036516
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help