All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kees Cook <keescook@chromium.org>
To: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Cc: thomas.hellstrom@linux.intel.com, jani.nikula@intel.com,
	Nick Desaulniers <ndesaulniers@google.com>,
	intel-gfx@lists.freedesktop.org,
	Rasmus Villemoes <linux@rasmusvillemoes.dk>,
	linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
	chris@chris-wilson.co.uk, airlied@linux.ie,
	andrzej.hajda@intel.com, matthew.auld@intel.com, daniel@ffwll.ch,
	intel-gfx-trybot@lists.freedesktop.org, mchehab@kernel.org,
	nirmoy.das@intel.com
Subject: Re: [Intel-gfx] [PATCH v9 1/8] overflow: Move and add few utility macros into overflow
Date: Thu, 25 Aug 2022 09:47:16 -0700	[thread overview]
Message-ID: <202208250848.1C77B9C38@keescook> (raw)
In-Reply-To: <20220824084514.2261614-2-gwan-gyeong.mun@intel.com>

On Wed, Aug 24, 2022 at 05:45:07PM +0900, Gwan-gyeong Mun wrote:
> It moves overflows_type utility macro into overflow header from i915_utils
> header. The overflows_type can be used to catch the truncaion (overflow)
> between different data types. And it adds check_assign() macro which
> performs an assigning source value into destination ptr along with an
> overflow check. overflow_type macro has been improved to handle the signbit
> by gcc's built-in overflow check function. And it adds overflows_ptr()
> helper macro for checking the overflows between a value and a pointer
> type/value.
> 
> v3: Add is_type_unsigned() macro (Mauro)
>     Modify overflows_type() macro to consider signed data types (Mauro)
>     Fix the problem that safe_conversion() macro always returns true
> v4: Fix kernel-doc markups
> v6: Move macro addition location so that it can be used by other than drm
>     subsystem (Jani, Mauro, Andi)
>     Change is_type_unsigned to is_unsigned_type to have the same name form
>     as is_signed_type macro
> v8: Add check_assign() and remove safe_conversion() (Kees)
>     Fix overflows_type() to use gcc's built-in overflow function (Andrzej)
>     Add overflows_ptr() to allow overflow checking when assigning a value
>     into a pointer variable (G.G.)
> v9: Fix overflows_type() to use __builtin_add_overflow() instead of
>     __builtin_add_overflow_p() (Andrzej)
>     Fix overflows_ptr() to use overflows_type() with the unsigned long type
>     (Andrzej)
> 
> Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> Cc: Matthew Auld <matthew.auld@intel.com>
> Cc: Nirmoy Das <nirmoy.das@intel.com>
> Cc: Jani Nikula <jani.nikula@intel.com>
> Cc: Andi Shyti <andi.shyti@linux.intel.com>
> Cc: Andrzej Hajda <andrzej.hajda@intel.com>
> Cc: Mauro Carvalho Chehab <mauro.chehab@linux.intel.com>
> Cc: Kees Cook <keescook@chromium.org>
> Reviewed-by: Mauro Carvalho Chehab <mchehab@kernel.org> (v5)
> ---
>  drivers/gpu/drm/i915/i915_user_extensions.c |  3 +-
>  drivers/gpu/drm/i915/i915_utils.h           |  5 +-
>  include/linux/overflow.h                    | 62 +++++++++++++++++++++
>  3 files changed, 64 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_user_extensions.c b/drivers/gpu/drm/i915/i915_user_extensions.c
> index c822d0aafd2d..6f6b5b910968 100644
> --- a/drivers/gpu/drm/i915/i915_user_extensions.c
> +++ b/drivers/gpu/drm/i915/i915_user_extensions.c
> @@ -50,8 +50,7 @@ int i915_user_extensions(struct i915_user_extension __user *ext,
>  		if (err)
>  			return err;
>  
> -		if (get_user(next, &ext->next_extension) ||
> -		    overflows_type(next, ext))
> +		if (get_user(next, &ext->next_extension) || overflows_ptr(next))
>  			return -EFAULT;
>  
>  		ext = u64_to_user_ptr(next);

I continue to dislike the layers of macros and specialization here.
This is just a fancy version of check_assign():

	if (get_user(next, &ext->next_extension) || check_assign(next, &ext))
		return -EFAULT;

However, the __builtin_*_overflow() family only wants to work on
integral types, so this needs to be slightly expanded:

	uintptr_t kptr;
	...
	if (get_user(next, &ext->next_extension) || check_assign(next, &kptr))
		return -EFAULT;

	ext = (void * __user)kptr;

But, it does seem like the actual problem here is that u64_to_user_ptr()
is not performing the checking? It's used heavily in the drm code.

Is a check_assign_user_ptr() needed?

> diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h
> index c10d68cdc3ca..eb0ded23fa9c 100644
> --- a/drivers/gpu/drm/i915/i915_utils.h
> +++ b/drivers/gpu/drm/i915/i915_utils.h
> @@ -32,6 +32,7 @@
>  #include <linux/types.h>
>  #include <linux/workqueue.h>
>  #include <linux/sched/clock.h>
> +#include <linux/overflow.h>
>  
>  #ifdef CONFIG_X86
>  #include <asm/hypervisor.h>
> @@ -111,10 +112,6 @@ bool i915_error_injected(void);
>  #define range_overflows_end_t(type, start, size, max) \
>  	range_overflows_end((type)(start), (type)(size), (type)(max))
>  
> -/* Note we don't consider signbits :| */
> -#define overflows_type(x, T) \
> -	(sizeof(x) > sizeof(T) && (x) >> BITS_PER_TYPE(T))
> -
>  #define ptr_mask_bits(ptr, n) ({					\
>  	unsigned long __v = (unsigned long)(ptr);			\
>  	(typeof(ptr))(__v & -BIT(n));					\
> diff --git a/include/linux/overflow.h b/include/linux/overflow.h
> index f1221d11f8e5..6af9df1d67a1 100644
> --- a/include/linux/overflow.h
> +++ b/include/linux/overflow.h
> @@ -52,6 +52,68 @@ static inline bool __must_check __must_check_overflow(bool overflow)
>  	return unlikely(overflow);
>  }
>  
> +/**
> + * overflows_type - helper for checking the overflows between data types or
> + *                  values
> + *
> + * @x: Source value or data type for overflow check
> + * @T: Destination value or data type for overflow check
> + *
> + * It compares the values or data type between the first and second argument to
> + * check whether overflow can occur when assigning the first argument to the
> + * variable of the second argument. Source and Destination can be singned or
> + * unsigned data types. Source and Destination can be different data types.
> + *
> + * Returns:
> + * True if overflow can occur, false otherwise.
> + */
> +#define overflows_type(x, T) __must_check_overflow(({	\
> +	typeof(T) v = 0;				\
> +	__builtin_add_overflow((x), v, &v);		\
> +}))

