]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
dmesg: fix off-by-one read buffer size
authorBrian Mak <makb@juniper.net>
Thu, 28 May 2026 19:08:04 +0000 (12:08 -0700)
committerBrian Mak <makb@juniper.net>
Fri, 29 May 2026 19:27:10 +0000 (12:27 -0700)
PRINTK_MESSAGE_MAX is 2048 in the kernel. In a formatted record that is
exactly 2048 bytes, reading /proc/kmsg with a size of PRINTK_MESSAGE_MAX
- 1 (2047) will result in the read syscall returning -EINVAL.

We see such a case when using a large initrd, for which the kernel
outputs loading spinner characters, based on the size of the initrd. For
a large enough initrd, there will be enough spinner characters to create
several formatted records of size 2048.

We fix this by increasing the kmsg_buf size by 1, which increases the
size used by the read syscall to PRINTK_MESSAGE_MAX (2048).

Signed-off-by: Brian Mak <makb@juniper.net>
sys-utils/dmesg.c

index 15a0d1e6b86985c1183099a30f191577cec2e2f0..e39ec34a8512bc8a66da5c1b7e82f1d4177533a4 100644 (file)
@@ -75,6 +75,8 @@
 #define DMESG_CALLER_PREFIX "caller="
 #define DMESG_CALLER_PREFIXSZ (sizeof(DMESG_CALLER_PREFIX)-1)
 
+#define PRINTK_MESSAGE_MAX 2048
+
 /*
  * Color scheme
  */
@@ -211,12 +213,14 @@ struct dmesg_control {
        int             kmsg;           /* /dev/kmsg file descriptor */
        ssize_t         kmsg_first_read;/* initial read() return code */
        /*
-        * the kernel will give EINVAL if we do read() on /proc/kmsg with
-        * length insufficient for the next message. messages may be up to
-        * PRINTK_MESSAGE_MAX, which is defined as 2048, so we must be
-        * able to buffer at least that much in one call
+        * The kernel will give -EINVAL if we do read() on /proc/kmsg with
+        * length insufficient for the next message. Messages may be up to
+        * PRINTK_MESSAGE_MAX, which is defined as 2048, so the read() must
+        * use a size of at least that. We pass into read(), the size of
+        * kmsg_buf - 1. Therefore, kmsg_buf must have a size of at least
+        * PRINTK_MESSAGE_MAX + 1 bytes long.
         */
-       char            kmsg_buf[2048]; /* buffer to read kmsg data */
+       char            kmsg_buf[PRINTK_MESSAGE_MAX + 1]; /* kmsg data buffer */
 
        usec_t          since;          /* filter records by time */
        usec_t          until;          /* filter records by time */