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: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Sun, 11 Sep 2022 00:28:10 +0200 (CEST)
From:   Thomas Gleixner <tglx@...utronix.de>
To:     LKML <linux-kernel@...r.kernel.org>
Cc:     John Ogness <john.ogness@...utronix.de>,
        Petr Mladek <pmladek@...e.com>,
        Sergey Senozhatsky <senozhatsky@...omium.org>,
        Steven Rostedt <rostedt@...dmis.org>,
        Linus Torvalds <torvalds@...uxfoundation.org>,
        Peter Zijlstra <peterz@...radead.org>,
        "Paul E. McKenney" <paulmck@...nel.org>,
        Daniel Vetter <daniel@...ll.ch>,
        Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
        Helge Deller <deller@....de>,
        Jason Wessel <jason.wessel@...driver.com>,
        Daniel Thompson <daniel.thompson@...aro.org>,
        John Ogness <jogness@...utronix.de>
Subject: [patch RFC 25/29] printk: Provide functions to emit a ringbuffer
 record on non-BKL consoles

Utilize the shared fill function and add the required safety points to
check for handover/takeover and invoke the atomic write function of the
console driver. Add the proper handling for updating the sequence number.

Co-Developed-by: John Ogness <jogness@...utronix.de>
Signed-off-by: John Ogness <jogness@...utronix.de>
Signed-off-by: Thomas Gleixner <tglx@...utronix.de>
---
 include/linux/console.h      |    7 ++
 kernel/printk/printk_nobkl.c |  107 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 112 insertions(+), 2 deletions(-)

--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -281,10 +281,12 @@ struct console;
  * @newseq:		The sequence number for progress
  * @prio:		Priority of the context
  * @txtbuf:		Pointer to the text buffer for this context
+ * @dropped:		Dropped counter for the current context
  * @thread:		The acquire is printk thread context
  * @hostile:		Hostile takeover requested. Cleared on normal
  *			acquire or friendly handover
  * @spinwait:		Spinwait on acquire if possible
+ * @backlog:		Ringbuffer has pending records
  */
 struct cons_context {
 	struct console		*console;
@@ -297,9 +299,11 @@ struct cons_context {
 	unsigned int		spinwait_max_us;
 	enum cons_prio		prio;
 	struct cons_text_buf	*txtbuf;
+	unsigned long		dropped;
 	unsigned int		thread		: 1;
 	unsigned int		hostile		: 1;
 	unsigned int		spinwait	: 1;
+	unsigned int		backlog		: 1;
 };
 
 /**
@@ -380,6 +384,9 @@ struct console {
 #ifndef CONFIG_64BIT
 	atomic_t __private	atomic_seq;
 #endif
+
+	bool (*write_atomic)(struct console *con, struct cons_write_context *wctxt);
+
 	struct cons_context_data __percpu	*pcpu_data;
 	struct cons_context_data		ctxt_data;
 };
--- a/kernel/printk/printk_nobkl.c
+++ b/kernel/printk/printk_nobkl.c
@@ -328,7 +328,7 @@ static void cons_context_sequence_init(s
  * invalid. Caller has to reacquire the console.
  */
 #ifdef CONFIG_64BIT
-static bool __maybe_unused cons_sequence_try_update(struct cons_context *ctxt)
+static bool cons_sequence_try_update(struct cons_context *ctxt)
 {
 	struct console *con = ctxt->console;
 	struct cons_state old, new;
@@ -354,7 +354,7 @@ static bool __maybe_unused cons_sequence
 	return true;
 }
 #else
-static bool __maybe_unused cons_sequence_try_update(struct cons_context *ctxt)
+static bool cons_sequence_try_update(struct cons_context *ctxt)
 {
 	struct console *con = ctxt->console;
 	unsigned long old, new, cur;
@@ -1006,6 +1006,109 @@ bool console_exit_unsafe(struct cons_wri
 	return __console_update_unsafe(wctxt, false);
 }
 
+static bool cons_fill_outbuf(struct cons_outbuf_desc *desc);
+
+/**
+ * cons_get_record - Fill the buffer with the next pending ringbuffer record
+ * @wctxt:	The write context which will be handed to the write function
+ *
+ * Returns:	True if there are records to print. If the output buffer is
+ *		filled @wctxt->outbuf points to the text, otherwise it is NULL.
+ *
+ *		False signals that there are no pending records anymore and
+ *		the printing can stop.
+ */
+static bool cons_get_record(struct cons_write_context *wctxt)
+{
+	struct cons_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
+	struct console *con = ctxt->console;
+	struct cons_outbuf_desc desc = {
+		.txtbuf		= ctxt->txtbuf,
+		.extmsg		= con->flags & CON_EXTENDED,
+		.seq		= ctxt->newseq,
+		.dropped	= ctxt->dropped,
+	};
+	bool progress = cons_fill_outbuf(&desc);
+
+	ctxt->newseq = desc.seq;
+	ctxt->dropped = desc.dropped;
+
+	wctxt->pos = 0;
+	wctxt->len = desc.len;
+	wctxt->outbuf = desc.outbuf;
+	return progress;
+}
+
+/**
+ * cons_emit_record - Emit record in the acquired context
+ * @wctxt:	The write context which will be handed to the write function
+ *
+ * Returns:	False if the operation was aborted (takeover)
+ *		True otherwise
+ *
+ * In case of takeover the caller is not allowed to touch console state.
+ * The console is owned by someone else. If the caller wants to print
+ * more it has to reacquire the console first.
+ *
+ * If it returns true @wctxt->ctxt.backlog indicates whether there are
+ * still records pending in the ringbuffer,
+ */
+static int __maybe_unused cons_emit_record(struct cons_write_context *wctxt)
+{
+	struct cons_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
+	struct console *con = ctxt->console;
+	bool done = false;
+
+	/*
+	 * @con->dropped is not protected in case of hostile takeovers so
+	 * the update below is racy. Annotate it accordingly.
+	 */
+	ctxt->dropped = data_race(READ_ONCE(con->dropped));
+
+	/* Fill the output buffer with the next record */
+	ctxt->backlog = cons_get_record(wctxt);
+	if (!ctxt->backlog)
+		return true;
+
+	/* Safety point. Don't touch state in case of takeover */
+	if (!console_can_proceed(wctxt))
+		return false;
+
+	/* Counterpart to the read above */
+	WRITE_ONCE(con->dropped, ctxt->dropped);
+
+	/*
+	 * In case of skipped records, Update sequence state in @con.
+	 */
+	if (!wctxt->outbuf)
+		goto update;
+
+	/* Tell the driver about potential unsafe state */
+	wctxt->unsafe = ctxt->state.unsafe;
+
+	if (!ctxt->thread && con->write_atomic) {
+		done = con->write_atomic(con, wctxt);
+	} else {
+		cons_release(ctxt);
+		WARN_ON_ONCE(1);
+		return false;
+	}
+
+	/* If not done, the write was aborted due to takeover */
+	if (!done)
+		return false;
+
+	ctxt->newseq++;
+update:
+	/*
+	 * The sequence update attempt is not part of console_release()
+	 * because in panic situations the console is not released by
+	 * the panic CPU until all records are written. On 32bit the
+	 * sequence is seperate from state anyway.
+	 */
+	return cons_sequence_try_update(ctxt);
+}
+
 /**
  * cons_nobkl_init - Initialize the NOBKL console state
  * @con:	Console to initialize

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