I'd like to avoid "externalizing" these kinds of checks when the better
path is to catch the issue at operation type (add, sub, mul, assign).
Looking at existing users, I see stuff like:

                if (overflows_type(item.query_id - 1, unsigned long))
                        return -EINVAL;

                func_idx = item.query_id - 1;

This requires too much open-coded checking, IMO. It's better as:

		if (check_assign(item.query_id - 1, &func_idx))
			return -EINVAL;

or other similar:

        if (overflows_type(user->slice_mask, context->slice_mask) ||
	...
        context->slice_mask = user->slice_mask;

and some that don't make sense to me. Why check argument types? Is this
trying to avoid implicit type conversions?

So, if it's _really_ needed, I can live with adding overflows_type().

> +
> +/**
> + * overflows_ptr - helper for checking the occurrence of overflows when a value
> + *                 assigns to  the pointer data type
> + *
> + * @x: Source value for overflow check
> + *
> + * gcc's built-in overflow check functions don't support checking between the
> + * pointer type and non-pointer type. And ILP32 and LP64 have the same bit size
> + * between long and pointer. Therefore it internally compares the source value
> + * and unsigned long data type for checking overflow.
> + *
> + * Returns:
> + * True if overflow can occur, false otherwise.
> + */
> +#define overflows_ptr(x) __must_check_overflow(overflows_type(x, unsigned long))

I'd rather not have this -- it's just a specialized use of
overflows_type(), and only used in 1 place.

> +
> +/**
> + * check_assign - perform an assigning source value into destination ptr along
> + *                with an overflow check.
> + *
> + * @value: Source value
> + * @ptr: Destination pointer address, If the pointer type is not used,
> + *       a warning message is output during build.
> + *
> + * It checks internally the ptr is a pointer type. And it uses gcc's built-in
> + * overflow check function.
> + * It does not use the check_*() wrapper functions, but directly uses gcc's
> + * built-in overflow check function so that it can be used even when
> + * the type of value and the type pointed to by ptr are different without build
> + * warning messages.

This is a good point: the check_{add,sub,mul}_overflow() helpers
currently require all the params be the same type, which rather limits
their usage. Perhaps this can be weakened now that we're not using[1]
the fallback logic any more? (Separate patch.)

> + *
> + * Returns:
> + * If the value would overflow the destination, it returns true. If not return
> + * false. When overflow does not occur, the assigning into ptr from value
> + * succeeds. It follows the return policy as other check_*_overflow() functions
> + * return non-zero as a failure.
> + */
> +#define check_assign(value, ptr) __must_check_overflow(({	\
> +	typecheck_pointer(ptr); 		\
> +	__builtin_add_overflow(0, value, ptr);	\
> +}))

