Skip to content

Commit 4b21d25

Browse files
committed
overflow: Introduce overflows_type() and castable_to_type()
Implement a robust overflows_type() macro to test if a variable or constant value would overflow another variable or type. This can be used as a constant expression for static_assert() (which requires a constant expression[1][2]) when used on constant values. This must be constructed manually, since __builtin_add_overflow() does not produce a constant expression[3]. Additionally adds castable_to_type(), similar to __same_type(), but for checking if a constant value would overflow if cast to a given type. Add unit tests for overflows_type(), __same_type(), and castable_to_type() to the existing KUnit "overflow" test: [16:03:33] ================== overflow (21 subtests) ================== ... [16:03:33] [PASSED] overflows_type_test [16:03:33] [PASSED] same_type_test [16:03:33] [PASSED] castable_to_type_test [16:03:33] ==================== [PASSED] overflow ===================== [16:03:33] ============================================================ [16:03:33] Testing complete. Ran 21 tests: passed: 21 [16:03:33] Elapsed time: 24.022s total, 0.002s configuring, 22.598s building, 0.767s running [1] https://en.cppreference.com/w/c/language/_Static_assert [2] C11 standard (ISO/IEC 9899:2011): 6.7.10 Static assertions [3] https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html 6.56 Built-in Functions to Perform Arithmetic with Overflow Checking Built-in Function: bool __builtin_add_overflow (type1 a, type2 b, Cc: Luc Van Oostenryck <[email protected]> Cc: Nathan Chancellor <[email protected]> Cc: Nick Desaulniers <[email protected]> Cc: Tom Rix <[email protected]> Cc: Daniel Latypov <[email protected]> Cc: Vitor Massaru Iha <[email protected]> Cc: "Gustavo A. R. Silva" <[email protected]> Cc: Jani Nikula <[email protected]> Cc: Mauro Carvalho Chehab <[email protected]> Cc: [email protected] Cc: [email protected] Co-developed-by: Gwan-gyeong Mun <[email protected]> Signed-off-by: Gwan-gyeong Mun <[email protected]> Signed-off-by: Kees Cook <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 6dd142d commit 4b21d25

File tree

6 files changed

+431
-5
lines changed

6 files changed

+431
-5
lines changed

drivers/gpu/drm/i915/i915_user_extensions.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ int i915_user_extensions(struct i915_user_extension __user *ext,
5151
return err;
5252

5353
if (get_user(next, &ext->next_extension) ||
54-
overflows_type(next, ext))
54+
overflows_type(next, uintptr_t))
5555
return -EFAULT;
5656

5757
ext = u64_to_user_ptr(next);

drivers/gpu/drm/i915/i915_utils.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,6 @@ bool i915_error_injected(void);
111111
#define range_overflows_end_t(type, start, size, max) \
112112
range_overflows_end((type)(start), (type)(size), (type)(max))
113113

114-
/* Note we don't consider signbits :| */
115-
#define overflows_type(x, T) \
116-
(sizeof(x) > sizeof(T) && (x) >> BITS_PER_TYPE(T))
117-
118114
#define ptr_mask_bits(ptr, n) ({ \
119115
unsigned long __v = (unsigned long)(ptr); \
120116
(typeof(ptr))(__v & -BIT(n)); \

include/linux/compiler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ static inline void *offset_to_ptr(const int *off)
236236
* bool and also pointer types.
237237
*/
238238
#define is_signed_type(type) (((type)(-1)) < (__force type)1)
239+
#define is_unsigned_type(type) (!is_signed_type(type))
239240

240241
/*
241242
* This is needed in functions which generate the stack canary, see

include/linux/overflow.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,53 @@ static inline bool __must_check __must_check_overflow(bool overflow)
128128
(*_d >> _to_shift) != _a); \
129129
}))
130130

131+
#define __overflows_type_constexpr(x, T) ( \
132+
is_unsigned_type(typeof(x)) ? \
133+
(x) > type_max(typeof(T)) : \
134+
is_unsigned_type(typeof(T)) ? \
135+
(x) < 0 || (x) > type_max(typeof(T)) : \
136+
(x) < type_min(typeof(T)) || (x) > type_max(typeof(T)))
137+
138+
#define __overflows_type(x, T) ({ \
139+
typeof(T) v = 0; \
140+
check_add_overflow((x), v, &v); \
141+
})
142+
143+
/**
144+
* overflows_type - helper for checking the overflows between value, variables,
145+
* or data type
146+
*
147+
* @n: source constant value or variable to be checked
148+
* @T: destination variable or data type proposed to store @x
149+
*
150+
* Compares the @x expression for whether or not it can safely fit in
151+
* the storage of the type in @T. @x and @T can have different types.
152+
* If @x is a constant expression, this will also resolve to a constant
153+
* expression.
154+
*
155+
* Returns: true if overflow can occur, false otherwise.
156+
*/
157+
#define overflows_type(n, T) \
158+
__builtin_choose_expr(__is_constexpr(n), \
159+
__overflows_type_constexpr(n, T), \
160+
__overflows_type(n, T))
161+
162+
/**
163+
* castable_to_type - like __same_type(), but also allows for casted literals
164+
*
165+
* @n: variable or constant value
166+
* @T: variable or data type
167+
*
168+
* Unlike the __same_type() macro, this allows a constant value as the
169+
* first argument. If this value would not overflow into an assignment
170+
* of the second argument's type, it returns true. Otherwise, this falls
171+
* back to __same_type().
172+
*/
173+
#define castable_to_type(n, T) \
174+
__builtin_choose_expr(__is_constexpr(n), \
175+
!__overflows_type_constexpr(n, T), \
176+
__same_type(n, T))
177+
131178
/**
132179
* size_mul() - Calculate size_t multiplication with saturation at SIZE_MAX
133180
* @factor1: first factor

lib/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ obj-$(CONFIG_CMDLINE_KUNIT_TEST) += cmdline_kunit.o
374374
obj-$(CONFIG_SLUB_KUNIT_TEST) += slub_kunit.o
375375
obj-$(CONFIG_MEMCPY_KUNIT_TEST) += memcpy_kunit.o
376376
obj-$(CONFIG_IS_SIGNED_TYPE_KUNIT_TEST) += is_signed_type_kunit.o
377+
CFLAGS_overflow_kunit.o = $(call cc-disable-warning, tautological-constant-out-of-range-compare)
377378
obj-$(CONFIG_OVERFLOW_KUNIT_TEST) += overflow_kunit.o
378379
CFLAGS_stackinit_kunit.o += $(call cc-disable-warning, switch-unreachable)
379380
obj-$(CONFIG_STACKINIT_KUNIT_TEST) += stackinit_kunit.o

0 commit comments

Comments
 (0)