lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Thu, 22 Oct 2015 11:16:50 +0100
From:	David Howells <dhowells@...hat.com>
To:	linux-kernel@...r.kernel.org
Cc:	jack@...e.cz, will.deacon@....com, rostedt@...dmis.org,
	dhowells@...hat.com, pmladek@...e.cz, dwmw2@...radead.org
Subject: [PATCH] printk: Don't discard earlier unprinted messages to make
 space

printk() currently discards earlier messages to make space for new messages
arriving.  This has the distinct downside that if the kernel starts
churning out messages because of some initial incident, the report of the
initial incident is likely to be lost under a blizzard of:

	** NNN printk messages dropped **

messages from console_unlock().

The first message generated (typically an oops) is usually the most
important - the one you want to solve first - so we really want to see
that.

To this end, change log_store() to only write a message into the buffer if
there is sufficient space to hold that message.  The message may be
truncated if it will then fit.

This patch could be improved by noting that some messages got discarded
when next there is space to do so.

Signed-off-by: David Howells <dhowells@...hat.com>
---

 kernel/printk/printk.c |   96 ++++++++++++++++++------------------------------
 1 file changed, 35 insertions(+), 61 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 8f0324ef72ab..c2099ede0bc8 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -46,6 +46,7 @@
 #include <linux/utsname.h>
 #include <linux/ctype.h>
 #include <linux/uio.h>
+#include <linux/circ_buf.h>
 
 #include <asm/uaccess.h>
 
@@ -336,48 +337,6 @@ static u32 log_next(u32 idx)
 	return idx + msg->len;
 }
 
-/*
- * Check whether there is enough free space for the given message.
- *
- * The same values of first_idx and next_idx mean that the buffer
- * is either empty or full.
- *
- * If the buffer is empty, we must respect the position of the indexes.
- * They cannot be reset to the beginning of the buffer.
- */
-static int logbuf_has_space(u32 msg_size, bool empty)
-{
-	u32 free;
-
-	if (log_next_idx > log_first_idx || empty)
-		free = max(log_buf_len - log_next_idx, log_first_idx);
-	else
-		free = log_first_idx - log_next_idx;
-
-	/*
-	 * We need space also for an empty header that signalizes wrapping
-	 * of the buffer.
-	 */
-	return free >= msg_size + sizeof(struct printk_log);
-}
-
-static int log_make_free_space(u32 msg_size)
-{
-	while (log_first_seq < log_next_seq) {
-		if (logbuf_has_space(msg_size, false))
-			return 0;
-		/* drop old messages until we have enough contiguous space */
-		log_first_idx = log_next(log_first_idx);
-		log_first_seq++;
-	}
-
-	/* sequence numbers are equal, so the log buffer is empty */
-	if (logbuf_has_space(msg_size, true))
-		return 0;
-
-	return -ENOMEM;
-}
-
 /* compute the message size including the padding bytes */
 static u32 msg_used_size(u16 text_len, u16 dict_len, u32 *pad_len)
 {
@@ -423,32 +382,47 @@ static int log_store(int facility, int level,
 		     const char *text, u16 text_len)
 {
 	struct printk_log *msg;
-	u32 size, pad_len;
+	u32 size, wsize, pad_len;
 	u16 trunc_msg_len = 0;
 
 	/* number of '\0' padding bytes to next message */
 	size = msg_used_size(text_len, dict_len, &pad_len);
 
-	if (log_make_free_space(size)) {
-		/* truncate the message if it is too long for empty buffer */
-		size = truncate_msg(&text_len, &trunc_msg_len,
-				    &dict_len, &pad_len);
-		/* survive when the log buffer is too small for trunc_msg */
-		if (log_make_free_space(size))
-			return 0;
-	}
+	/* See if we have sufficient space to insert a message.  Note we also
+	 * need to keep a gap right at the end of the buffer to insert a 'wrap
+	 * here' marker.
+	 */
+	wsize = size + sizeof(struct printk_log);
 
-	if (log_next_idx + size + sizeof(struct printk_log) > log_buf_len) {
-		/*
-		 * This message + an additional empty header does not fit
-		 * at the end of the buffer. Add an empty header with len == 0
-		 * to signify a wrap around.
-		 */
-		memset(log_buf + log_next_idx, 0, sizeof(struct printk_log));
-		log_next_idx = 0;
-	}
+	if (log_first_seq != log_next_seq && log_first_idx == log_next_idx)
+		return 0; /* Buffer is completely full */
+
+	if (CIRC_SPACE_TO_END(log_next_idx, log_first_idx, log_buf_len) >= wsize)
+		goto have_space_no_wrap;
+
+	if (CIRC_SPACE(log_next_idx, log_first_idx, log_buf_len) >= size)
+		goto have_space_wrap;
+
+	/* Try to truncate the message. */
+	size = truncate_msg(&text_len, &trunc_msg_len, &dict_len, &pad_len);
+	wsize = size + sizeof(struct printk_log);
+
+	if (CIRC_SPACE_TO_END(log_next_idx, log_first_idx, log_buf_len) >= wsize)
+		goto have_space_no_wrap;
+
+	if (CIRC_SPACE(log_next_idx, log_first_idx, log_buf_len) < size)
+		return 0;
+
+have_space_wrap:
+	/* This message plus an additional empty header does not fit at the end
+	 * of the buffer.  Insert an empty header with len == 0 as a wrap
+	 * around marker.
+	 */
+	memset(log_buf + log_next_idx, 0, sizeof(struct printk_log));
+	log_next_idx = 0;
 
-	/* fill message */
+have_space_no_wrap:
+	/* Write the message into the buffer */
 	msg = (struct printk_log *)(log_buf + log_next_idx);
 	memcpy(log_text(msg), text, text_len);
 	msg->text_len = text_len;

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