But yes, this looks correct. I really like it. :)

> +
>  /*
>   * For simplicity and code hygiene, the fallback code below insists on
>   * a, b and *d having the same type (similar to the min() and max()
> -- 
> 2.37.1
> 

-Kees

[1] 4eb6bd55cfb2 ("compiler.h: drop fallback overflow checkers")

-- 
Kees Cook

WARNING: multiple messages have this Message-ID (diff)
From: Kees Cook <keescook@chromium.org>
To: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Cc: thomas.hellstrom@linux.intel.com, mauro.chehab@linux.intel.com,
	andi.shyti@linux.intel.com, jani.nikula@intel.com,
	Nick Desaulniers <ndesaulniers@google.com>,
	intel-gfx@lists.freedesktop.org,
	Rasmus Villemoes <linux@rasmusvillemoes.dk>,
	linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
	chris@chris-wilson.co.uk, airlied@linux.ie,
	andrzej.hajda@intel.com, matthew.auld@intel.com,
	intel-gfx-trybot@lists.freedesktop.org, mchehab@kernel.org,
	nirmoy.das@intel.com
Subject: Re: [PATCH v9 1/8] overflow: Move and add few utility macros into overflow
Date: Thu, 25 Aug 2022 09:47:16 -0700	[thread overview]
Message-ID: <202208250848.1C77B9C38@keescook> (raw)
In-Reply-To: <20220824084514.2261614-2-gwan-gyeong.mun@intel.com>

On Wed, Aug 24, 2022 at 05:45:07PM +0900, Gwan-gyeong Mun wrote:
> It moves overflows_type utility macro into overflow header from i915_utils
> header. The overflows_type can be used to catch the truncaion (overflow)
> between different data types. And it adds check_assign() macro which
> performs an assigning source value into destination ptr along with an
> overflow check. overflow_type macro has been improved to handle the signbit
> by gcc's built-in overflow check function. And it adds overflows_ptr()
> helper macro for checking the overflows between a value and a pointer
> type/value.
> 
> v3: Add is_type_unsigned() macro (Mauro)
>     Modify overflows_type() macro to consider signed data types (Mauro)
>     Fix the problem that safe_conversion() macro always returns true
> v4: Fix kernel-doc markups
> v6: Move macro addition location so that it can be used by other than drm
>     subsystem (Jani, Mauro, Andi)
>     Change is_type_unsigned to is_unsigned_type to have the same name form
>     as is_signed_type macro
> v8: Add check_assign() and remove safe_conversion() (Kees)
>     Fix overflows_type() to use gcc's built-in overflow function (Andrzej)
>     Add overflows_ptr() to allow overflow checking when assigning a value
>     into a pointer variable (G.G.)
> v9: Fix overflows_type() to use __builtin_add_overflow() instead of
>     __builtin_add_overflow_p() (Andrzej)
>     Fix overflows_ptr() to use overflows_type() with the unsigned long type
>     (Andrzej)
> 
> Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> Cc: Matthew Auld <matthew.auld@intel.com>
> Cc: Nirmoy Das <nirmoy.das@intel.com>
> Cc: Jani Nikula <jani.nikula@intel.com>
> Cc: Andi Shyti <andi.shyti@linux.intel.com>
> Cc: Andrzej Hajda <andrzej.hajda@intel.com>
> Cc: Mauro Carvalho Chehab <mauro.chehab@linux.intel.com>
> Cc: Kees Cook <keescook@chromium.org>
> Reviewed-by: Mauro Carvalho Chehab <mchehab@kernel.org> (v5)
> ---
>  drivers/gpu/drm/i915/i915_user_extensions.c |  3 +-
>  drivers/gpu/drm/i915/i915_utils.h           |  5 +-
>  include/linux/overflow.h                    | 62 +++++++++++++++++++++
>  3 files changed, 64 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_user_extensions.c b/drivers/gpu/drm/i915/i915_user_extensions.c
> index c822d0aafd2d..6f6b5b910968 100644
> --- a/drivers/gpu/drm/i915/i915_user_extensions.c
> +++ b/drivers/gpu/drm/i915/i915_user_extensions.c
> @@ -50,8 +50,7 @@ int i915_user_extensions(struct i915_user_extension __user *ext,
>  		if (err)
>  			return err;
>  
> -		if (get_user(next, &ext->next_extension) ||
> -		    overflows_type(next, ext))
> +		if (get_user(next, &ext->next_extension) || overflows_ptr(next))
>  			return -EFAULT;
>  
>  		ext = u64_to_user_ptr(next);

I continue to dislike the layers of macros and specialization here.
This is just a fancy version of check_assign():

	if (get_user(next, &ext->next_extension) || check_assign(next, &ext))
		return -EFAULT;

However, the __builtin_*_overflow() family only wants to work on
integral types, so this needs to be slightly expanded:

	uintptr_t kptr;
	...
	if (get_user(next, &ext->next_extension) || check_assign(next, &kptr))
		return -EFAULT;

	ext = (void * __user)kptr;

But, it does seem like the actual problem here is that u64_to_user_ptr()
is not performing the checking? It's used heavily in the drm code.

Is a check_assign_user_ptr() needed?

> diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h
> index c10d68cdc3ca..eb0ded23fa9c 100644
> --- a/drivers/gpu/drm/i915/i915_utils.h
> +++ b/drivers/gpu/drm/i915/i915_utils.h
> @@ -32,6 +32,7 @@
>  #include <linux/types.h>
>  #include <linux/workqueue.h>
>  #include <linux/sched/clock.h>
> +#include <linux/overflow.h>
>  
>  #ifdef CONFIG_X86
>  #include <asm/hypervisor.h>
> @@ -111,10 +112,6 @@ bool i915_error_injected(void);
>  #define range_overflows_end_t(type, start, size, max) \
>  	range_overflows_end((type)(start), (type)(size), (type)(max))
>  
> -/* Note we don't consider signbits :| */
> -#define overflows_type(x, T) \
> -	(sizeof(x) > sizeof(T) && (x) >> BITS_PER_TYPE(T))
> -
>  #define ptr_mask_bits(ptr, n) ({					\
>  	unsigned long __v = (unsigned long)(ptr);			\
>  	(typeof(ptr))(__v & -BIT(n));					\
> diff --git a/include/linux/overflow.h b/include/linux/overflow.h
> index f1221d11f8e5..6af9df1d67a1 100644
> --- a/include/linux/overflow.h
> +++ b/include/linux/overflow.h
> @@ -52,6 +52,68 @@ static inline bool __must_check __must_check_overflow(bool overflow)
>  	return unlikely(overflow);
>  }
>  
> +/**
> + * overflows_type - helper for checking the overflows between data types or
> + *                  values
> + *
> + * @x: Source value or data type for overflow check
> + * @T: Destination value or data type for overflow check
> + *
> + * It compares the values or data type between the first and second argument to
> + * check whether overflow can occur when assigning the first argument to the
> + * variable of the second argument. Source and Destination can be singned or
> + * unsigned data types. Source and Destination can be different data types.
> + *
> + * Returns:
> + * True if overflow can occur, false otherwise.
> + */
> +#define overflows_type(x, T) __must_check_overflow(({	\
> +	typeof(T) v = 0;				\
> +	__builtin_add_overflow((x), v, &v);		\
> +}))

