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-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <aL88Gb6R5M3zhMTb@mozart.vkv.me>
Date: Mon, 8 Sep 2025 13:27:05 -0700
From: Calvin Owens <calvin@...nvd.org>
To: John Ogness <john.ogness@...utronix.de>,
	Breno Leitao <leitao@...ian.org>
Cc: Mike Galbraith <efault@....de>, Simon Horman <horms@...nel.org>,
	kuba@...nel.org, Pavel Begunkov <asml.silence@...il.com>,
	Johannes Berg <johannes@...solutions.net>, paulmck@...nel.org,
	LKML <linux-kernel@...r.kernel.org>, netdev@...r.kernel.org,
	boqun.feng@...il.com
Subject: Re: netconsole: HARDIRQ-safe -> HARDIRQ-unsafe lock order warning

On Friday 09/05 at 14:54 +0206, John Ogness wrote:
> <snip>
>
> NBCON is meant to deprecate @oops_in_progress. However, it is true that
> consoles not implementing ->write_atomic() will never print panic
> output.

Below is a silly little testcase that makes it more convenient to test
if crashes are getting out in a few canned cases, in case anyone else
finds it useful.

Testing this on 6.17-rc5 on a Pi 4b, I don't get any netconsole output
at all for any crash case over wifi, so that already doesn't work. All
the cases currently work over ethernet.

----8<----
From: Calvin Owens <calvin@...nvd.org>
Subject: [PATCH] Quick and dirty testcase for netconsole (and other consoles)

Signed-off-by: Calvin Owens <calvin@...nvd.org>
---
 drivers/tty/Kconfig     |   9 ++
 drivers/tty/Makefile    |   1 +
 drivers/tty/crashtest.c | 178 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 188 insertions(+)
 create mode 100644 drivers/tty/crashtest.c

diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index 149f3d53b760..c0f58943202c 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -424,6 +424,15 @@ config RPMSG_TTY
 	  To compile this driver as a module, choose M here: the module will be
 	  called rpmsg_tty.
 
+config CRASHTEST
+	tristate "Empirical testcase for console crash output"
+	help
+	  Say Y to expose a file at /sys/kernel/debug/crashtest which allows
+	  the kernel to be deliberately crashed in various execution contexts to
+	  prove crash traces can be successfully emitted on the console.
+
+	  To compile this driver as a module, choose M here. If unsure, say N.
+
 endif # TTY
 
 source "drivers/tty/serdev/Kconfig"
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index 07aca5184a55..0448b8285079 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -27,5 +27,6 @@ obj-$(CONFIG_GOLDFISH_TTY)	+= goldfish.o
 obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o
 obj-$(CONFIG_VCC)		+= vcc.o
 obj-$(CONFIG_RPMSG_TTY)		+= rpmsg_tty.o
+obj-$(CONFIG_CRASHTEST)		+= crashtest.o
 
 obj-y += ipwireless/
