This series adds SIMPLE_MAX() to be used in places where a stack array
is actually fixed, but the compiler still warns about VLA usage due to
confusion caused by the safety checks in the max() macro.
I'm sending these via -mm since that's where I've introduced SIMPLE_MAX(),
and they should all have no operational differences.
-Kees
In the quest to remove all stack VLAs from the kernel[1], this introduces
a new "simple max" macro, and changes the "sym" array size calculation to
use it. The value is actually a fixed size, but since the max() macro uses
some extensive tricks for safety, it ends up looking like a variable size
to the compiler.
[1] https://lkml.org/lkml/2018/3/7/621
Signed-off-by: Kees Cook <redacted>
---
include/linux/kernel.h | 11 +++++++++++
lib/vsprintf.c | 4 ++--
2 files changed, 13 insertions(+), 2 deletions(-)
In the quest to remove all stack VLAs from the kernel[1], this refactors
the stack array size calculation to avoid using max(), which makes the
compiler think the size isn't fixed.
[1] https://lkml.org/lkml/2018/3/7/621
Signed-off-by: Kees Cook <redacted>
---
net/ipv4/proc.c | 10 ++++------
net/ipv6/proc.c | 10 ++++------
2 files changed, 8 insertions(+), 12 deletions(-)
@@ -432,7 +430,7 @@ static int snmp_seq_show_tcp_udp(struct seq_file *seq, void *v)for(i=0;snmp4_udp_list[i].name;i++)seq_printf(seq," %lu",buff[i]);-memset(buff,0,TCPUDP_MIB_MAX*sizeof(unsignedlong));+memset(buff,0,sizeof(buff));/* the UDP and UDP-Lite MIBs are the same */seq_puts(seq,"\nUdpLite:");
In the quest to remove all stack VLAs from the kernel[1], this refactors
the stack array size calculation to avoid using max(), which makes the
compiler think the size isn't fixed.
[1] https://lkml.org/lkml/2018/3/7/621
Signed-off-by: Kees Cook <redacted>
---
fs/btrfs/tree-checker.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
In the quest to remove all stack VLAs from the kernel[1], this introduces
a new "simple max" macro, and changes the "sym" array size calculation to
use it. The value is actually a fixed size, but since the max() macro uses
some extensive tricks for safety, it ends up looking like a variable size
to the compiler.
[1] https://lkml.org/lkml/2018/3/7/621
Signed-off-by: Kees Cook <redacted>
---
include/linux/kernel.h | 11 +++++++++++
lib/vsprintf.c | 4 ++--
2 files changed, 13 insertions(+), 2 deletions(-)
This will be abused at some point, leading to the usual double
evaluation etc. etc. problems. The name is also too long (and in general
we should avoid adjectives like "simple", "safe", people reading the
code won't know what is simple or safe about it). I think this should work
#define MAX(x, y) (__builtin_choose_expr((x) > (y), x, y))
That forces (x)>(y) to be a compile-time constant, so x and y must also
be; hence there can be no side effects. The MIN version of this could
replace the custom __const_min in fs/file.c, and probably other places
as well.
I tested that this at least works in the vsprintf case, -Wvla no longer
complains. fs/file.c also compiles with the MIN version of this.
I suppose MIN and MAX will collide with other uses in the tree. Hmm.
Rasmus
From: Thomas Gleixner <hidden> Date: 2018-03-08 11:21:23
On Thu, 8 Mar 2018, Rasmus Villemoes wrote:
On 2018-03-08 04:30, Kees Cook wrote:
quoted
/**+ * SIMPLE_MAX - return maximum of two values without any type checking+ * @x: first value+ * @y: second value+ *+ * This should only be used in stack array sizes, since the type-checking+ * from max() confuses the compiler into thinking a VLA is being used.+ */+#define SIMPLE_MAX(x, y) ((size_t)(x) > (size_t)(y) ? (size_t)(x) \+ : (size_t)(y))
This will be abused at some point, leading to the usual double
evaluation etc. etc. problems. The name is also too long (and in general
we should avoid adjectives like "simple", "safe", people reading the
code won't know what is simple or safe about it). I think this should work
#define MAX(x, y) (__builtin_choose_expr((x) > (y), x, y))
That forces (x)>(y) to be a compile-time constant, so x and y must also
be; hence there can be no side effects. The MIN version of this could
replace the custom __const_min in fs/file.c, and probably other places
as well.
I tested that this at least works in the vsprintf case, -Wvla no longer
complains. fs/file.c also compiles with the MIN version of this.
I suppose MIN and MAX will collide with other uses in the tree. Hmm.
Make it CONST_MAX() or something like that which makes it entirely clear.
Thanks,
tglx
From: David Sterba <hidden> Date: 2018-03-08 11:33:33
On Wed, Mar 07, 2018 at 07:30:47PM -0800, Kees Cook wrote:
In the quest to remove all stack VLAs from the kernel[1], this refactors
the stack array size calculation to avoid using max(), which makes the
compiler think the size isn't fixed.
[1] https://lkml.org/lkml/2018/3/7/621
Signed-off-by: Kees Cook <redacted>
Acked-by: David Sterba <dsterba@suse.com>
for whatever name you decide for the max macro.
On Wed, Mar 07, 2018 at 07:30:44PM -0800, Kees Cook wrote:
This series adds SIMPLE_MAX() to be used in places where a stack array
is actually fixed, but the compiler still warns about VLA usage due to
confusion caused by the safety checks in the max() macro.
I'm sending these via -mm since that's where I've introduced SIMPLE_MAX(),
and they should all have no operational differences.
What if we instead simplify the max() macro's type checking so that GCC
can more easily fold the array size constants? The below patch seems to
work:
On Thu, Mar 8, 2018 at 7:02 AM, Josh Poimboeuf [off-list ref] wrote:
On Wed, Mar 07, 2018 at 07:30:44PM -0800, Kees Cook wrote:
quoted
This series adds SIMPLE_MAX() to be used in places where a stack array
is actually fixed, but the compiler still warns about VLA usage due to
confusion caused by the safety checks in the max() macro.
I'm sending these via -mm since that's where I've introduced SIMPLE_MAX(),
and they should all have no operational differences.
What if we instead simplify the max() macro's type checking so that GCC
can more easily fold the array size constants? The below patch seems to
work:
Oooooh magic! Very nice. I couldn't figure out how to do this when I
stared at it. Yes, let me respin. (I assume I can add your S-o-b?)
-Kees
From: Steven Rostedt <rostedt@goodmis.org> Date: 2018-03-08 18:06:33
On Thu, 8 Mar 2018 09:02:36 -0600
Josh Poimboeuf [off-list ref] wrote:
On Wed, Mar 07, 2018 at 07:30:44PM -0800, Kees Cook wrote:
quoted
This series adds SIMPLE_MAX() to be used in places where a stack array
is actually fixed, but the compiler still warns about VLA usage due to
confusion caused by the safety checks in the max() macro.
I'm sending these via -mm since that's where I've introduced SIMPLE_MAX(),
and they should all have no operational differences.
What if we instead simplify the max() macro's type checking so that GCC
can more easily fold the array size constants? The below patch seems to
work:
Nice. Have you tried to do a allmodconfig and build on various archs?
Of course pushing it to kernel.org will have the zero day bot do it for
you ;-)
-- Steve
On Thu, Mar 08, 2018 at 10:02:01AM -0800, Kees Cook wrote:
On Thu, Mar 8, 2018 at 7:02 AM, Josh Poimboeuf [off-list ref] wrote:
quoted
On Wed, Mar 07, 2018 at 07:30:44PM -0800, Kees Cook wrote:
quoted
This series adds SIMPLE_MAX() to be used in places where a stack array
is actually fixed, but the compiler still warns about VLA usage due to
confusion caused by the safety checks in the max() macro.
I'm sending these via -mm since that's where I've introduced SIMPLE_MAX(),
and they should all have no operational differences.
What if we instead simplify the max() macro's type checking so that GCC
can more easily fold the array size constants? The below patch seems to
work:
Oooooh magic! Very nice. I couldn't figure out how to do this when I
stared at it. Yes, let me respin. (I assume I can add your S-o-b?)
I'm going to be traveling for a few days, so I bequeath the patch to
you. You can add my SOB. I agree with Steve's suggestion to run it
through 0-day.
On Wed, Mar 07, 2018 at 07:30:44PM -0800, Kees Cook wrote:
quoted
This series adds SIMPLE_MAX() to be used in places where a stack array
is actually fixed, but the compiler still warns about VLA usage due to
confusion caused by the safety checks in the max() macro.
I'm sending these via -mm since that's where I've introduced SIMPLE_MAX(),
and they should all have no operational differences.
What if we instead simplify the max() macro's type checking so that GCC
can more easily fold the array size constants? The below patch seems to
work:
quoted hunk
+extern long __error_incompatible_types_in_min_macro;+extern long __error_incompatible_types_in_max_macro;++#define __min(t1, t2, x, y) \+ __builtin_choose_expr(__builtin_types_compatible_p(t1, t2), \+ (t1)(x) < (t2)(y) ? (t1)(x) : (t2)(y), \+ (t1)__error_incompatible_types_in_min_macro) /** * 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) \
But this introduces the the-chosen-one-of-x-and-y-gets-evaluated-twice
problem. Maybe we don't care? But until we get a
__builtin_assert_this_has_no_side_effects() I think that's a little
dangerous.
Rasmus
On Thu, Mar 8, 2018 at 11:57 AM, Rasmus Villemoes
[off-list ref] wrote:
On 2018-03-08 16:02, Josh Poimboeuf wrote:
quoted
On Wed, Mar 07, 2018 at 07:30:44PM -0800, Kees Cook wrote:
quoted
This series adds SIMPLE_MAX() to be used in places where a stack array
is actually fixed, but the compiler still warns about VLA usage due to
confusion caused by the safety checks in the max() macro.
I'm sending these via -mm since that's where I've introduced SIMPLE_MAX(),
and they should all have no operational differences.
What if we instead simplify the max() macro's type checking so that GCC
can more easily fold the array size constants? The below patch seems to
work:
quoted
+extern long __error_incompatible_types_in_min_macro;+extern long __error_incompatible_types_in_max_macro;++#define __min(t1, t2, x, y) \+ __builtin_choose_expr(__builtin_types_compatible_p(t1, t2), \+ (t1)(x) < (t2)(y) ? (t1)(x) : (t2)(y), \+ (t1)__error_incompatible_types_in_min_macro) /** * 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) \
But this introduces the the-chosen-one-of-x-and-y-gets-evaluated-twice
problem. Maybe we don't care? But until we get a
__builtin_assert_this_has_no_side_effects() I think that's a little
dangerous.
Eek, yes, we can't do the double-eval. The proposed change breaks
things badly. :)
a: 20
b: 40
max(a++, b++): 40
a: 21
b: 41
a: 20
b: 40
new_max(a++, b++): 41
a: 21
b: 42
However, this works for me:
#define __new_max(t1, t2, max1, max2, x, y) \
__builtin_choose_expr(__builtin_constant_p(x) && \
__builtin_constant_p(y) && \
__builtin_types_compatible_p(t1, t2), \
(t1)(x) > (t2)(y) ? (t1)(x) : (t2)(y), \
__max(t1, t2, max1, max2, x, y))
#define new_max(x, y) \
__new_max(typeof(x), typeof(y), \
__UNIQUE_ID(max1_), __UNIQUE_ID(max2_), \
x, y)
(pardon the whitespace damage...)
Let me spin a sane patch and test it...
-Kees
--
Kees Cook
Pixel Security
From: Andrew Morton <akpm@linux-foundation.org> Date: 2018-03-08 20:49:13
On Thu, 8 Mar 2018 09:02:36 -0600 Josh Poimboeuf [off-list ref] wrote:
On Wed, Mar 07, 2018 at 07:30:44PM -0800, Kees Cook wrote:
quoted
This series adds SIMPLE_MAX() to be used in places where a stack array
is actually fixed, but the compiler still warns about VLA usage due to
confusion caused by the safety checks in the max() macro.
I'm sending these via -mm since that's where I've introduced SIMPLE_MAX(),
and they should all have no operational differences.
What if we instead simplify the max() macro's type checking so that GCC
can more easily fold the array size constants? The below patch seems to
work:
-/*
- * min()/max()/clamp() macros that also do
- * strict type-checking.. See the
- * "unnecessary" pointer comparison.
- */
-#define __min(t1, t2, min1, min2, x, y) ({ \
- t1 min1 = (x); \
- t2 min2 = (y); \
- (void) (&min1 == &min2); \
- min1 < min2 ? min1 : min2; })
+extern long __error_incompatible_types_in_min_macro;
+extern long __error_incompatible_types_in_max_macro;
+
+#define __min(t1, t2, x, y) \
+ __builtin_choose_expr(__builtin_types_compatible_p(t1, t2), \
+ (t1)(x) < (t2)(y) ? (t1)(x) : (t2)(y), \
+ (t1)__error_incompatible_types_in_min_macro)
This will move the error detection from compile-time to link-time.
That's tolerable I guess, but a bit sad and should be flagged in the
changelog at least.
On 8 March 2018 at 21:39, Kees Cook [off-list ref] wrote:
On Thu, Mar 8, 2018 at 11:57 AM, Rasmus Villemoes
[off-list ref] wrote:
quoted
On 2018-03-08 16:02, Josh Poimboeuf wrote:
quoted
On Wed, Mar 07, 2018 at 07:30:44PM -0800, Kees Cook wrote:
+extern long __error_incompatible_types_in_min_macro;
+extern long __error_incompatible_types_in_max_macro;
+
+#define __min(t1, t2, x, y) \
+ __builtin_choose_expr(__builtin_types_compatible_p(t1, t2), \
+ (t1)(x) < (t2)(y) ? (t1)(x) : (t2)(y), \
+ (t1)__error_incompatible_types_in_min_macro)
/**
* 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) \
But this introduces the the-chosen-one-of-x-and-y-gets-evaluated-twice
problem. Maybe we don't care? But until we get a
__builtin_assert_this_has_no_side_effects() I think that's a little
dangerous.
Eek, yes, we can't do the double-eval. The proposed change breaks
things badly. :)
a: 20
b: 40
max(a++, b++): 40
a: 21
b: 41
a: 20
b: 40
new_max(a++, b++): 41
a: 21
b: 42
However, this works for me:
#define __new_max(t1, t2, max1, max2, x, y) \
__builtin_choose_expr(__builtin_constant_p(x) && \
__builtin_constant_p(y) && \
__builtin_types_compatible_p(t1, t2), \
(t1)(x) > (t2)(y) ? (t1)(x) : (t2)(y), \
__max(t1, t2, max1, max2, x, y))
#define new_max(x, y) \
__new_max(typeof(x), typeof(y), \
__UNIQUE_ID(max1_), __UNIQUE_ID(max2_), \
x, y)
Yes, that would seem to do the trick.
Thinking out loud: do we really want or need the
__builtin_types_compatible condition when x and y are compile-time
constants? I think it would be nice to be able to use max(16,
sizeof(bla)) without having to cast either the literal or the sizeof.
Just omitting the type compatibility check might be dangerous, but
perhaps it could be relaxed to a check that both values are
representable in their common promoted type. Something like
(type_signed(t1) == type_signed(t2)) || ((t1)x >= 0 && (t2)y >= 0)
should be safe (if the types have same signedness, or the value of
signed type is positive), though it doesn't allow a few corner cases
(e.g. short vs. unsigned char is always ok due to promotion to int,
and also if the signed type is strictly wider than the unsigned type).
Rasmus
Yes, that would seem to do the trick.
Thinking out loud: do we really want or need the
__builtin_types_compatible condition when x and y are compile-time
constants? I think it would be nice to be able to use max(16,
sizeof(bla)) without having to cast either the literal or the sizeof.
Just omitting the type compatibility check might be dangerous, but
perhaps it could be relaxed to a check that both values are
representable in their common promoted type. Something like
(type_signed(t1) == type_signed(t2)) || ((t1)x >= 0 && (t2)y >= 0)
should be safe (if the types have same signedness, or the value of
signed type is positive), though it doesn't allow a few corner cases
(e.g. short vs. unsigned char is always ok due to promotion to int,
and also if the signed type is strictly wider than the unsigned type).
I agree, it would be nice. However, I think it'd be better to continue
to depend on max_t() for these kinds of cases though. For example:
char foo[max_t(size_t, 6, sizeof(something))];
Works with the proposed patch.
Also, I think this mismatch would already be triggering warnings, so
we shouldn't have any currently.
-Kees
--
Kees Cook
Pixel Security