Received: by 10.213.65.68 with SMTP id h4csp67105imn; Mon, 26 Mar 2018 15:18:34 -0700 (PDT) X-Google-Smtp-Source: AIpwx4/3KSN7Qem94bfnCtkX923ZL0JExW41mKR6nKwjm+OO5I7YK/0arRZh1YOHDPVFOaeEC0Ip X-Received: by 2002:a17:902:76c4:: with SMTP id j4-v6mr1547025plt.31.1522102714215; Mon, 26 Mar 2018 15:18:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1522102714; cv=none; d=google.com; s=arc-20160816; b=sHys6nHI3P76up9AyT0OY9fmKceDxsVFxF46V0RW+KdU2jOiwSmlTxwWlFX9CCz/Tr 5+3VDKQMR+MJc/LEiXAd4o8p0EM+qYKqn+F6PcIrR28t3e1+Ifv9/7sneFXOZGYzDGPn RU99/yPaJItjhFm3tvZgb0+VxY+4EhE7PcZRktcG2Yr9zgatYXidPeo/vYOT4dwpb7Bn OXHlM2hleWRyc6xhdgVqoBU1wullK4YBhjnVlI+v4LvRMe/CkL+bt6LkQ5HtWvGZ3WvB c/6hNH/aGcTncXyOoOatX23pTk4STEzN98SAh5RrZqD44ONu44/98UpVO3w5Brp2LaFf V59w== 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 :content-disposition:mime-version:message-id:subject:cc:to:from:date :dkim-signature:arc-authentication-results; bh=bundRCztckITz26EtBwzhlsHkVwpszMpBvcXimcL9Wk=; b=oYA1J2owMF4FiEXfxYxT7OVcMbpHXlGar+LmfGWCx3lz9zju3BBSNdzFvm/RSYQkm2 cMbpG1XI+CXz7lx7oJ1Wyh0Mmb/A56dOeI6/USQoTConfpDLfSrYCXpjylJ/1cJ4wbVt tI8S7m6jbEDn78QfRbmkWl6D/OdAQk0ItItZBqz8DSOaXdLQploBC+nsG1sxNy7r4kkb +9VQBvyQocLi9Q1/WBTN7NwX1l5tREO/1DSLd/2uAKMQihqONdoJpLGyOEFzLZPwMigY qqX5KzTWnLaLi/+7ZQz6AEjoN2Z1FHq/VP8Xh5Nb2d3R/FmBmmtDBQEj05Fg9Ni5eyMc +23g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=n9htcguo; 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=NONE dis=NONE) header.from=chromium.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f123si462654pfa.364.2018.03.26.15.18.19; Mon, 26 Mar 2018 15:18:34 -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=@chromium.org header.s=google header.b=n9htcguo; 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=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752177AbeCZWP6 (ORCPT + 99 others); Mon, 26 Mar 2018 18:15:58 -0400 Received: from mail-pf0-f195.google.com ([209.85.192.195]:33707 "EHLO mail-pf0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752065AbeCZWP5 (ORCPT ); Mon, 26 Mar 2018 18:15:57 -0400 Received: by mail-pf0-f195.google.com with SMTP id f15so2339195pfn.0 for ; Mon, 26 Mar 2018 15:15:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=date:from:to:cc:subject:message-id:mime-version:content-disposition :content-transfer-encoding; bh=bundRCztckITz26EtBwzhlsHkVwpszMpBvcXimcL9Wk=; b=n9htcguoZFvXAGZmf5lFA/PaUnfW6KuIBpptty6Ma0EM6ODBgp6oBbrzE+FgJSscte ln056RqKtYHSB6PsUzEquTnAFM/mwndJ4JqW6nCjJ5JMji7M5orD3A1U7ACAqrnQ1ZWM R2f7ngGwMtkizDTG/Qev0oiK8noRcYxgSN/Z8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-disposition:content-transfer-encoding; bh=bundRCztckITz26EtBwzhlsHkVwpszMpBvcXimcL9Wk=; b=knQyw/SKb7s8ZyQgvy+EmlbR+4kwvhyr8d8A/5dADKpQoXrKV35VGeXQnMc60kQoM3 7Jn5kfcRnLiIgK6cOlnXGHVepdfxnL4UKrgvpZcVOFlkLHLZaKlXm0BkMUHIQkKIz216 YWCWGJ0zXQrM6m1o2suzUjfM9WKWzXZfVzzh6k5C1B4KjXacMtUro9vi4Wtc1781UE1w LgoupOaa1/gKSho097NXoL8SX4al+zX43qoJGfWclYE4nfH8EUtQzWI0FvlxqaeAxlZv dYmVnYZOaXTl5m3/KnEsVOJ3+kYWBUGSjAfJUn2vgCbSJEPdENoXmP0d0VCW2YPJFGM8 /Wfw== X-Gm-Message-State: AElRT7F5+0XmC1fi4xNFD8RAaP+QZkFI4c+ik4UnGtWTqfDxUNtcp6xU WvbYWFzTZu9Vv9gyjfjnbfqlPA== X-Received: by 10.98.7.83 with SMTP id b80mr11514687pfd.133.1522102556775; Mon, 26 Mar 2018 15:15:56 -0700 (PDT) Received: from www.outflux.net (173-164-112-133-Oregon.hfc.comcastbusiness.net. [173.164.112.133]) by smtp.gmail.com with ESMTPSA id j23sm28914229pfi.78.2018.03.26.15.15.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 26 Mar 2018 15:15:55 -0700 (PDT) Date: Mon, 26 Mar 2018 15:15:54 -0700 From: Kees Cook To: Andrew Morton Cc: Linus Torvalds , Martin Uecker , Josh Poimboeuf , Rasmus Villemoes , Randy Dunlap , Miguel Ojeda , Ingo Molnar , David Laight , Ian Abbott , linux-kernel@vger.kernel.org, kernel-hardening@lists.openwall.com Subject: [PATCH v6] kernel.h: Retain constant expression output for max()/min() Message-ID: <20180326221554.GA45166@beast> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 with 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 ‘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] 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_core.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_TIMEOUT_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_TIMEOUT_C) +#define TIS_TIMEOUT_D_MAX max_t(int, TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_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_mode 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 == (typeof(y)*)1))) + +/* + * This returns a constant expression while determining if an argument is + * a constant expression, most importantly without evaluating the argument. + * Glory to Martin Uecker */ -#define __min(t1, t2, min1, min2, x, y) ({ \ - t1 min1 = (x); \ - t2 min2 = (y); \ - (void) (&min1 == &min2); \ - min1 < min2 ? min1 : min2; }) +#define __is_constant(x) \ + (sizeof(int) == sizeof(*(1 ? ((void*)((long)(x) * 0l)) : (int*)1))) + +#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 = (x); \ + typeof(y) __y = (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, op)) /** * 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 = (x); \ - t2 max2 = (y); \ - (void) (&max1 == &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