All of lore.kernel.org
 help / color / mirror / Atom feed
From: Siddhesh Poyarekar <siddhesh@gotplt.org>
To: Kees Cook <keescook@chromium.org>, linux-hardening@vger.kernel.org
Cc: Nathan Chancellor <nathan@kernel.org>,
	Nick Desaulniers <ndesaulniers@google.com>,
	Arnd Bergmann <arnd@arndb.de>, Juergen Gross <jgross@suse.com>,
	Boris Ostrovsky <boris.ostrovsky@oracle.com>,
	Tom Rix <trix@redhat.com>, Miguel Ojeda <ojeda@kernel.org>,
	linux-kernel@vger.kernel.org, llvm@lists.linux.dev
Subject: Re: [PATCH 2/4] fortify: Explicitly check bounds are compile-time constants
Date: Wed, 21 Sep 2022 07:48:44 -0400	[thread overview]
Message-ID: <b8f5f716-3ee6-87fd-d0e2-b1c35c98e0b0@gotplt.org> (raw)
In-Reply-To: <20220920192202.190793-3-keescook@chromium.org>



On 2022-09-20 15:22, Kees Cook wrote:
> In preparation for replacing __builtin_object_size() with
> __builtin_dynamic_object_size(), all the compile-time size checks need
> to check that the bounds variables are, in fact, known at compile-time.
> Enforce what was guaranteed with __bos(). In other words, since all uses
> of __bos() were constant expressions, it was not required to test for
> this. When these change to __bdos(), they _may_ be constant expressions,
> and the checks are only valid when the prior condition holds. This
> results in no binary differences.
> 
> Signed-off-by: Kees Cook <keescook@chromium.org>
> ---
>   include/linux/fortify-string.h | 50 +++++++++++++++++++++-------------
>   1 file changed, 31 insertions(+), 19 deletions(-)
> 
> diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h
> index ff879efe94ed..71c0a432c638 100644
> --- a/include/linux/fortify-string.h
> +++ b/include/linux/fortify-string.h
> @@ -80,6 +80,12 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size)
>   #define POS	__pass_object_size(1)
>   #define POS0	__pass_object_size(0)
>   
> +#define __compiletime_lessthan(bounds, length)	(	\
> +	__builtin_constant_p(length) &&			\
> +	__builtin_constant_p(bounds) &&			\
> +	bounds < length					\
> +)

So with the gcc ranger, the compiler has lately been quite successful at 
computing a constant `bounds < length` even though bounds and length are 
not constant.  So perhaps this:

#define __compiletime_lessthan (bounds, length) (	\
	__builtin_constant (bounds < length) &&		\
	bounds < length					\
)

might succeed in a few more cases.

Thanks,
Sid