I'd like to avoid "externalizing" these kinds of checks when the better
path is to catch the issue at operation type (add, sub, mul, assign).
Looking at existing users, I see stuff like:

                if (overflows_type(item.query_id - 1, unsigned long))
                        return -EINVAL;

                func_idx = item.query_id - 1;

This requires too much open-coded checking, IMO. It's better as:

		if (check_assign(item.query_id - 1, &func_idx))
			return -EINVAL;

or other similar:

        if (overflows_type(user->slice_mask, context->slice_mask) ||
	...
        context->slice_mask = user->slice_mask;

and some that don't make sense to me. Why check argument types? Is this
trying to avoid implicit type conversions?

So, if it's _really_ needed, I can live with adding overflows_type().

> +
> +/**
> + * overflows_ptr - helper for checking the occurrence of overflows when a value
> + *                 assigns to  the pointer data type
> + *
> + * @x: Source value for overflow check
> + *
> + * gcc's built-in overflow check functions don't support checking between the
> + * pointer type and non-pointer type. And ILP32 and LP64 have the same bit size
> + * between long and pointer. Therefore it internally compares the source value
> + * and unsigned long data type for checking overflow.
> + *
> + * Returns:
> + * True if overflow can occur, false otherwise.
> + */
> +#define overflows_ptr(x) __must_check_overflow(overflows_type(x, unsigned long))

I'd rather not have this -- it's just a specialized use of
overflows_type(), and only used in 1 place.

> +
> +/**
> + * check_assign - perform an assigning source value into destination ptr along
> + *                with an overflow check.
> + *
> + * @value: Source value
> + * @ptr: Destination pointer address, If the pointer type is not used,
> + *       a warning message is output during build.
> + *
> + * It checks internally the ptr is a pointer type. And it uses gcc's built-in
> + * overflow check function.
> + * It does not use the check_*() wrapper functions, but directly uses gcc's
> + * built-in overflow check function so that it can be used even when
> + * the type of value and the type pointed to by ptr are different without build
> + * warning messages.

This is a good point: the check_{add,sub,mul}_overflow() helpers
currently require all the params be the same type, which rather limits
their usage. Perhaps this can be weakened now that we're not using[1]
the fallback logic any more? (Separate patch.)

> + *
> + * Returns:
> + * If the value would overflow the destination, it returns true. If not return
> + * false. When overflow does not occur, the assigning into ptr from value
> + * succeeds. It follows the return policy as other check_*_overflow() functions
> + * return non-zero as a failure.
> + */
> +#define check_assign(value, ptr) __must_check_overflow(({	\
> +	typecheck_pointer(ptr); 		\
> +	__builtin_add_overflow(0, value, ptr);	\
> +}))

