Received: by 10.213.65.68 with SMTP id h4csp476511imn; Tue, 27 Mar 2018 03:05:25 -0700 (PDT) X-Google-Smtp-Source: AG47ELv8/e36Tm3OaYhhQpTZA/SdzaFKHeB63YM2oGGSA53NvjJw27q0iNVKyPvUsAs8PcxQ9X5A X-Received: by 10.98.237.12 with SMTP id u12mr35870147pfh.72.1522145125111; Tue, 27 Mar 2018 03:05:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1522145125; cv=none; d=google.com; s=arc-20160816; b=UCk1IbRmvHp+n6mqyWkFLzj3AnR3UNnYyPE6PoyAzOOyIaphG1foeYCoVGGSjXFYJO xE7C/HJ1E3JgQvylaUsmUq6sjtF5Iuev8KmURpLIu6rGrDYKneX99cnWvWHxLyORGgOL 4hSpIDkMKc9igw/wAzZYVW9W3Oe9hqbksatfOfqw/5N/cVwyKCzX6iNHPnuG7QreuGbS tCT6WG8QJxu6/19xeSyf21RG/sc35bR7uMoy0DFZ59vytLJzBOweVbbrzW9z0hq1qW9L uUNjVJG5LvwBtUPLZCEjs08FrBnS3xYwx7IWGTtjICmvEdSRw7DQ/e9nCFt0OWqQavy1 J/lw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:cc:to:subject :message-id:date:from:references:in-reply-to:mime-version :dkim-signature:arc-authentication-results; bh=nmEL/SzZlxtp+BBojcJditYaIft8SbhvGmQ9fxpPOgU=; b=vJtX4XEmYpP2qU6AVtpMVGobclSmHjeWThsqRg1jKrN8Hfj7YmvpyvSInGhoJUFG8P WGdwt4d8KqVKa6iT1F/ilXt1yHAAeO61Lrbv8HIIebKC/XkPffLVAQxg6FbHcxoYGWyv lLOHlZc1ET34MCa4Yyo1YMRvlTlbrPpWWPu0WO7FGQjrfcVEAj9v6+iZPA+qX7swlYc4 Xhgj1k8i87fjM+bZzbYmFgREaPSaJYkrqT9Lrxf4LNyj65ExBj5QA0SPmmiZruTsRvqG blIlHD/D7SoiXchsQJiG7+rC0a7srASzVPS247YcsMsinJH0G8zBQshYMl0jiSBVBuKw KSFA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=uHEO4rkU; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 79si637063pga.440.2018.03.27.03.05.10; Tue, 27 Mar 2018 03:05:25 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=uHEO4rkU; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752310AbeC0KDi (ORCPT + 99 others); Tue, 27 Mar 2018 06:03:38 -0400 Received: from mail-qt0-f196.google.com ([209.85.216.196]:33618 "EHLO mail-qt0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752269AbeC0KDf (ORCPT ); Tue, 27 Mar 2018 06:03:35 -0400 Received: by mail-qt0-f196.google.com with SMTP id i8so23163669qtj.0 for ; Tue, 27 Mar 2018 03:03:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc:content-transfer-encoding; bh=nmEL/SzZlxtp+BBojcJditYaIft8SbhvGmQ9fxpPOgU=; b=uHEO4rkUbhWYh/n79MOSOqqb2e5ymy5YFn4sFAgCNuLy4UCqWUtgWjL6LbGTBgq2iK 0RQm/n0JB/Etv30MLt7Zo3jmZ/Z+tgS8d4ebEhTHimFEsYDeWzx4XIPXO6uqQZLLkYI+ xJtG1rKxq+fmhhf0IUHLJajCdYGDQjTlZfV073gLjgg3uN7dTImqDNT94ujS3yl1MclY WjNHb+vhf+3f0IsAgZ+VSZY1J5LhNK+WbltRxpdNOmEXyin+O3Aj27tSPpN27ZfcDDNR s4QH5GNGl1hWBszgQ0Uv7uQXD+2kb2P5jgGLg5r7hMDuV7MtKrvQtPP4s7Kszo04P/rB /YXg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc:content-transfer-encoding; bh=nmEL/SzZlxtp+BBojcJditYaIft8SbhvGmQ9fxpPOgU=; b=T2xvfuQSZJHD7QJn9nJWzEG2Gh4DyRsL2wT5vxOv/1+DZQ7m5WvQ2jIgXdRIHlu4sQ sKseZ4QRduolk+cKpNsWIGq18ungYUwMlLpUzuNsDlLoNvbZ+03dTQQBMlDpjT2p4SI1 Os+EgYEXp7ONrCAfeGzABpqjPi/5UCT0sQFK3pRjH7qVG57uc2edX5SnLHyqCt6C5GNB NaMdl4rlAeMpjUUI1VE6g307zhbH8avsvxGm21KME4mSyBR//abLcVB6Bki5qTKscxec 0MJ/iykzNs0hhj/xXbcq6c+RtpjceXd+VVIAKRf+brGq5Yf18Z0GgWZy0KZKcJwLdPAr 4vaA== X-Gm-Message-State: AElRT7HT1+D/ADh4mfLx+m63e/QEFgD710YA4plRG8D8iLtRfqLayzJ1 SFzhYCzIQuW5GBLZ2AoKelr/bl6LY0qX6O+etig= X-Received: by 10.237.36.167 with SMTP id t36mr63462908qtc.136.1522145014245; Tue, 27 Mar 2018 03:03:34 -0700 (PDT) MIME-Version: 1.0 Received: by 10.200.52.227 with HTTP; Tue, 27 Mar 2018 03:03:13 -0700 (PDT) In-Reply-To: <20180326221554.GA45166@beast> References: <20180326221554.GA45166@beast> From: Miguel Ojeda Date: Tue, 27 Mar 2018 12:03:13 +0200 Message-ID: Subject: Re: [PATCH v6] kernel.h: Retain constant expression output for max()/min() To: Kees Cook Cc: Andrew Morton , Linus Torvalds , Martin Uecker , Josh Poimboeuf , Rasmus Villemoes , Randy Dunlap , Ingo Molnar , David Laight , Ian Abbott , linux-kernel , Kernel Hardening Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Tue, Mar 27, 2018 at 12:15 AM, Kees Cook wrote: > In the effort to remove all VLAs from the kernel[1], it is desirable to > build with -Wvla. However, this warning is overly pessimistic, in that > it is only happy with stack array sizes that are declared as constant > expressions, and not constant values. One case of this is the evaluation > of the max() macro which, due to its construction, ends up converting > constant expression arguments into a constant value result. > > All attempts to rewrite this macro with __builtin_constant_p() failed wit= h > older compilers (e.g. gcc 4.4)[2]. However, Martin Uecker constructed[3] = a > mind-shattering solution that works everywhere. Cthulhu fhtagn! > > This patch updates the min()/max() macros to evaluate to a constant > expression when called on constant expression arguments. This removes > several false-positive stack VLA warnings from an x86 allmodconfig > build when -Wvla is added: > > $ diff -u before.txt after.txt | grep ^- > -drivers/input/touchscreen/cyttsp4_core.c:871:2: warning: ISO C90 forbids= variable length array =E2=80=98ids=E2=80=99 [-Wvla] > -fs/btrfs/tree-checker.c:344:4: warning: ISO C90 forbids variable length = array =E2=80=98namebuf=E2=80=99 [-Wvla] > -lib/vsprintf.c:747:2: warning: ISO C90 forbids variable length array =E2= =80=98sym=E2=80=99 [-Wvla] > -net/ipv4/proc.c:403:2: warning: ISO C90 forbids variable length array = =E2=80=98buff=E2=80=99 [-Wvla] > -net/ipv6/proc.c:198:2: warning: ISO C90 forbids variable length array = =E2=80=98buff=E2=80=99 [-Wvla] > -net/ipv6/proc.c:218:2: warning: ISO C90 forbids variable length array = =E2=80=98buff64=E2=80=99 [-Wvla] > > This also updates the one case where different enums were being compared > and explicitly casts them to int (which matches the old side-effect of > the single-evaluation code). > > [1] https://lkml.org/lkml/2018/3/7/621 > [2] https://lkml.org/lkml/2018/3/10/170 > [3] https://lkml.org/lkml/2018/3/20/845 > > Co-Developed-by: Linus Torvalds > Co-Developed-by: Martin Uecker > Signed-off-by: Kees Cook > --- > Let's see if this one sticks! > --- > drivers/char/tpm/tpm_tis_core.h | 8 ++--- > include/linux/kernel.h | 71 ++++++++++++++++++++++++-----------= ------ > 2 files changed, 45 insertions(+), 34 deletions(-) > > diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_c= ore.h > index d5c6a2e952b3..f6e1dbe212a7 100644 > --- a/drivers/char/tpm/tpm_tis_core.h > +++ b/drivers/char/tpm/tpm_tis_core.h > @@ -62,10 +62,10 @@ enum tis_defaults { > /* Some timeout values are needed before it is known whether the chip is > * TPM 1.0 or TPM 2.0. > */ > -#define TIS_TIMEOUT_A_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_A) > -#define TIS_TIMEOUT_B_MAX max(TIS_LONG_TIMEOUT, TPM2_TIMEOUT_B) > -#define TIS_TIMEOUT_C_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_C) > -#define TIS_TIMEOUT_D_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_D) > +#define TIS_TIMEOUT_A_MAX max_t(int, TIS_SHORT_TIMEOUT, TPM2_TIMEOU= T_A) > +#define TIS_TIMEOUT_B_MAX max_t(int, TIS_LONG_TIMEOUT, TPM2_TIMEOUT= _B) > +#define TIS_TIMEOUT_C_MAX max_t(int, TIS_SHORT_TIMEOUT, TPM2_TIMEOU= T_C) > +#define TIS_TIMEOUT_D_MAX max_t(int, TIS_SHORT_TIMEOUT, TPM2_TIMEOU= T_D) > > #define TPM_ACCESS(l) (0x0000 | ((l) << 12)) > #define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12)) > diff --git a/include/linux/kernel.h b/include/linux/kernel.h > index 3fd291503576..a2c1b2a382dd 100644 > --- a/include/linux/kernel.h > +++ b/include/linux/kernel.h > @@ -783,41 +783,58 @@ static inline void ftrace_dump(enum ftrace_dump_mod= e oops_dump_mode) { } > #endif /* CONFIG_TRACING */ > > /* > - * min()/max()/clamp() macros that also do > - * strict type-checking.. See the > - * "unnecessary" pointer comparison. > + * min()/max()/clamp() macros must accomplish three things: > + * > + * - avoid multiple evaluations of the arguments (so side-effects like > + * "x++" happen only once) when non-constant. > + * - perform strict type-checking (to generate warnings instead of > + * nasty runtime surprises). See the "unnecessary" pointer comparison > + * in __typecheck(). > + * - retain result as a constant expressions when called with only > + * constant expressions (to avoid tripping VLA warnings in stack > + * allocation usage). > + */ > +#define __typecheck(x, y) \ > + (!!(sizeof((typeof(x)*)1 =3D=3D (typeof(y)*)1))) > + > +/* > + * This returns a constant expression while determining if an argument i= s > + * a constant expression, most importantly without evaluating the argume= nt. > + * Glory to Martin Uecker > */ > -#define __min(t1, t2, min1, min2, x, y) ({ \ > - t1 min1 =3D (x); \ > - t2 min2 =3D (y); \ > - (void) (&min1 =3D=3D &min2); \ > - min1 < min2 ? min1 : min2; }) > +#define __is_constant(x) \ > + (sizeof(int) =3D=3D sizeof(*(1 ? ((void*)((long)(x) * 0l)) : (int= *)1))) I think Linus suggested __is_constant, but what about __is_constexpr instead? It makes the intention a bit more clear and follows the C++'s specifier. Acked-by: Miguel Ojeda Cheers, Miguel > + > +#define __no_side_effects(x, y) \ > + (__is_constant(x) && __is_constant(y)) > + > +#define __safe_cmp(x, y) \ > + (__typecheck(x, y) && __no_side_effects(x, y)) > + > +#define __cmp(x, y, op) ((x) op (y) ? (x) : (y)) > + > +#define __cmp_once(x, y, op) ({ \ > + typeof(x) __x =3D (x); \ > + typeof(y) __y =3D (y); \ > + __cmp(__x, __y, op); }) > + > +#define __careful_cmp(x, y, op) \ > + __builtin_choose_expr(__safe_cmp(x, y), \ > + __cmp(x, y, op), __cmp_once(x, y, o= p)) > > /** > * 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 __max(t1, t2, max1, max2, x, y) ({ \ > - t1 max1 =3D (x); \ > - t2 max2 =3D (y); \ > - (void) (&max1 =3D=3D &max2); \ > - max1 > max2 ? max1 : max2; }) > +#define min(x, y) __careful_cmp(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) __careful_cmp(x, y, >) > > /** > * min3 - return minimum of three values > @@ -869,10 +886,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(t, x, y) __careful_cmp((t)(x), (t)(y), <) > > /** > * max_t - return maximum of two values, using the specified type > @@ -880,10 +894,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(t, x, y) __careful_cmp((t)(x), (t)(y), >) > > /** > * clamp_t - return a value clamped to a given range using a given type > -- > 2.7.4 > > > -- > Kees Cook > Pixel Security