git: c999e3481d93 - main - dmesg: detect wrapped msgbuf on the kernel side and if so, skip first line

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Sat, 05 Feb 2022 21:35:39 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=c999e3481d936980354d09e3d6a138e5dde5fabc

commit c999e3481d936980354d09e3d6a138e5dde5fabc
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2022-02-05 21:25:38 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2022-02-05 21:35:31 +0000

    dmesg: detect wrapped msgbuf on the kernel side and if so, skip first line
    
    Since 59f256ec35d3 dmesg(8) will always skip first line of the message
    buffer, cause it might be incomplete.  The problem is that in most cases
    it is complete, valid and contains the "---<<BOOT>>---" marker.  This
    skip can be disabled with '-a', but that would also unhide all non-kernel
    messages.  Move this functionality from dmesg(8) to kernel, since kernel
    actually knows if wrap has happened or not.
    
    The main motivation for the change is not actually the value of the
    "---<<BOOT>>---" marker.  The problem breaks unit tests, that clear
    message buffer, perform a test and then check the message buffer for
    a result.  Example of such test is sys/kern/sonewconn_overflow.
---
 sbin/dmesg/dmesg.c  |  4 ----
 sys/kern/subr_prf.c | 23 ++++++++++++++++++++---
 2 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/sbin/dmesg/dmesg.c b/sbin/dmesg/dmesg.c
index 469582204f7b..f266e6b98b39 100644
--- a/sbin/dmesg/dmesg.c
+++ b/sbin/dmesg/dmesg.c
@@ -184,10 +184,6 @@ main(int argc, char *argv[])
 		/* Strip leading \0's */
 		while (*p == '\0')
 			p++;
-	} else if (!all) {
-		/* Skip the first line, since it is probably incomplete. */
-		p = memchr(p, '\n', ep - p);
-		p++;
 	}
 	for (; p < ep; p = nextp) {
 		nextp = memchr(p, '\n', ep - p);
diff --git a/sys/kern/subr_prf.c b/sys/kern/subr_prf.c
index 1106587ebbe7..62a0bd0a3699 100644
--- a/sys/kern/subr_prf.c
+++ b/sys/kern/subr_prf.c
@@ -1058,9 +1058,10 @@ msgbufinit(void *ptr, int size)
 static int
 sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
 {
-	char buf[128];
+	char buf[128], *bp;
 	u_int seq;
 	int error, len;
+	bool wrap;
 
 	error = priv_check(req->td, PRIV_MSGBUF);
 	if (error)
@@ -1069,13 +1070,29 @@ sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
 	/* Read the whole buffer, one chunk at a time. */
 	mtx_lock(&msgbuf_lock);
 	msgbuf_peekbytes(msgbufp, NULL, 0, &seq);
+	wrap = (seq != 0);
 	for (;;) {
 		len = msgbuf_peekbytes(msgbufp, buf, sizeof(buf), &seq);
 		mtx_unlock(&msgbuf_lock);
 		if (len == 0)
 			return (SYSCTL_OUT(req, "", 1)); /* add nulterm */
-
-		error = sysctl_handle_opaque(oidp, buf, len, req);
+		if (wrap) {
+			/* Skip the first line, as it is probably incomplete. */
+			bp = memchr(buf, '\n', len);
+			if (bp == NULL) {
+				mtx_lock(&msgbuf_lock);
+				continue;
+			}
+			wrap = false;
+			bp++;
+			len -= bp - buf;
+			if (len == 0) {
+				mtx_lock(&msgbuf_lock);
+				continue;
+			}
+		} else
+			bp = buf;
+		error = sysctl_handle_opaque(oidp, bp, len, req);
 		if (error)
 			return (error);