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-next>] [day] [month] [year] [list]
Message-ID: <20131015155806.04e2613f@gandalf.local.home>
Date:	Tue, 15 Oct 2013 15:58:06 -0400
From:	Steven Rostedt <rostedt@...dmis.org>
To:	LKML <linux-kernel@...r.kernel.org>
Cc:	Linus Torvalds <torvalds@...ux-foundation.org>,
	"H. Peter Anvin" <hpa@...ux.intel.com>,
	Ingo Molnar <mingo@...nel.org>,
	Peter Zijlstra <peterz@...radead.org>,
	Thomas Gleixner <tglx@...utronix.de>,
	Andrew Morton <akpm@...ux-foundation.org>,
	Frederic Weisbecker <fweisbec@...il.com>,
	"Liu, Chuansheng" <chuansheng.liu@...el.com>
Subject: [PATCH] bug: Use xchg() to update WARN_ON_ONCE() static variable

The WARN_ON_ONCE() code is to trigger a waring only once when some
condition happens. But due to the way it is written it is racy.

	if (unlikely(condition)) {
		if (WARN(!__warned))
			__warned = true;
	}

The problem is that multiple CPUs could hit the same warning and
produce multiple output dumps of the same warning, or an interrupt could
happen and hit the same warning and do the warning in the middle of a
previous one, especially since the WARN() does a dump of the current
stack.

Even more of a problem, a recent WARN_ON_ONCE() that was in the page
fault handler triggered and the stack dump of the WARN() caused the
same WARN_ON_ONCE() get hit again. Since the __warned = true is not
updated until after the WARN() is completed, each WARN() triggered
another page fault causing the stack to be filled and crashed the box.

The point of WARN_ON() is to warn the user and not to crash the box.

The easy fix is to update the __warned variable with a xchg(). This way
only one WARN_ON_ONCE() will actually happen, and prevents any issues
of the WARN() causing the same WARN() to be hit and crash the system.

[ Fixed the WARN() whitespace offset of a '\' while I was at it ]

Signed-off-by: Steven Rostedt <rostedt@...dmis.org>

diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index 7d10f96..ab7ebdb 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -11,6 +11,7 @@
 
 #ifndef __ASSEMBLY__
 #include <linux/kernel.h>
+#include <asm/cmpxchg.h>
 
 #ifdef CONFIG_BUG
 
@@ -91,7 +92,7 @@ extern void warn_slowpath_null(const char *file, const int line);
 #endif
 
 #ifndef WARN
-#define WARN(condition, format...) ({						\
+#define WARN(condition, format...) ({					\
 	int __ret_warn_on = !!(condition);				\
 	if (unlikely(__ret_warn_on))					\
 		__WARN_printf(format);					\
@@ -134,32 +135,29 @@ extern void warn_slowpath_null(const char *file, const int line);
 #endif
 
 #define WARN_ON_ONCE(condition)	({				\
-	static bool __section(.data.unlikely) __warned;		\
+	static int __section(.data.unlikely) __warned;		\
 	int __ret_warn_once = !!(condition);			\
 								\
 	if (unlikely(__ret_warn_once))				\
-		if (WARN_ON(!__warned)) 			\
-			__warned = true;			\
+		WARN_ON(!xchg(&__warned, 1));			\
 	unlikely(__ret_warn_once);				\
 })
 
 #define WARN_ONCE(condition, format...)	({			\
-	static bool __section(.data.unlikely) __warned;		\
+	static int __section(.data.unlikely) __warned;		\
 	int __ret_warn_once = !!(condition);			\
 								\
 	if (unlikely(__ret_warn_once))				\
-		if (WARN(!__warned, format)) 			\
-			__warned = true;			\
+		WARN(!xchg(&__warned, 1), format);		\
 	unlikely(__ret_warn_once);				\
 })
 
 #define WARN_TAINT_ONCE(condition, taint, format...)	({	\
-	static bool __section(.data.unlikely) __warned;		\
+	static int __section(.data.unlikely) __warned;		\
 	int __ret_warn_once = !!(condition);			\
 								\
 	if (unlikely(__ret_warn_once))				\
-		if (WARN_TAINT(!__warned, taint, format))	\
-			__warned = true;			\
+		WARN_TAINT(!xchg(&__warned, 1), taint, format);	\
 	unlikely(__ret_warn_once);				\
 })
 
--
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