diff --git a/drivers/tty/crashtest.c b/drivers/tty/crashtest.c
new file mode 100644
index 000000000000..a7b90300d906
--- /dev/null
+++ b/drivers/tty/crashtest.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * # cat /sys/kernel/debug/crashtest
+ * crash_user
+ * crash_user_nobh
+ * crash_user_noirq
+ * crash_user_conlock
+ * crash_user_rtnllock
+ * crash_bh
+ * crash_irq
+ * # echo "crash_user" > /sys/kernel/debug/crashtest
+ */
+
+#include <linux/console.h>
+#include <linux/debugfs.h>
+#include <linux/irq_work.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rtnetlink.h>
+#include <linux/string.h>
+
+static ssize_t __crash(void)
+{
+	pr_emerg("BANG!\n");
+	*(volatile unsigned char *)NULL = '!';
+	return -ENOSYS;
+}
+
+static void __crash_irq_work(struct irq_work *work)
+{
+	__crash();
+}
+
+static struct irq_work irq_crash_work;
+
+static ssize_t crash_irq(void)
+{
+	if (!irq_work_queue(&irq_crash_work))
+		return -EBUSY;
+
+	irq_work_sync(&irq_crash_work);
+	return -ENOSYS;
+}
+
+static void __crash_bh_work(struct work_struct *work)
+{
+	__crash();
+}
+
+static struct work_struct bh_crash_work;
+
+static ssize_t crash_bh(void)
+{
+	if (!queue_work(system_bh_wq, &bh_crash_work))
+		return -EBUSY;
+
+	flush_work(&bh_crash_work);
+	return -ENOSYS;
+}
+
+static ssize_t crash_user(void)
+{
+	return __crash();
+}
+
+static ssize_t crash_user_nobh(void)
+{
+	local_bh_disable();
+	return crash_user();
+}
+
+static ssize_t crash_user_noirq(void)
+{
+	local_irq_disable();
+	return crash_user();
+}
+
+static ssize_t crash_user_conlock(void)
+{
+	console_lock();
+	return crash_user();
+}
+
+static ssize_t crash_user_rtnllock(void)
+{
+	rtnl_lock();
+	return crash_user();
+}
+
+struct crashtest_case {
+	ssize_t (*fn)(void);
+	const char *str;
+};
+
+#define CRASHTEST_CASE(fn_) \
+	(struct crashtest_case){.fn = fn_, .str = #fn_ "\n"}
+
+static const struct crashtest_case tests[] = {
+	CRASHTEST_CASE(crash_user),
+	CRASHTEST_CASE(crash_user_nobh),
+	CRASHTEST_CASE(crash_user_noirq),
+	CRASHTEST_CASE(crash_user_conlock),
+	CRASHTEST_CASE(crash_user_rtnllock),
+	CRASHTEST_CASE(crash_bh),
+	CRASHTEST_CASE(crash_irq),
+};
+
+static ssize_t crashtest_write(struct file *file, const char __user *u_buf,
+			       size_t u_len, loff_t *u_off)
+{
+	char buf[32] = {0};
+	unsigned i;
+
+	if (copy_from_user(buf, u_buf, min(u_len, sizeof(buf) - 1)) != 0)
+		return -EFAULT;
+
+	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
+		if (!strcmp(tests[i].str, buf))
+			return tests[i].fn();
+
+	return -EEXIST;
+}
+
+static ssize_t crashtest_read(struct file *file, char __user *u_buf,
+			      size_t u_len, loff_t *u_off)
+{
+	ssize_t ret = 0;
+	unsigned i;
+
+	if (*u_off > 0)
+		return 0;
+
+	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+		unsigned long len, done;
+
+		len = strlen(tests[i].str);
+		done = len - copy_to_user(u_buf, tests[i].str, min(u_len, len));
+		u_len -= done;
+		u_buf += done;
+		ret += done;
+		if (done != len)
+			break;
+	}
+
+	*u_off += ret;
+	return ret;
+}
+
+static const struct file_operations crashtest_fops = {
+	.write = crashtest_write,
+	.read = crashtest_read,
+};
+
+static struct dentry *crashtest_dentry;
+
+static int __init setup_crashtest(void)
+{
+	INIT_WORK(&bh_crash_work, __crash_bh_work);
+	init_irq_work(&irq_crash_work, __crash_irq_work);
+	crashtest_dentry = debugfs_create_file("crashtest", 0600, NULL, NULL,
+					       &crashtest_fops);
+	if (IS_ERR(crashtest_dentry))
+		return PTR_ERR(crashtest_dentry);
+
+	return 0;
+}
+
+static void __exit cleanup_crashtest(void)
+{
+	debugfs_remove(crashtest_dentry);
+}
+
+late_initcall(setup_crashtest);
+module_exit(cleanup_crashtest);
+
+MODULE_AUTHOR("Calvin Owens <calvin@...nvd.org>");
+MODULE_DESCRIPTION("Empirical testcase for console crash output");
+MODULE_LICENSE("GPL");
-- 
2.47.2


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