But yes, this looks correct. I really like it. :)

> +
>  /*
>   * For simplicity and code hygiene, the fallback code below insists on
>   * a, b and *d having the same type (similar to the min() and max()
> -- 
> 2.37.1
> 

-Kees

[1] 4eb6bd55cfb2 ("compiler.h: drop fallback overflow checkers")

-- 
Kees Cook

WARNING: multiple messages have this Message-ID (diff)
From: Kees Cook <keescook@chromium.org>
To: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Cc: intel-gfx@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	dri-devel@lists.freedesktop.org, mchehab@kernel.org,
	chris@chris-wilson.co.uk, matthew.auld@intel.com,
	thomas.hellstrom@linux.intel.com, jani.nikula@intel.com,
	nirmoy.das@intel.com, airlied@linux.ie, daniel@ffwll.ch,
	andi.shyti@linux.intel.com, andrzej.hajda@intel.com,
	mauro.chehab@linux.intel.com,
	intel-gfx-trybot@lists.freedesktop.org,
	Rasmus Villemoes <linux@rasmusvillemoes.dk>,
	Nick Desaulniers <ndesaulniers@google.com>
Subject: Re: [PATCH v9 1/8] overflow: Move and add few utility macros into overflow
Date: Thu, 25 Aug 2022 09:47:16 -0700	[thread overview]
Message-ID: <202208250848.1C77B9C38@keescook> (raw)
In-Reply-To: <20220824084514.2261614-2-gwan-gyeong.mun@intel.com>

On Wed, Aug 24, 2022 at 05:45:07PM +0900, Gwan-gyeong Mun wrote:
> It moves overflows_type utility macro into overflow header from i915_utils
> header. The overflows_type can be used to catch the truncaion (overflow)
> between different data types. And it adds check_assign() macro which
> performs an assigning source value into destination ptr along with an
> overflow check. overflow_type macro has been improved to handle the signbit
> by gcc's built-in overflow check function. And it adds overflows_ptr()
> helper macro for checking the overflows between a value and a pointer
> type/value.
> 
> v3: Add is_type_unsigned() macro (Mauro)
>     Modify overflows_type() macro to consider signed data types (Mauro)
>     Fix the problem that safe_conversion() macro always returns true
> v4: Fix kernel-doc markups
> v6: Move macro addition location so that it can be used by other than drm
>     subsystem (Jani, Mauro, Andi)
>     Change is_type_unsigned to is_unsigned_type to have the same name form
>     as is_signed_type macro
> v8: Add check_assign() and remove safe_conversion() (Kees)
>     Fix overflows_type() to use gcc's built-in overflow function (Andrzej)
>     Add overflows_ptr() to allow overflow checking when assigning a value
>     into a pointer variable (G.G.)
> v9: Fix overflows_type() to use __builtin_add_overflow() instead of
>     __builtin_add_overflow_p() (Andrzej)
>     Fix overflows_ptr() to use overflows_type() with the unsigned long type
>     (Andrzej)
> 
> Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> Cc: Matthew Auld <matthew.auld@intel.com>
> Cc: Nirmoy Das <nirmoy.das@intel.com>
> Cc: Jani Nikula <jani.nikula@intel.com>
> Cc: Andi Shyti <andi.shyti@linux.intel.com>
> Cc: Andrzej Hajda <andrzej.hajda@intel.com>
> Cc: Mauro Carvalho Chehab <mauro.chehab@linux.intel.com>
> Cc: Kees Cook <keescook@chromium.org>
> Reviewed-by: Mauro Carvalho Chehab <mchehab@kernel.org> (v5)
> ---
>  drivers/gpu/drm/i915/i915_user_extensions.c |  3 +-
>  drivers/gpu/drm/i915/i915_utils.h           |  5 +-
>  include/linux/overflow.h                    | 62 +++++++++++++++++++++
>  3 files changed, 64 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_user_extensions.c b/drivers/gpu/drm/i915/i915_user_extensions.c
> index c822d0aafd2d..6f6b5b910968 100644
> --- a/drivers/gpu/drm/i915/i915_user_extensions.c
> +++ b/drivers/gpu/drm/i915/i915_user_extensions.c
> @@ -50,8 +50,7 @@ int i915_user_extensions(struct i915_user_extension __user *ext,
>  		if (err)
>  			return err;
>  
> -		if (get_user(next, &ext->next_extension) ||
> -		    overflows_type(next, ext))
> +		if (get_user(next, &ext->next_extension) || overflows_ptr(next))
>  			return -EFAULT;
>  
>  		ext = u64_to_user_ptr(next);

I continue to dislike the layers of macros and specialization here.
This is just a fancy version of check_assign():

	if (get_user(next, &ext->next_extension) || check_assign(next, &ext))
		return -EFAULT;

However, the __builtin_*_overflow() family only wants to work on
integral types, so this needs to be slightly expanded:

	uintptr_t kptr;
	...
	if (get_user(next, &ext->next_extension) || check_assign(next, &kptr))
		return -EFAULT;

	ext = (void * __user)kptr;

But, it does seem like the actual problem here is that u64_to_user_ptr()
is not performing the checking? It's used heavily in the drm code.

Is a check_assign_user_ptr() needed?

> diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h
> index c10d68cdc3ca..eb0ded23fa9c 100644
> --- a/drivers/gpu/drm/i915/i915_utils.h
> +++ b/drivers/gpu/drm/i915/i915_utils.h
> @@ -32,6 +32,7 @@
>  #include <linux/types.h>
>  #include <linux/workqueue.h>
>  #include <linux/sched/clock.h>
> +#include <linux/overflow.h>
>  
>  #ifdef CONFIG_X86
>  #include <asm/hypervisor.h>
> @@ -111,10 +112,6 @@ bool i915_error_injected(void);
>  #define range_overflows_end_t(type, start, size, max) \
>  	range_overflows_end((type)(start), (type)(size), (type)(max))
>  
> -/* Note we don't consider signbits :| */
> -#define overflows_type(x, T) \
> -	(sizeof(x) > sizeof(T) && (x) >> BITS_PER_TYPE(T))
> -
>  #define ptr_mask_bits(ptr, n) ({					\
>  	unsigned long __v = (unsigned long)(ptr);			\
>  	(typeof(ptr))(__v & -BIT(n));					\
> diff --git a/include/linux/overflow.h b/include/linux/overflow.h
> index f1221d11f8e5..6af9df1d67a1 100644
> --- a/include/linux/overflow.h
> +++ b/include/linux/overflow.h
> @@ -52,6 +52,68 @@ static inline bool __must_check __must_check_overflow(bool overflow)
>  	return unlikely(overflow);
>  }
>  
> +/**
> + * overflows_type - helper for checking the overflows between data types or
> + *                  values
> + *
> + * @x: Source value or data type for overflow check
> + * @T: Destination value or data type for overflow check
> + *
> + * It compares the values or data type between the first and second argument to
> + * check whether overflow can occur when assigning the first argument to the
> + * variable of the second argument. Source and Destination can be singned or
> + * unsigned data types. Source and Destination can be different data types.
> + *
> + * Returns:
> + * True if overflow can occur, false otherwise.
> + */
> +#define overflows_type(x, T) __must_check_overflow(({	\
> +	typeof(T) v = 0;				\
> +	__builtin_add_overflow((x), v, &v);		\
> +}))

