Message ID | 20240301044428.work.411-kees@kernel.org |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel+bounces-87897-ouuuleilei=gmail.com@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7301:2097:b0:108:e6aa:91d0 with SMTP id gs23csp859306dyb; Thu, 29 Feb 2024 20:45:02 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCWHn8tlr5oj72Kjv082sIra+Qa4N1uVWF6M+vs39kroVjxq2gCiX9FMGEsRfwWeZJRRnXBGpuNRtzTUsBZ8dAcEbVwixQ== X-Google-Smtp-Source: AGHT+IEcLOsCqVhBAY0nBvPge9RCdHv7ImbqfGW8WYc8h+7a92tk4Lhs//HT3HqdJ+7eM1ni9fzz X-Received: by 2002:a05:620a:891:b0:788:bd9:ae2 with SMTP id b17-20020a05620a089100b007880bd90ae2mr280805qka.59.1709268302580; Thu, 29 Feb 2024 20:45:02 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1709268302; cv=pass; d=google.com; s=arc-20160816; b=Z9N0lBqhLcFCLDWL/Na3oB50OhjbMLr9uEQeHzgvume4e/+fI35Usr3O8Sr/ZmT5j6 mAvako4fzEEJ9IcZ+pfHBBlSkRZEeOVuyS2V6uZvt4VuglDKNXCGR2bfkCvtbe0MqQ1I sOw6PAtyTVJ+a7GZSzh1we1cDAq0zLi0rJZUAauJ5uDwMnpqe9tOtPFGzG64Fmxnk5U7 SjM1+fEiAzzsvIFsRmcE+TKmGUdXJIXcYMgfooCjnpV7LqkIgEIMSOY1/OmZdjOU07oa Z+68T3BUNI+zHM7g2pa6mUruZ/DETEkgLI4smEsMDlBaWoOxAUDlu0eV1DuhofL+3aDT z/MQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:message-id:date:subject:cc:to :from:dkim-signature; bh=LUicd2n6ht+rA5byppQHy+nx4IzWcP+LTMq589jP68Y=; fh=mOoFkM6HpBk93tYefMVBf2HHtDQNuhaZ+wsr5CWKCj4=; b=WHMGvc8ej187Flmc08rpAdXAbkQmMrtPciiNZSQWhlXqlnjpE11gsWEzu735nb9ADS LaSBJ+EJf0rPY5YXTo2SDh9sjAX34YvsCDb8x9TURsjwR4f8Lvq6WDK755dkNurSdoJH 0jmnC9xevFiTLe98L9g0Wz6tWxhpstzkMFm1u3BK39SKLgSG8gQSpivfS8pyw9+HEZLi b122F7jHWh5Ytn1u41wgd5OeK9MaGnCriyIo1jnGZjjGR0GD79qdxxUfEBr5nm44L33h aO+0PVXIYw/J0JypfUnoI8UmGctfJeRsnWd69i4YWfiaz0CYnI0TC/TbJ9aa1AyHRV5Q xj9w==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b="SsL/ZEBw"; arc=pass (i=1 spf=pass spfdomain=chromium.org dkim=pass dkdomain=chromium.org dmarc=pass fromdomain=chromium.org); spf=pass (google.com: domain of linux-kernel+bounces-87897-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-87897-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [147.75.199.223]) by mx.google.com with ESMTPS id c18-20020a05620a0cf200b00787329ed625si2726270qkj.756.2024.02.29.20.45.02 for <ouuuleilei@gmail.com> (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Feb 2024 20:45:02 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-87897-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) client-ip=147.75.199.223; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b="SsL/ZEBw"; arc=pass (i=1 spf=pass spfdomain=chromium.org dkim=pass dkdomain=chromium.org dmarc=pass fromdomain=chromium.org); spf=pass (google.com: domain of linux-kernel+bounces-87897-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-87897-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 5F8801C22D6E for <ouuuleilei@gmail.com>; Fri, 1 Mar 2024 04:45:02 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 634A450A60; Fri, 1 Mar 2024 04:44:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="SsL/ZEBw" Received: from mail-oi1-f172.google.com (mail-oi1-f172.google.com [209.85.167.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7994052F7A for <linux-kernel@vger.kernel.org>; Fri, 1 Mar 2024 04:44:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1709268284; cv=none; b=m2QM8rvea5/WC40hC2BH6Oyl3tsUQvU16WlHyR5nhDlzBewUKtqJ7boj8a1yq8nPChO1J86dWKyHwZsOSFGYfqGto/efa3MZc5ltMZBw5lBd9QnWwjT9zVBQX/I65lu9gqMBA68F0z2QN2n+VjMeGRPen4anpLmXg98bBVNtw0w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1709268284; c=relaxed/simple; bh=mZCSNoaZZKbSakFDmMwKoymVUugJ1bVB7eASshxhkHw=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=GODu8cVgNNbReDZ++TQ7TZap1FhT/hXkKucYgYASyU2LpZ629wFoUYNP2ANwc7SBYWe8X9k+04dg8RAEiaQWLrAe0o2tw5jUItBy9Wn3ToJ/3ms3B+Xl530bLujYWQDOTJ4ai30wwlXeYerMHJVOAiTUxft+1Jow5+ZX9ovX1eg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org; spf=pass smtp.mailfrom=chromium.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b=SsL/ZEBw; arc=none smtp.client-ip=209.85.167.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=chromium.org Received: by mail-oi1-f172.google.com with SMTP id 5614622812f47-3bd72353d9fso984679b6e.3 for <linux-kernel@vger.kernel.org>; Thu, 29 Feb 2024 20:44:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1709268281; x=1709873081; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=LUicd2n6ht+rA5byppQHy+nx4IzWcP+LTMq589jP68Y=; b=SsL/ZEBwo4yOajF83l3tWeE3zUcqp7+MGFhG1sukjrLqR79CRZRqIeh5V84tuW/a72 s3HVZoy3P2td1BHQR1YxsPK/2MOlCSm4QbWKiLbVFq/vWo5o1kJOnEluOV6zp6sxwt6O TXFIiZwxoMgHcfhzz6uQnnC5aBpEpaw9nK2fk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1709268281; x=1709873081; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=LUicd2n6ht+rA5byppQHy+nx4IzWcP+LTMq589jP68Y=; b=Us7rC7fjZczdGEaazKmKVGl42mHaEFw6kwSK7+vm/rEexNcy/xgJakvkN2jKq83sRx I5+BPiU/5HIWSnEMfeN9nExzhZYut3vW3LFSsVEL1jZ86vZe568gJrVZp13oqRf45kVo NmtWnFrYmYp4jrogNw3CNZmB1sj29eNKV+eE26yVwUhsmpt508K2q38VqPDK/aKNQv8A MMTwqqt6NTkQY/zEYP/kg4Ag8IQ5TUL8M62uLkNCqJ6LXQO0+YTR5GJdYyOVXbvp6CR8 OPpovdebLWwMWEbF2IP5Nu5/qE72Hce/oZen+e8NzsMHNrhh2VVUJ4nhMRByo9pNzwW0 szjQ== X-Forwarded-Encrypted: i=1; AJvYcCVIMcsHvw3l8iy3cXYx0ye0N5BQeNKH57sQ2QFVb3IP7GcBQ9TpSXVe9X+91CaeAFQNS4bdgaATiKCRVxT7UBioz2Us5VpvGreIMFr2 X-Gm-Message-State: AOJu0YyymE6LfRPa5VFxt4hWvXY//9AqaCG+EfSjSJviN8CmppBF1QFK qZEafw+LYP9N55rw7UeVbRYdz7WkrLm2TP5D9CNUTvg9a6bx7QkowOErlZuTRPcIsZ1gGhmFEcE = X-Received: by 2002:a05:6808:bc8:b0:3c1:663e:ceb2 with SMTP id o8-20020a0568080bc800b003c1663eceb2mr831324oik.24.1709268281588; Thu, 29 Feb 2024 20:44:41 -0800 (PST) Received: from www.outflux.net ([198.0.35.241]) by smtp.gmail.com with ESMTPSA id se3-20020a17090b518300b00296fd5e0de1sm4444309pjb.34.2024.02.29.20.44.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Feb 2024 20:44:41 -0800 (PST) From: Kees Cook <keescook@chromium.org> To: Rasmus Villemoes <linux@rasmusvillemoes.dk> Cc: Kees Cook <keescook@chromium.org>, "Gustavo A . R . Silva" <gustavoars@kernel.org>, Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>, Jani Nikula <jani.nikula@linux.intel.com>, David Laight <David.Laight@aculab.com>, Nick Desaulniers <ndesaulniers@google.com>, Martin Uecker <Martin.Uecker@med.uni-goettingen.de>, Jonathan Corbet <corbet@lwn.net>, linux-doc@vger.kernel.org, Miguel Ojeda <ojeda@kernel.org>, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Subject: [PATCH] compiler.h: Explain how __is_constexpr() works Date: Thu, 29 Feb 2024 20:44:37 -0800 Message-Id: <20240301044428.work.411-kees@kernel.org> X-Mailer: git-send-email 2.34.1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: <linux-kernel.vger.kernel.org> List-Subscribe: <mailto:linux-kernel+subscribe@vger.kernel.org> List-Unsubscribe: <mailto:linux-kernel+unsubscribe@vger.kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=3830; i=keescook@chromium.org; h=from:subject:message-id; bh=mZCSNoaZZKbSakFDmMwKoymVUugJ1bVB7eASshxhkHw=; b=owEBbQKS/ZANAwAKAYly9N/cbcAmAcsmYgBl4V01DNueOMxKBHs1UNYi4cYy1NODxLhYG/ufE zM5XYdHsWuJAjMEAAEKAB0WIQSlw/aPIp3WD3I+bhOJcvTf3G3AJgUCZeFdNQAKCRCJcvTf3G3A JvsWD/41meKbJvTmmS63eBbTW06592QnHpGowqbBjGfTc/aFd2X9Y5fyc1502V1dr2w1pFO9mhD k4zOwkMno3DeB8ls+aLkQ+IG0qv2mBAT+sKkYUlTd2d04/e6PgwF/wKaEGGefhxhhFbbIyme616 3fZ1By98Hs9K3QbuMNAD8/1ns7gRqsm8whwJACqeEVPJcmVUG7CYqw0xv+OyvLSLb9b2gVe/vav +aNTSrCHBaEG6X/SUZYK9Ms45l8R8MRdo4lVnyWWmFXFKtkiftdogKeDMbDcb4IMtbNo6khAW06 1cboFMV7ZcvZF49NhMkxN/du3mjyhWZfN2CpcHo2PiU2CM3dHX2itJl/AKT/nrlSl1TnUaduxSM aRU48jYdYspLBfe5MDHPoIfvE2e7vip5KxyVLzuTDDTsI+s45N4jHSEukiiKNljLkV2t8J4mC7S DPkoAEdEYaleWvakf94egJdxCPE8F723bHoBvSgvcr1P8u8hVPhXHRyraYXcuaZipZewdT5JQ9B rev2s5GZJLLvnJrfYMN9sR9SO3DvmS6GODRBzjD+u00isEXqM8EQUs0MlitaXcob6r9/5XIcpKp 3bCK0SFvjhdlPxiSKaOZSEjVzOiQ5xybHyVsdY27A/qvPJfRdjsEu/hf/cHqR3dEfc5WDAxmM2+ Rb1bEsY JaZm7f4Q== X-Developer-Key: i=keescook@chromium.org; a=openpgp; fpr=A5C3F68F229DD60F723E6E138972F4DFDC6DC026 Content-Transfer-Encoding: 8bit X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1792297719757963358 X-GMAIL-MSGID: 1792297719757963358 |
Series |
compiler.h: Explain how __is_constexpr() works
|
|
Commit Message
Kees Cook
March 1, 2024, 4:44 a.m. UTC
The __is_constexpr() macro is dark magic. Shed some light on it with a comment to explain how and why it works. Acked-by: Gustavo A. R. Silva <gustavoars@kernel.org> Signed-off-by: Kees Cook <keescook@chromium.org> --- Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk> Cc: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> Cc: Jani Nikula <jani.nikula@linux.intel.com> Cc: David Laight <David.Laight@aculab.com> Cc: Nick Desaulniers <ndesaulniers@google.com> Cc: Martin Uecker <Martin.Uecker@med.uni-goettingen.de> Cc: Jonathan Corbet <corbet@lwn.net> Cc: linux-doc@vger.kernel.org v2: *thread necromancy* rewrite based on feedback to v1 v1: https://lore.kernel.org/all/20220131204357.1133674-1-keescook@chromium.org/ --- include/linux/compiler.h | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+)
Comments
On Thu, 29 Feb 2024, Kees Cook <keescook@chromium.org> wrote: > The __is_constexpr() macro is dark magic. Shed some light on it with > a comment to explain how and why it works. Hey, it was a fun little puzzle to figure out using the C standard. Now you're ruining it for everyone! ;) The description matches my recollection of how it works. Especially the meaning of the first 8 threw me off way back when. And looks like I've replied to that effect for v1. FWIW, Reviewed-by: Jani Nikula <jani.nikula@intel.com> but I'm sure there are more pedantic reviewers for all the minor details. > > Acked-by: Gustavo A. R. Silva <gustavoars@kernel.org> > Signed-off-by: Kees Cook <keescook@chromium.org> > --- > Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk> > Cc: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> > Cc: Jani Nikula <jani.nikula@linux.intel.com> > Cc: David Laight <David.Laight@aculab.com> > Cc: Nick Desaulniers <ndesaulniers@google.com> > Cc: Martin Uecker <Martin.Uecker@med.uni-goettingen.de> > Cc: Jonathan Corbet <corbet@lwn.net> > Cc: linux-doc@vger.kernel.org > v2: *thread necromancy* rewrite based on feedback to v1 > v1: https://lore.kernel.org/all/20220131204357.1133674-1-keescook@chromium.org/ > --- > include/linux/compiler.h | 39 +++++++++++++++++++++++++++++++++++++++ > 1 file changed, 39 insertions(+) > > diff --git a/include/linux/compiler.h b/include/linux/compiler.h > index bb1339c7057b..38cd9f3c8f6a 100644 > --- a/include/linux/compiler.h > +++ b/include/linux/compiler.h > @@ -231,6 +231,45 @@ static inline void *offset_to_ptr(const int *off) > * This returns a constant expression while determining if an argument is > * a constant expression, most importantly without evaluating the argument. > * Glory to Martin Uecker <Martin.Uecker@med.uni-goettingen.de> > + * > + * Details: > + * - sizeof() return an integer constant expression, and does not evaluate > + * the value of its operand; it only examines the type of its operand. > + * - The results of comparing two integer constant expressions is also > + * an integer constant expression. > + * - The first literal "8" isn't important. It could be any literal value. > + * - The second literal "8" is to avoid warnings about unaligned pointers; > + * this could otherwise just be "1". > + * - (long)(x) is used to avoid warnings about 64-bit types on 32-bit > + * architectures. > + * - The C Standard defines "null pointer constant", "(void *)0", as > + * distinct from other void pointers. > + * - If (x) is an integer constant expression, then the "* 0l" resolves > + * it into an integer constant expression of value 0. Since it is cast to > + * "void *", this makes the second operand a null pointer constant. > + * - If (x) is not an integer constant expression, then the second operand > + * resolves to a void pointer (but not a null pointer constant: the value > + * is not an integer constant 0). > + * - The conditional operator's third operand, "(int *)8", is an object > + * pointer (to type "int"). > + * - The behavior (including the return type) of the conditional operator > + * ("operand1 ? operand2 : operand3") depends on the kind of expressions > + * given for the second and third operands. This is the central mechanism > + * of the macro: > + * - When one operand is a null pointer constant (i.e. when x is an integer > + * constant expression) and the other is an object pointer (i.e. our > + * third operand), the conditional operator returns the type of the > + * object pointer operand (i.e. "int *). Here, within the sizeof(), we > + * would then get: > + * sizeof(*((int *)(...)) == sizeof(int) == 4 > + * - When one operand is a void pointer (i.e. when x is not an integer > + * constant expression) and the other is an object pointer (i.e. our > + * third operand), the conditional operator returns a "void *" type. > + * Here, within the sizeof(), we would then get: > + * sizeof(*((void *)(...)) == sizeof(void) == 1 > + * - The equality comparison to "sizeof(int)" therefore depends on (x): > + * sizeof(int) == sizeof(int) (x) was a constant expression > + * sizeof(int) != sizeof(void) (x) was not a constant expression > */ > #define __is_constexpr(x) \ > (sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))
From: Kees Cook > Sent: 01 March 2024 04:45 > To: Rasmus Villemoes <linux@rasmusvillemoes.dk> > > The __is_constexpr() macro is dark magic. Shed some light on it with > a comment to explain how and why it works. All the 8s don't help... I don't think you need that much explanation. Perhaps just saying that the type of ?: depends on the types of the values and is independent of the condition. The type of (0 ? (void *)p : (foo *)q) is normally 'void *' (so that both values can be assigned to it). But if 'p' is 'an integer constant expression with value 0' then (void *)p is NULL and the type is 'foo *'. The type can then be checked to find out it 'p' is constant 0. A non-zero constant 'p' can be multiples by 0. I need to replace the definition with (the more portable): #define __if_constexpr(cond, if_const, if_not_const) \ _Generic(0 ? (void *)((long)(cond) * 0) : (char *)0, \ char *: (if_const), \ void *: (if_not_const)) which is arguably less cryptic. #define __is_constexpr(cond) __if_constexpr(cond, 1, 0) So that I can write: #define is_non_neg_const(x) (__if_constexpr(x, x , -1) >= 0) and avoid the compiler bleating about some comparisons in unreachable code. David - Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
BTW my main email addess is now: uecker@tugraz.at My suggestion would also to limit explanation. Nobody should write such code and if you need to, you can find explanations all over the internet. Finally, I still think the motivation for this macro (removing VLAs) is misguided if security is the goal because VLAs provide precise bounds and larger worst-case fixed-size arrays do not. It would be better to use the compiler options that detect possibly use of VLAs of unbounded size and if there a problems with this, improve this on the compiler side. Martin Am Freitag, dem 01.03.2024 um 09:32 +0000 schrieb David Laight: > From: Kees Cook > > Sent: 01 March 2024 04:45 > > To: Rasmus Villemoes <linux@rasmusvillemoes.dk> > > > > The __is_constexpr() macro is dark magic. Shed some light on it with > > a comment to explain how and why it works. > > All the 8s don't help... > > I don't think you need that much explanation. > > Perhaps just saying that the type of ?: depends on the types > of the values and is independent of the condition. > The type of (0 ? (void *)p : (foo *)q) is normally 'void *' > (so that both values can be assigned to it). > But if 'p' is 'an integer constant expression with value 0' > then (void *)p is NULL and the type is 'foo *'. > > The type can then be checked to find out it 'p' is constant 0. > A non-zero constant 'p' can be multiples by 0. > > I need to replace the definition with (the more portable): > #define __if_constexpr(cond, if_const, if_not_const) \ > _Generic(0 ? (void *)((long)(cond) * 0) : (char *)0, \ > char *: (if_const), \ > void *: (if_not_const)) > which is arguably less cryptic. > > #define __is_constexpr(cond) __if_constexpr(cond, 1, 0) > > So that I can write: > #define is_non_neg_const(x) (__if_constexpr(x, x , -1) >= 0) > and avoid the compiler bleating about some comparisons > in unreachable code. > > David > > - > Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK > Registration No: 1397386 (Wales) >
From: Uecker, Martin > Sent: 01 March 2024 13:22 > > My suggestion would also to limit explanation. Nobody should > write such code and if you need to, you can find explanations > all over the internet. > > Finally, I still think the motivation for this macro (removing > VLAs) is misguided if security is the goal because VLAs provide > precise bounds and larger worst-case fixed-size arrays do not. > > It would be better to use the compiler options that detect > possibly use of VLAs of unbounded size and if there a problems > with this, improve this on the compiler side. In kernel code (with limited stack) there has to be enough room for the largest possible 'VLA' so you might as well allocate one. Allowing VLA also makes it pretty much impossible to do any kind of static stack use analysis. The fine IBT tags can be used identify valid indirect calls which pretty much only leaves recursion stopping full static stack analysis - and that could be banned except for a few limited cases where 1 level could be permittd. is_constexpr() has other uses - there are places where __builtin_constant_p() isn't strong enough. Particularly if you need to use builtin_choose_expr() or _Generic() to get select a type. For instance, if you can a constant value between 0 and MAXINT it is safe to cast to/from unsigned in order change any implicit integer promotion cast that may be grief some. David - Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Am Freitag, dem 01.03.2024 um 13:43 +0000 schrieb David Laight: > From: Uecker, Martin > > Sent: 01 March 2024 13:22 > > > > My suggestion would also to limit explanation. Nobody should > > write such code and if you need to, you can find explanations > > all over the internet. > > > > Finally, I still think the motivation for this macro (removing > > VLAs) is misguided if security is the goal because VLAs provide > > precise bounds and larger worst-case fixed-size arrays do not. > > > > It would be better to use the compiler options that detect > > possibly use of VLAs of unbounded size and if there a problems > > with this, improve this on the compiler side. > > In kernel code (with limited stack) there has to be enough room > for the largest possible 'VLA' so you might as well allocate one. > > Allowing VLA also makes it pretty much impossible to do any > kind of static stack use analysis. If you limit VLAs to a certain maximum size, then you could use this for analysis and it would not be worse than using worst case fixed-size array on the stack. But you can also use the *precise* run-time bound of the VLA if your static analysis is smart enough. You can also use the precise run-time bound for run-time bounds checking. It is strictly more expressive to use VLAs (or dependent types in general) and therefor *good* for static analysis. > The fine IBT tags can be used identify valid indirect calls > which pretty much only leaves recursion stopping full static > stack analysis - and that could be banned except for a few > limited cases where 1 level could be permittd. > > is_constexpr() has other uses - there are places where > __builtin_constant_p() isn't strong enough. > Particularly if you need to use builtin_choose_expr() > or _Generic() to get select a type. > > For instance, if you can a constant value between 0 and MAXINT > it is safe to cast to/from unsigned in order change any > implicit integer promotion cast that may be grief some. glad to hear it is useful. Martin > > David > > - > Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK > Registration No: 1397386 (Wales)
On Sat, Mar 02, 2024 at 03:17:32AM +0200, Andy Shevchenko wrote: > Thu, Feb 29, 2024 at 08:44:37PM -0800, Kees Cook kirjoitti: > > The __is_constexpr() macro is dark magic. Shed some light on it with > > a comment to explain how and why it works. > > I was under impression that somebody did it already once and it fell through > cracks when has been moved (?) to compiler.h. I tried to do it before (see the v1). > > Ah, now I see it, https://lore.kernel.org/all/YKeghxRY4FeOKuwb@smile.fi.intel.com/. > It was asked, but till now never fulfilled (maybe Reported-by:/Closes: tag?). Sure! akpm was hardly the first to ask about it, but yeah, makes for some good tags. Reported-by: Andrew Morton <akpm@linux-foundation.org> Closes: https://lore.kernel.org/all/20210520134112.ee15f156f1b7dbd3d8f16471@linux-foundation.org/ :) > And explanation before was given here: > https://stackoverflow.com/questions/49481217/linux-kernels-is-constexpr-macro. Sure, but I wanted something that lived with the macro and everyone was happy with the details. -Kees
On Thu, Feb 29, 2024 at 8:44 PM Kees Cook <keescook@chromium.org> wrote: > > The __is_constexpr() macro is dark magic. Shed some light on it with > a comment to explain how and why it works. > > Acked-by: Gustavo A. R. Silva <gustavoars@kernel.org> > Signed-off-by: Kees Cook <keescook@chromium.org> Is Documentation/kernel-hacking/hacking.rst perhaps a more appropriate place for this block of text? Perhaps as another :c:macro: in that file? You know I'm not a big fan of increasing header size, even if it is just a comment.
diff --git a/include/linux/compiler.h b/include/linux/compiler.h index bb1339c7057b..38cd9f3c8f6a 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -231,6 +231,45 @@ static inline void *offset_to_ptr(const int *off) * This returns a constant expression while determining if an argument is * a constant expression, most importantly without evaluating the argument. * Glory to Martin Uecker <Martin.Uecker@med.uni-goettingen.de> + * + * Details: + * - sizeof() return an integer constant expression, and does not evaluate + * the value of its operand; it only examines the type of its operand. + * - The results of comparing two integer constant expressions is also + * an integer constant expression. + * - The first literal "8" isn't important. It could be any literal value. + * - The second literal "8" is to avoid warnings about unaligned pointers; + * this could otherwise just be "1". + * - (long)(x) is used to avoid warnings about 64-bit types on 32-bit + * architectures. + * - The C Standard defines "null pointer constant", "(void *)0", as + * distinct from other void pointers. + * - If (x) is an integer constant expression, then the "* 0l" resolves + * it into an integer constant expression of value 0. Since it is cast to + * "void *", this makes the second operand a null pointer constant. + * - If (x) is not an integer constant expression, then the second operand + * resolves to a void pointer (but not a null pointer constant: the value + * is not an integer constant 0). + * - The conditional operator's third operand, "(int *)8", is an object + * pointer (to type "int"). + * - The behavior (including the return type) of the conditional operator + * ("operand1 ? operand2 : operand3") depends on the kind of expressions + * given for the second and third operands. This is the central mechanism + * of the macro: + * - When one operand is a null pointer constant (i.e. when x is an integer + * constant expression) and the other is an object pointer (i.e. our + * third operand), the conditional operator returns the type of the + * object pointer operand (i.e. "int *). Here, within the sizeof(), we + * would then get: + * sizeof(*((int *)(...)) == sizeof(int) == 4 + * - When one operand is a void pointer (i.e. when x is not an integer + * constant expression) and the other is an object pointer (i.e. our + * third operand), the conditional operator returns a "void *" type. + * Here, within the sizeof(), we would then get: + * sizeof(*((void *)(...)) == sizeof(void) == 1 + * - The equality comparison to "sizeof(int)" therefore depends on (x): + * sizeof(int) == sizeof(int) (x) was a constant expression + * sizeof(int) != sizeof(void) (x) was not a constant expression */ #define __is_constexpr(x) \ (sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))