> +
>   /**
>    * strncpy - Copy a string to memory with non-guaranteed NUL padding
>    *
> @@ -117,7 +123,7 @@ char *strncpy(char * const POS p, const char *q, __kernel_size_t size)
>   {
>   	size_t p_size = __builtin_object_size(p, 1);
>   
> -	if (__builtin_constant_p(size) && p_size < size)
> +	if (__compiletime_lessthan(p_size, size))
>   		__write_overflow();
>   	if (p_size < size)
>   		fortify_panic(__func__);
> @@ -224,7 +230,7 @@ __FORTIFY_INLINE ssize_t strscpy(char * const POS p, const char * const POS q, s
>   	 * If size can be known at compile time and is greater than
>   	 * p_size, generate a compile time write overflow error.
>   	 */
> -	if (__builtin_constant_p(size) && size > p_size)
> +	if (__compiletime_lessthan(p_size, size))
>   		__write_overflow();
>   
>   	/*
> @@ -281,15 +287,16 @@ __FORTIFY_INLINE void fortify_memset_chk(__kernel_size_t size,
>   		/*
>   		 * Length argument is a constant expression, so we
>   		 * can perform compile-time bounds checking where
> -		 * buffer sizes are known.
> +		 * buffer sizes are also known at compile time.
>   		 */
>   
>   		/* Error when size is larger than enclosing struct. */
> -		if (p_size > p_size_field && p_size < size)
> +		if (__compiletime_lessthan(p_size_field, p_size) &&
> +		    __compiletime_lessthan(p_size, size))
>   			__write_overflow();
>   
>   		/* Warn when write size is larger than dest field. */
> -		if (p_size_field < size)
> +		if (__compiletime_lessthan(p_size_field, size))
>   			__write_overflow_field(p_size_field, size);
>   	}
>   	/*
> @@ -365,25 +372,28 @@ __FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size,
>   		/*
>   		 * Length argument is a constant expression, so we
>   		 * can perform compile-time bounds checking where
> -		 * buffer sizes are known.
> +		 * buffer sizes are also known at compile time.
>   		 */
>   
>   		/* Error when size is larger than enclosing struct. */
> -		if (p_size > p_size_field && p_size < size)
> +		if (__compiletime_lessthan(p_size_field, p_size) &&
> +		    __compiletime_lessthan(p_size, size))
>   			__write_overflow();
> -		if (q_size > q_size_field && q_size < size)
> +		if (__compiletime_lessthan(q_size_field, q_size) &&
> +		    __compiletime_lessthan(q_size, size))
>   			__read_overflow2();
>   
>   		/* Warn when write size argument larger than dest field. */
> -		if (p_size_field < size)
> +		if (__compiletime_lessthan(p_size_field, size))
>   			__write_overflow_field(p_size_field, size);
>   		/*
>   		 * Warn for source field over-read when building with W=1
>   		 * or when an over-write happened, so both can be fixed at
>   		 * the same time.
>   		 */
> -		if ((IS_ENABLED(KBUILD_EXTRA_WARN1) || p_size_field < size) &&
> -		    q_size_field < size)
> +		if ((IS_ENABLED(KBUILD_EXTRA_WARN1) ||
> +		     __compiletime_lessthan(p_size_field, size)) &&
> +		    __compiletime_lessthan(q_size_field, size))
>   			__read_overflow2_field(q_size_field, size);
>   	}
>   	/*
> @@ -494,7 +504,7 @@ __FORTIFY_INLINE void *memscan(void * const POS0 p, int c, __kernel_size_t size)
>   {
>   	size_t p_size = __builtin_object_size(p, 0);
>   
> -	if (__builtin_constant_p(size) && p_size < size)
> +	if (__compiletime_lessthan(p_size, size))
>   		__read_overflow();
>   	if (p_size < size)
>   		fortify_panic(__func__);
> @@ -508,9 +518,9 @@ int memcmp(const void * const POS0 p, const void * const POS0 q, __kernel_size_t
>   	size_t q_size = __builtin_object_size(q, 0);
>   
>   	if (__builtin_constant_p(size)) {
> -		if (p_size < size)
> +		if (__compiletime_lessthan(p_size, size))
>   			__read_overflow();
> -		if (q_size < size)
> +		if (__compiletime_lessthan(q_size, size))
>   			__read_overflow2();
>   	}
>   	if (p_size < size || q_size < size)
> @@ -523,7 +533,7 @@ void *memchr(const void * const POS0 p, int c, __kernel_size_t size)
>   {
>   	size_t p_size = __builtin_object_size(p, 0);
>   
> -	if (__builtin_constant_p(size) && p_size < size)
> +	if (__compiletime_lessthan(p_size, size))
>   		__read_overflow();
>   	if (p_size < size)
>   		fortify_panic(__func__);
> @@ -535,7 +545,7 @@ __FORTIFY_INLINE void *memchr_inv(const void * const POS0 p, int c, size_t size)
>   {
>   	size_t p_size = __builtin_object_size(p, 0);
>   
> -	if (__builtin_constant_p(size) && p_size < size)
> +	if (__compiletime_lessthan(p_size, size))
>   		__read_overflow();
>   	if (p_size < size)
>   		fortify_panic(__func__);
> @@ -547,7 +557,7 @@ __FORTIFY_INLINE void *kmemdup(const void * const POS0 p, size_t size, gfp_t gfp
>   {
>   	size_t p_size = __builtin_object_size(p, 0);
>   
> -	if (__builtin_constant_p(size) && p_size < size)
> +	if (__compiletime_lessthan(p_size, size))
>   		__read_overflow();
>   	if (p_size < size)
>   		fortify_panic(__func__);
> @@ -563,11 +573,13 @@ char *strcpy(char * const POS p, const char * const POS q)
>   	size_t size;
>   
>   	/* If neither buffer size is known, immediately give up. */
> -	if (p_size == SIZE_MAX && q_size == SIZE_MAX)
> +	if (__builtin_constant_p(p_size) &&
> +	    __builtin_constant_p(q_size) &&
> +	    p_size == SIZE_MAX && q_size == SIZE_MAX)
>   		return __underlying_strcpy(p, q);
>   	size = strlen(q) + 1;
>   	/* Compile-time check for const size overflow. */
> -	if (__builtin_constant_p(size) && p_size < size)
> +	if (__compiletime_lessthan(p_size, size))
>   		__write_overflow();
>   	/* Run-time check for dynamic size overflow. */
>   	if (p_size < size)

  reply	other threads:[~2022-09-21 11:57 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-20 19:21 [PATCH 0/4] fortify: Use __builtin_dynamic_object_size() when available Kees Cook
2022-09-20 19:21 ` [PATCH 1/4] x86/entry: Work around Clang __bdos() bug Kees Cook
2022-09-21  0:07   ` Boris Ostrovsky
2022-09-20 19:22 ` [PATCH 2/4] fortify: Explicitly check bounds are compile-time constants Kees Cook
2022-09-21 11:48   ` Siddhesh Poyarekar [this message]
2022-09-22  3:46     ` Kees Cook
2022-09-20 19:22 ` [PATCH 3/4] fortify: Convert to struct vs member helpers Kees Cook
2022-09-20 19:22 ` [PATCH 4/4] fortify: Use __builtin_dynamic_object_size() when available Kees Cook
2022-09-21 11:24   ` Miguel Ojeda
2022-09-21 11:43   ` Siddhesh Poyarekar
2022-09-22  3:33     ` Kees Cook
2022-09-22 14:45       ` Siddhesh Poyarekar
2022-11-22 10:20   ` Siddhesh Poyarekar
2022-11-23  5:15     ` Kees Cook
2022-11-23 15:29       ` Siddhesh Poyarekar
2023-01-13 15:59   ` linux-next - bxnt buffer overflow in strnlen Niklas Cassel
2023-01-13 16:08     ` linux-next - bnxt " Niklas Cassel
2023-01-13 22:44       ` Kees Cook
2023-01-16 10:56         ` Niklas Cassel
2022-09-22 20:26 ` [PATCH 0/4] fortify: Use __builtin_dynamic_object_size() when available Siddhesh Poyarekar
2022-09-23  0:20   ` Kees Cook
2022-09-23  0:55     ` Siddhesh Poyarekar

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=b8f5f716-3ee6-87fd-d0e2-b1c35c98e0b0@gotplt.org \
    --to=siddhesh@gotplt.org \
    --cc=arnd@arndb.de \
    --cc=boris.ostrovsky@oracle.com \
    --cc=jgross@suse.com \
    --cc=keescook@chromium.org \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=llvm@lists.linux.dev \
    --cc=nathan@kernel.org \
    --cc=ndesaulniers@google.com \
    --cc=ojeda@kernel.org \
    --cc=trix@redhat.com \
    /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.