I'd like to avoid "externalizing" these kinds of checks when the better
path is to catch the issue at operation type (add, sub, mul, assign).
Looking at existing users, I see stuff like:

                if (overflows_type(item.query_id - 1, unsigned long))
                        return -EINVAL;

                func_idx = item.query_id - 1;

This requires too much open-coded checking, IMO. It's better as:

		if (check_assign(item.query_id - 1, &func_idx))
			return -EINVAL;

or other similar:

        if (overflows_type(user->slice_mask, context->slice_mask) ||
	...
        context->slice_mask = user->slice_mask;

and some that don't make sense to me. Why check argument types? Is this
trying to avoid implicit type conversions?

So, if it's _really_ needed, I can live with adding overflows_type().

> +
> +/**
> + * overflows_ptr - helper for checking the occurrence of overflows when a value
> + *                 assigns to  the pointer data type
> + *
> + * @x: Source value for overflow check
> + *
> + * gcc's built-in overflow check functions don't support checking between the
> + * pointer type and non-pointer type. And ILP32 and LP64 have the same bit size
> + * between long and pointer. Therefore it internally compares the source value
> + * and unsigned long data type for checking overflow.
> + *
> + * Returns:
> + * True if overflow can occur, false otherwise.
> + */
> +#define overflows_ptr(x) __must_check_overflow(overflows_type(x, unsigned long))

I'd rather not have this -- it's just a specialized use of
overflows_type(), and only used in 1 place.

> +
> +/**
> + * check_assign - perform an assigning source value into destination ptr along
> + *                with an overflow check.
> + *
> + * @value: Source value
> + * @ptr: Destination pointer address, If the pointer type is not used,
> + *       a warning message is output during build.
> + *
> + * It checks internally the ptr is a pointer type. And it uses gcc's built-in
> + * overflow check function.
> + * It does not use the check_*() wrapper functions, but directly uses gcc's
> + * built-in overflow check function so that it can be used even when
> + * the type of value and the type pointed to by ptr are different without build
> + * warning messages.

This is a good point: the check_{add,sub,mul}_overflow() helpers
currently require all the params be the same type, which rather limits
their usage. Perhaps this can be weakened now that we're not using[1]
the fallback logic any more? (Separate patch.)

> + *
> + * Returns:
> + * If the value would overflow the destination, it returns true. If not return
> + * false. When overflow does not occur, the assigning into ptr from value
> + * succeeds. It follows the return policy as other check_*_overflow() functions
> + * return non-zero as a failure.
> + */
> +#define check_assign(value, ptr) __must_check_overflow(({	\
> +	typecheck_pointer(ptr); 		\
> +	__builtin_add_overflow(0, value, ptr);	\
> +}))

