linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3] kernel.h: Skip single-eval logic on literals in min()/max()
@ 2018-03-09 20:05 Kees Cook
  2018-03-09 21:10 ` Linus Torvalds
  2018-03-10  0:07 ` Andrew Morton
  0 siblings, 2 replies; 51+ messages in thread
From: Kees Cook @ 2018-03-09 20:05 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-kernel, Josh Poimboeuf, Rasmus Villemoes,
	Gustavo A. R. Silva, Tobin C. Harding, Steven Rostedt,
	Jonathan Corbet, Chris Mason, Josef Bacik, David Sterba,
	David S. Miller, Alexey Kuznetsov, Hideaki YOSHIFUJI,
	Ingo Molnar, Peter Zijlstra, Thomas Gleixner, Masahiro Yamada,
	Borislav Petkov, Randy Dunlap, Ian Abbott, Sergey Senozhatsky,
	Petr Mladek, Andy Shevchenko, Pantelis Antoniou, Linux Btrfs,
	Network Development, Kernel Hardening

When max() is used in stack array size calculations from literal values
(e.g. "char foo[max(sizeof(struct1), sizeof(struct2))]", the compiler
thinks this is a dynamic calculation due to the single-eval logic, which
is not needed in the literal case. This change removes several accidental
stack VLAs from an x86 allmodconfig build:

$ diff -u before.txt after.txt | grep ^-
-drivers/input/touchscreen/cyttsp4_core.c:871:2: warning: ISO C90 forbids variable length array ‘ids’ [-Wvla]
-fs/btrfs/tree-checker.c:344:4: warning: ISO C90 forbids variable length array ‘namebuf’ [-Wvla]
-lib/vsprintf.c:747:2: warning: ISO C90 forbids variable length array ‘sym’ [-Wvla]
-net/ipv4/proc.c:403:2: warning: ISO C90 forbids variable length array ‘buff’ [-Wvla]
-net/ipv6/proc.c:198:2: warning: ISO C90 forbids variable length array ‘buff’ [-Wvla]
-net/ipv6/proc.c:218:2: warning: ISO C90 forbids variable length array ‘buff64’ [-Wvla]

Based on an earlier patch from Josh Poimboeuf.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
v3:
- drop __builtin_types_compatible_p() (Rasmus, Linus)
v2:
- fix copy/paste-o max1_/max2_ (ijc)
- clarify "compile-time" constant in comment (Rasmus)
- clean up formatting on min_t()/max_t()
---
 include/linux/kernel.h | 48 ++++++++++++++++++++++++++++++------------------
 1 file changed, 30 insertions(+), 18 deletions(-)

diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 3fd291503576..a0fca4deb3ab 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -787,37 +787,55 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
  * strict type-checking.. See the
  * "unnecessary" pointer comparison.
  */
-#define __min(t1, t2, min1, min2, x, y) ({		\
+#define __single_eval_min(t1, t2, min1, min2, x, y) ({	\
 	t1 min1 = (x);					\
 	t2 min2 = (y);					\
 	(void) (&min1 == &min2);			\
 	min1 < min2 ? min1 : min2; })
 
+/*
+ * In the case of compile-time constant values, there is no need to do
+ * the double-evaluation protection, so the raw comparison can be made.
+ * This allows min()/max() to be used in stack array allocations and
+ * avoid the compiler thinking it is a dynamic value leading to an
+ * accidental VLA.
+ */
+#define __min(t1, t2, x, y)						\
+	__builtin_choose_expr(__builtin_constant_p(x) &&		\
+			      __builtin_constant_p(y),			\
+			      (t1)(x) < (t2)(y) ? (t1)(x) : (t2)(y),	\
+			      __single_eval_min(t1, t2,			\
+						__UNIQUE_ID(min1_),	\
+						__UNIQUE_ID(min2_),	\
+						x, y))
+
 /**
  * min - return minimum of two values of the same or compatible types
  * @x: first value
  * @y: second value
  */
-#define min(x, y)					\
-	__min(typeof(x), typeof(y),			\
-	      __UNIQUE_ID(min1_), __UNIQUE_ID(min2_),	\
-	      x, y)
+#define min(x, y)	__min(typeof(x), typeof(y), x, y)
 
