From: Kees Cook <kees@kernel.org>
To: david.laight.linux@gmail.com
Cc: linux-hardening@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH next 3/3] fortify: Simplify strlen() logic
Date: Mon, 30 Mar 2026 23:18:37 -0700 [thread overview]
Message-ID: <202603302312.29AE002@keescook> (raw)
In-Reply-To: <20260330132003.3379-4-david.laight.linux@gmail.com>
On Mon, Mar 30, 2026 at 02:20:03PM +0100, david.laight.linux@gmail.com wrote:
> From: David Laight <david.laight.linux@gmail.com>
>
> The __builtin_choose_expr() doesn't gain you anything, replace with
> a simple ?: operator.
> Then __is_constexpr() can then be replaced with __builtin_constant_p().
> This still works for static initialisers - the expression can contain
> a function call - provided it isn't actually called.
>
> Calling the strnlen() wrapper just add a lot more logic to read through.
> Replace with a call to __real_strnlen().
>
> However the compiler can decide that __builtin_constant_p(__builtin_strlen(p))
> is false, but split as ret = __builtin_strlen(p); __builtin_constant_p(ret)
> and it suddenly becomes true.
> So an additional check is needed before calling __real_strnlen().
Ah, there it is, exactly the issue I'm remembering, see
commit 4f3d1be4c2f8 ("compiler.h: add const_true()")
Instead of this patch, I should likely replace the open-coded versions
of const_true() here.
Regardless, we should not change this or the compiletime_strlen() macro
as you've suggested, IMO. They both work as they already are, so I see
no reason re-open this can of worms without a good reason.
What was the specific code that caused an issue for you with
__fortify_strlen ?
-Kees
>
> Signed-off-by: David Laight <david.laight.linux@gmail.com>
> ---
> include/linux/fortify-string.h | 20 +++++++++++++-------
> 1 file changed, 13 insertions(+), 7 deletions(-)
>
> diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h
> index 758afd7c5f8a..6cd670492270 100644
> --- a/include/linux/fortify-string.h
> +++ b/include/linux/fortify-string.h
> @@ -230,9 +230,8 @@ __FORTIFY_INLINE __kernel_size_t strnlen(const char * const POS p, __kernel_size
> }
>
> /*
> - * Defined after fortified strnlen to reuse it. However, it must still be
> - * possible for strlen() to be used on compile-time strings for use in
> - * static initializers (i.e. as a constant expression).
> + * strlen() of a compile-time string needs to be a constant expression
> + * so it can be used, for example, as a static initializer.
> */
> /**
> * strlen - Return count of characters in a NUL-terminated string
> @@ -247,9 +246,9 @@ __FORTIFY_INLINE __kernel_size_t strnlen(const char * const POS p, __kernel_size
> * Returns number of characters in @p (NOT including the final NUL).
> *
> */
> -#define strlen(p) \
> - __builtin_choose_expr(__is_constexpr(__builtin_strlen(p)), \
> - __builtin_strlen(p), __fortify_strlen(p))
> +#define strlen(p) \
> + (__builtin_constant_p(__builtin_strlen(p)) ? \
> + __builtin_strlen(p) : __fortify_strlen(p))
> __FORTIFY_INLINE __diagnose_as(__builtin_strlen, 1)
> __kernel_size_t __fortify_strlen(const char * const POS p)
> {
> @@ -259,7 +258,14 @@ __kernel_size_t __fortify_strlen(const char * const POS p)
> /* Give up if we don't know how large p is. */
> if (p_size == SIZE_MAX)
> return __underlying_strlen(p);
> - ret = strnlen(p, p_size);
> + /*
> + * 'ret' can be constant here even though the __builtin_constant_p(__builtin_strlen(p))
> + * in the #define wrapper is false.
> + */
> + ret = __builtin_strlen(p);
> + if (__builtin_constant_p(ret))
> + return ret;
> + ret = __real_strnlen(p, p_size);
> if (p_size <= ret)
> fortify_panic(FORTIFY_FUNC_strlen, FORTIFY_READ, p_size, ret + 1, ret);
> return ret;
> --
> 2.39.5
>
--
Kees Cook
prev parent reply other threads:[~2026-03-31 6:18 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-30 13:20 [PATCH next 0/3] fortify: Minor changes to strlen() and strnlen() david.laight.linux
2026-03-30 13:20 ` [PATCH next 1/3] fortify: replace __compiletime_lessthan() with statically_true() david.laight.linux
2026-03-30 23:50 ` Kees Cook
2026-03-30 13:20 ` [PATCH next 2/3] fortify: Optimise strnlen() david.laight.linux
2026-03-30 23:54 ` Kees Cook
2026-03-31 22:09 ` David Laight
2026-03-31 23:51 ` Kees Cook
2026-04-01 13:48 ` David Laight
2026-04-03 8:50 ` David Laight
2026-04-16 14:22 ` David Laight
2026-03-31 6:36 ` Kees Cook
2026-03-31 10:14 ` David Laight
2026-03-31 14:55 ` David Laight
2026-03-31 15:56 ` Kees Cook
2026-04-01 0:15 ` kernel test robot
2026-04-03 8:23 ` David Laight
2026-03-30 13:20 ` [PATCH next 3/3] fortify: Simplify strlen() logic david.laight.linux
2026-03-31 6:07 ` Kees Cook
2026-03-31 8:58 ` David Laight
2026-03-31 6:18 ` Kees Cook [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=202603302312.29AE002@keescook \
--to=kees@kernel.org \
--cc=david.laight.linux@gmail.com \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.