But yes, this looks correct. I really like it. :)

> +
>  /*
>   * For simplicity and code hygiene, the fallback code below insists on
>   * a, b and *d having the same type (similar to the min() and max()
> -- 
> 2.37.1
> 

-Kees

[1] 4eb6bd55cfb2 ("compiler.h: drop fallback overflow checkers")

-- 
Kees Cook

  parent reply	other threads:[~2022-08-25 16:47 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-24  8:45 [Intel-gfx] [PATCH v9 0/8] Fixes integer overflow or integer truncation issues in page lookups, ttm place configuration and scatterlist creation Gwan-gyeong Mun
2022-08-24  8:45 ` Gwan-gyeong Mun
2022-08-24  8:45 ` Gwan-gyeong Mun
2022-08-24  8:45 ` [Intel-gfx] [PATCH v9 1/8] overflow: Move and add few utility macros into overflow Gwan-gyeong Mun
2022-08-24  8:45   ` Gwan-gyeong Mun
2022-08-24  8:45   ` Gwan-gyeong Mun
2022-08-24 10:06   ` [Intel-gfx] " Andrzej Hajda
2022-08-24 10:06     ` Andrzej Hajda
2022-08-24 10:06     ` Andrzej Hajda
2022-08-25 16:47   ` Kees Cook [this message]
2022-08-25 16:47     ` Kees Cook
2022-08-25 16:47     ` Kees Cook
2022-08-26 13:44     ` [Intel-gfx] " Andrzej Hajda
2022-08-26 13:44       ` Andrzej Hajda
2022-08-26 13:44       ` Andrzej Hajda
2022-09-09 10:52       ` Gwan-gyeong Mun
2022-09-09 10:52         ` Gwan-gyeong Mun
2022-09-09 10:52         ` Gwan-gyeong Mun
2022-09-09 10:50     ` Gwan-gyeong Mun
2022-09-09 10:50       ` Gwan-gyeong Mun
2022-09-09 10:50       ` Gwan-gyeong Mun
2022-08-24  8:45 ` [Intel-gfx] [PATCH v9 2/8] util_macros: Add exact_type macro to catch type mis-match while compiling Gwan-gyeong Mun
2022-08-24  8:45   ` Gwan-gyeong Mun
2022-08-24  8:45   ` Gwan-gyeong Mun
2022-08-25  8:04   ` [Intel-gfx] " Gwan-gyeong Mun
2022-08-25  8:04     ` Gwan-gyeong Mun
2022-08-25  8:04     ` Gwan-gyeong Mun
2022-08-25 17:19   ` Kees Cook
2022-08-25 17:19     ` Kees Cook
2022-08-25 17:19     ` Kees Cook
2022-09-09 10:58     ` [Intel-gfx] " Gwan-gyeong Mun
2022-09-09 10:58       ` Gwan-gyeong Mun
2022-09-09 10:58       ` Gwan-gyeong Mun
2022-08-24  8:45 ` [Intel-gfx] [PATCH v9 3/8] drm/i915/gem: Typecheck page lookups Gwan-gyeong Mun
2022-08-24  8:45   ` Gwan-gyeong Mun
2022-08-24  8:45   ` Gwan-gyeong Mun
2022-08-24  8:45 ` [Intel-gfx] [PATCH v9 4/8] drm/i915: Check for integer truncation on scatterlist creation Gwan-gyeong Mun
2022-08-24  8:45   ` Gwan-gyeong Mun
2022-08-24  8:45   ` Gwan-gyeong Mun
2022-08-24  8:45 ` [Intel-gfx] [PATCH v9 5/8] drm/i915: Check for integer truncation on the configuration of ttm place Gwan-gyeong Mun
2022-08-24  8:45   ` Gwan-gyeong Mun
2022-08-24  8:45   ` Gwan-gyeong Mun
2022-08-24  8:45 ` [Intel-gfx] [PATCH v9 6/8] drm/i915: Check if the size is too big while creating shmem file Gwan-gyeong Mun
2022-08-24  8:45   ` Gwan-gyeong Mun
2022-08-24  8:45   ` Gwan-gyeong Mun
2022-08-24  8:45 ` [Intel-gfx] [PATCH v9 7/8] drm/i915: Use error code as -E2BIG when the size of gem ttm object is too large Gwan-gyeong Mun
2022-08-24  8:45   ` Gwan-gyeong Mun
2022-08-24  8:45   ` Gwan-gyeong Mun
2022-08-24  8:45 ` [Intel-gfx] [PATCH v9 8/8] drm/i915: Remove truncation warning for large objects Gwan-gyeong Mun
2022-08-24  8:45   ` Gwan-gyeong Mun
2022-08-24  8:45   ` Gwan-gyeong Mun
2022-08-24  9:14 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for Fixes integer overflow or integer truncation issues in page lookups, ttm place configuration and scatterlist creation Patchwork
2022-08-24  9:36 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2022-08-25 10:43 ` [Intel-gfx] ✓ Fi.CI.IGT: " Patchwork

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=202208250848.1C77B9C38@keescook \
    --to=keescook@chromium.org \
    --cc=airlied@linux.ie \
    --cc=andrzej.hajda@intel.com \
    --cc=chris@chris-wilson.co.uk \
    --cc=daniel@ffwll.ch \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=gwan-gyeong.mun@intel.com \
    --cc=intel-gfx-trybot@lists.freedesktop.org \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=jani.nikula@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@rasmusvillemoes.dk \
    --cc=matthew.auld@intel.com \
    --cc=mchehab@kernel.org \
    --cc=ndesaulniers@google.com \
    --cc=nirmoy.das@intel.com \
    --cc=thomas.hellstrom@linux.intel.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.