-#define __max(t1, t2, max1, max2, x, y) ({		\
+#define __single_eval_max(t1, t2, max1, max2, x, y) ({	\
 	t1 max1 = (x);					\
 	t2 max2 = (y);					\
 	(void) (&max1 == &max2);			\
 	max1 > max2 ? max1 : max2; })
 
+#define __max(t1, t2, x, y)						\
+	__builtin_choose_expr(__builtin_constant_p(x) &&		\
+			      __builtin_constant_p(y),			\
+			      (t1)(x) > (t2)(y) ? (t1)(x) : (t2)(y),	\
+			      __single_eval_max(t1, t2,			\
+						__UNIQUE_ID(max1_),	\
+						__UNIQUE_ID(max2_),	\
+						x, y))
 /**
  * max - return maximum of two values of the same or compatible types
  * @x: first value
  * @y: second value
  */
-#define max(x, y)					\
-	__max(typeof(x), typeof(y),			\
-	      __UNIQUE_ID(max1_), __UNIQUE_ID(max2_),	\
-	      x, y)
+#define max(x, y)	__max(typeof(x), typeof(y), x, y)
 
 /**
  * min3 - return minimum of three values
@@ -869,10 +887,7 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
  * @x: first value
  * @y: second value
  */
-#define min_t(type, x, y)				\
-	__min(type, type,				\
-	      __UNIQUE_ID(min1_), __UNIQUE_ID(min2_),	\
-	      x, y)
+#define min_t(type, x, y)	 __min(type, type, x, y)
 
 /**
  * max_t - return maximum of two values, using the specified type
@@ -880,10 +895,7 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
  * @x: first value
  * @y: second value
  */
-#define max_t(type, x, y)				\
-	__max(type, type,				\
-	      __UNIQUE_ID(min1_), __UNIQUE_ID(min2_),	\
-	      x, y)
+#define max_t(type, x, y)	__max(type, type, x, y)
 
 /**
  * clamp_t - return a value clamped to a given range using a given type
-- 
2.7.4


-- 
Kees Cook
Pixel Security

^ permalink raw reply related	[flat|nested] 51+ messages in thread
* [PATCH 0/3] tracing: Rewrite the function filter code
@ 2018-03-10  2:34 Steven Rostedt
  2018-03-10  2:34 ` [PATCH 1/3] tracing: Combine enum and arrays into single macro in " Steven Rostedt
                   ` (3 more replies)
  0 siblings, 4 replies; 51+ messages in thread
From: Steven Rostedt @ 2018-03-10  2:34 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Al Viro, Tom Zanussi, Namhyung Kim,
	Masami Hiramatsu, Jiri Olsa


Al Viro reviewed the ftrace event filter logic and was horrified. He wrote
Tom and I a lengthy private email with a formal proof on how to do it
simpler as well as more efficient.

Currently the filter logic creates a binary search tree (with some
optimizations), and walks it to get a result.

Say we had the following filter: a && !(!b || c) || d && !e
Where each letter is a predicate. A tree would be made to look something
like:

             ||
            /  \
          &&    &&
         /  |   | \
        a  !||  d  !e
           /  \
          !b   c

If a == 1, b == 1, c == 1, d == 1, e == 0, then all nodes would be walked.

 || -> && -> a -> && -> !|| -> !b -> !|| -> c -> !|| -> && -> || -> && ->
 d -> && -> !e -> && -> || -> return TRUE!

That's 16 steps across vertices.

Al's method would create a program using an array that denotes the predicate
function, when to branch, and a target to branch to if the value is the same
as when to branch. Storing the array as:

 prog[0] = { a, 0, 2}; // predicate, when_to_branch, target
 prog[1] = { b, 0, 2};
 prog[2] = { c, 0, 4};
 prog[3] = { d, 0, 5};
 prog[4] = { e, 1, 5};
 prog[5] = { NULL, 0, 1}; // TRUE
 prog[6] = { NULL, 0, 0}; // FALSE

Where the code to execute the above looks like:

	for (i = 0; prog[i].pred; i++) {
		struct filter_pred *pred = prog[i].pred;
		int match = pred->fn(pred, rec);
		if (match == prog[i].when_to_branch)
			i = prog[i].target;
	}
	return prog[i].target;

Which translates the above program array into:

 n0: if (!a) goto n3;
 n1: if (!b) goto n3;
 n2: if (!c) goto T;
 n3: if (!d) goto F;
 n4: if (e) goto F;
 T: return TRUE;
 F: return FALSE;

And the above example only takes 6 steps to return TRUE.

Special thanks goes out to Al for his patience and his time that he spent in
educating us in a proper logical parser.

Two patches were added to do some initial clean up. The last patch
implements Al's suggestions. I wrote up a very lengthy comment describing
what Al taught us in my own words (hopefully I got it right), and the
implementation is similar to what Al showed with a few changes (again,
hopefully I got that right too). I tested this with lots of different
filters and it looks to be holding up.


 Jiri,

This affects perf as well. I ran some tests and I believe I got
it woking as it does today.

Steven Rostedt (VMware) (3):
      tracing: Combine enum and arrays into single macro in filter code
      tracing: Clean up and document pred_funcs_##type creation and use
      tracing: Rewrite filter logic to be simpler and faster

----
 kernel/trace/trace.h               |   15 +-
 kernel/trace/trace_events_filter.c | 2372 ++++++++++++++++--------------------
 2 files changed, 1083 insertions(+), 1304 deletions(-)

^ permalink raw reply	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2018-03-14 11:35 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-09 20:05 [PATCH v3] kernel.h: Skip single-eval logic on literals in min()/max() Kees Cook
2018-03-09 21:10 ` Linus Torvalds
2018-03-09 21:47   ` Kees Cook
2018-03-11 22:46   ` Tobin C. Harding
2018-03-13 13:31   ` David Laight
2018-03-10  0:07 ` Andrew Morton
2018-03-10  0:28   ` Linus Torvalds
2018-03-10  0:32     ` Andrew Morton
2018-03-10  0:38       ` Linus Torvalds
2018-03-10  1:30         ` Kees Cook
2018-03-10  1:31           ` Kees Cook
2018-03-10  2:37             ` Linus Torvalds
2018-03-12 22:55           ` Andrew Morton
2018-03-12 23:57             ` Linus Torvalds
2018-03-13  4:28               ` Kees Cook
2018-03-13 21:02                 ` Andrew Morton
2018-03-13 22:14                   ` Kees Cook
2018-03-14 11:35                     ` David Laight
2018-03-10  3:11   ` Randy Dunlap
2018-03-10  6:10     ` Miguel Ojeda
2018-03-10  7:03       ` Miguel Ojeda
2018-03-10 16:04         ` Linus Torvalds
2018-03-10 15:33       ` Kees Cook
2018-03-10 16:11         ` Linus Torvalds
2018-03-10 16:30         ` Linus Torvalds
2018-03-10 17:34           ` Miguel Ojeda
2018-03-10 17:51             ` Linus Torvalds
2018-03-10 19:08               ` Miguel Ojeda
2018-03-11 11:05               ` Ingo Molnar
2018-03-11 18:23                 ` Linus Torvalds
2018-03-10  2:34 [PATCH 0/3] tracing: Rewrite the function filter code Steven Rostedt
2018-03-10  2:34 ` [PATCH 1/3] tracing: Combine enum and arrays into single macro in " Steven Rostedt
2018-03-12 10:31   ` Masami Hiramatsu
2018-03-10  2:34 ` [PATCH 2/3] tracing: Clean up and document pred_funcs_##type creation and use Steven Rostedt
2018-03-12 13:42   ` Masami Hiramatsu
2018-03-10  2:34 ` [PATCH 3/3] tracing: Rewrite filter logic to be simpler and faster Steven Rostedt
2018-03-10  3:10   ` Steven Rostedt
2018-03-10  3:15     ` Steven Rostedt
2018-03-10  3:22       ` Steven Rostedt
2018-03-10  3:18   ` Steven Rostedt
2018-03-12 12:42   ` Jiri Olsa
2018-03-12 18:38     ` Steven Rostedt
2018-03-12 15:10   ` Jiri Olsa
2018-03-12 18:40     ` Steven Rostedt
2018-03-12 18:54       ` Jiri Olsa
2018-03-12 19:10         ` Steven Rostedt
2018-03-12 23:52         ` Steven Rostedt
2018-03-13 10:14           ` Jiri Olsa
2018-03-13 14:12             ` Steven Rostedt
2018-03-13 14:27               ` Jiri Olsa
2018-03-11 19:54 ` [PATCH 0/3] tracing: Rewrite the function filter code Jiri Olsa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).