2018-05-08 01:36:28 +03:00
// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
2022-02-17 01:17:49 +03:00
* Test cases for arithmetic overflow checks . See :
* https : //www.kernel.org/doc/html/latest/dev-tools/kunit/kunit-tool.html#configuring-building-and-running-tests
* . / tools / testing / kunit / kunit . py run overflow [ - - raw_output ]
2018-05-08 01:36:28 +03:00
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2022-02-17 01:17:49 +03:00
# include <kunit/test.h>
2018-05-11 02:40:03 +03:00
# include <linux/device.h>
2018-05-08 01:36:28 +03:00
# include <linux/kernel.h>
2018-05-11 02:40:03 +03:00
# include <linux/mm.h>
2018-05-08 01:36:28 +03:00
# include <linux/module.h>
# include <linux/overflow.h>
2018-05-11 02:40:03 +03:00
# include <linux/slab.h>
2018-05-08 01:36:28 +03:00
# include <linux/types.h>
2018-05-11 02:40:03 +03:00
# include <linux/vmalloc.h>
2018-05-08 01:36:28 +03:00
# define DEFINE_TEST_ARRAY(t) \
static const struct test_ # # t { \
t a , b ; \
t sum , diff , prod ; \
bool s_of , d_of , p_of ; \
2022-02-17 01:17:49 +03:00
} t # # _tests [ ]
2018-05-08 01:36:28 +03:00
DEFINE_TEST_ARRAY ( u8 ) = {
{ 0 , 0 , 0 , 0 , 0 , false , false , false } ,
{ 1 , 1 , 2 , 0 , 1 , false , false , false } ,
{ 0 , 1 , 1 , U8_MAX , 0 , false , true , false } ,
{ 1 , 0 , 1 , 1 , 0 , false , false , false } ,
{ 0 , U8_MAX , U8_MAX , 1 , 0 , false , true , false } ,
{ U8_MAX , 0 , U8_MAX , U8_MAX , 0 , false , false , false } ,
{ 1 , U8_MAX , 0 , 2 , U8_MAX , true , true , false } ,
{ U8_MAX , 1 , 0 , U8_MAX - 1 , U8_MAX , true , false , false } ,
{ U8_MAX , U8_MAX , U8_MAX - 1 , 0 , 1 , true , false , true } ,
{ U8_MAX , U8_MAX - 1 , U8_MAX - 2 , 1 , 2 , true , false , true } ,
{ U8_MAX - 1 , U8_MAX , U8_MAX - 2 , U8_MAX , 2 , true , true , true } ,
{ 1U < < 3 , 1U < < 3 , 1U < < 4 , 0 , 1U < < 6 , false , false , false } ,
{ 1U < < 4 , 1U < < 4 , 1U < < 5 , 0 , 0 , false , false , true } ,
{ 1U < < 4 , 1U < < 3 , 3 * ( 1U < < 3 ) , 1U < < 3 , 1U < < 7 , false , false , false } ,
{ 1U < < 7 , 1U < < 7 , 0 , 0 , 0 , true , false , true } ,
{ 48 , 32 , 80 , 16 , 0 , false , false , true } ,
{ 128 , 128 , 0 , 0 , 0 , true , false , true } ,
{ 123 , 234 , 101 , 145 , 110 , true , true , true } ,
} ;
DEFINE_TEST_ARRAY ( u16 ) = {
{ 0 , 0 , 0 , 0 , 0 , false , false , false } ,
{ 1 , 1 , 2 , 0 , 1 , false , false , false } ,
{ 0 , 1 , 1 , U16_MAX , 0 , false , true , false } ,
{ 1 , 0 , 1 , 1 , 0 , false , false , false } ,
{ 0 , U16_MAX , U16_MAX , 1 , 0 , false , true , false } ,
{ U16_MAX , 0 , U16_MAX , U16_MAX , 0 , false , false , false } ,
{ 1 , U16_MAX , 0 , 2 , U16_MAX , true , true , false } ,
{ U16_MAX , 1 , 0 , U16_MAX - 1 , U16_MAX , true , false , false } ,
{ U16_MAX , U16_MAX , U16_MAX - 1 , 0 , 1 , true , false , true } ,
{ U16_MAX , U16_MAX - 1 , U16_MAX - 2 , 1 , 2 , true , false , true } ,
{ U16_MAX - 1 , U16_MAX , U16_MAX - 2 , U16_MAX , 2 , true , true , true } ,
{ 1U < < 7 , 1U < < 7 , 1U < < 8 , 0 , 1U < < 14 , false , false , false } ,
{ 1U < < 8 , 1U < < 8 , 1U < < 9 , 0 , 0 , false , false , true } ,
{ 1U < < 8 , 1U < < 7 , 3 * ( 1U < < 7 ) , 1U < < 7 , 1U < < 15 , false , false , false } ,
{ 1U < < 15 , 1U < < 15 , 0 , 0 , 0 , true , false , true } ,
{ 123 , 234 , 357 , 65425 , 28782 , false , true , false } ,
{ 1234 , 2345 , 3579 , 64425 , 10146 , false , true , true } ,
} ;
DEFINE_TEST_ARRAY ( u32 ) = {
{ 0 , 0 , 0 , 0 , 0 , false , false , false } ,
{ 1 , 1 , 2 , 0 , 1 , false , false , false } ,
{ 0 , 1 , 1 , U32_MAX , 0 , false , true , false } ,
{ 1 , 0 , 1 , 1 , 0 , false , false , false } ,
{ 0 , U32_MAX , U32_MAX , 1 , 0 , false , true , false } ,
{ U32_MAX , 0 , U32_MAX , U32_MAX , 0 , false , false , false } ,
{ 1 , U32_MAX , 0 , 2 , U32_MAX , true , true , false } ,
{ U32_MAX , 1 , 0 , U32_MAX - 1 , U32_MAX , true , false , false } ,
{ U32_MAX , U32_MAX , U32_MAX - 1 , 0 , 1 , true , false , true } ,
{ U32_MAX , U32_MAX - 1 , U32_MAX - 2 , 1 , 2 , true , false , true } ,
{ U32_MAX - 1 , U32_MAX , U32_MAX - 2 , U32_MAX , 2 , true , true , true } ,
{ 1U < < 15 , 1U < < 15 , 1U < < 16 , 0 , 1U < < 30 , false , false , false } ,
{ 1U < < 16 , 1U < < 16 , 1U < < 17 , 0 , 0 , false , false , true } ,
{ 1U < < 16 , 1U < < 15 , 3 * ( 1U < < 15 ) , 1U < < 15 , 1U < < 31 , false , false , false } ,
{ 1U < < 31 , 1U < < 31 , 0 , 0 , 0 , true , false , true } ,
{ - 2U , 1U , - 1U , - 3U , - 2U , false , false , false } ,
{ - 4U , 5U , 1U , - 9U , - 20U , true , false , true } ,
} ;
2022-05-11 20:40:43 +03:00
# if BITS_PER_LONG == 64
2018-05-08 01:36:28 +03:00
DEFINE_TEST_ARRAY ( u64 ) = {
{ 0 , 0 , 0 , 0 , 0 , false , false , false } ,
{ 1 , 1 , 2 , 0 , 1 , false , false , false } ,
{ 0 , 1 , 1 , U64_MAX , 0 , false , true , false } ,
{ 1 , 0 , 1 , 1 , 0 , false , false , false } ,
{ 0 , U64_MAX , U64_MAX , 1 , 0 , false , true , false } ,
{ U64_MAX , 0 , U64_MAX , U64_MAX , 0 , false , false , false } ,
{ 1 , U64_MAX , 0 , 2 , U64_MAX , true , true , false } ,
{ U64_MAX , 1 , 0 , U64_MAX - 1 , U64_MAX , true , false , false } ,
{ U64_MAX , U64_MAX , U64_MAX - 1 , 0 , 1 , true , false , true } ,
{ U64_MAX , U64_MAX - 1 , U64_MAX - 2 , 1 , 2 , true , false , true } ,
{ U64_MAX - 1 , U64_MAX , U64_MAX - 2 , U64_MAX , 2 , true , true , true } ,
{ 1ULL < < 31 , 1ULL < < 31 , 1ULL < < 32 , 0 , 1ULL < < 62 , false , false , false } ,
{ 1ULL < < 32 , 1ULL < < 32 , 1ULL < < 33 , 0 , 0 , false , false , true } ,
{ 1ULL < < 32 , 1ULL < < 31 , 3 * ( 1ULL < < 31 ) , 1ULL < < 31 , 1ULL < < 63 , false , false , false } ,
{ 1ULL < < 63 , 1ULL < < 63 , 0 , 0 , 0 , true , false , true } ,
{ 1000000000ULL /* 10^9 */ , 10000000000ULL /* 10^10 */ ,
11000000000ULL , 18446744064709551616ULL , 10000000000000000000ULL ,
false , true , false } ,
{ - 15ULL , 10ULL , - 5ULL , - 25ULL , - 150ULL , false , false , true } ,
} ;
2022-05-11 20:40:43 +03:00
# endif
2018-05-08 01:36:28 +03:00
DEFINE_TEST_ARRAY ( s8 ) = {
{ 0 , 0 , 0 , 0 , 0 , false , false , false } ,
{ 0 , S8_MAX , S8_MAX , - S8_MAX , 0 , false , false , false } ,
{ S8_MAX , 0 , S8_MAX , S8_MAX , 0 , false , false , false } ,
{ 0 , S8_MIN , S8_MIN , S8_MIN , 0 , false , true , false } ,
{ S8_MIN , 0 , S8_MIN , S8_MIN , 0 , false , false , false } ,
{ - 1 , S8_MIN , S8_MAX , S8_MAX , S8_MIN , true , false , true } ,
{ S8_MIN , - 1 , S8_MAX , - S8_MAX , S8_MIN , true , false , true } ,
{ - 1 , S8_MAX , S8_MAX - 1 , S8_MIN , - S8_MAX , false , false , false } ,
{ S8_MAX , - 1 , S8_MAX - 1 , S8_MIN , - S8_MAX , false , true , false } ,
{ - 1 , - S8_MAX , S8_MIN , S8_MAX - 1 , S8_MAX , false , false , false } ,
{ - S8_MAX , - 1 , S8_MIN , S8_MIN + 2 , S8_MAX , false , false , false } ,
{ 1 , S8_MIN , - S8_MAX , - S8_MAX , S8_MIN , false , true , false } ,
{ S8_MIN , 1 , - S8_MAX , S8_MAX , S8_MIN , false , true , false } ,
{ 1 , S8_MAX , S8_MIN , S8_MIN + 2 , S8_MAX , true , false , false } ,
{ S8_MAX , 1 , S8_MIN , S8_MAX - 1 , S8_MAX , true , false , false } ,
{ S8_MIN , S8_MIN , 0 , 0 , 0 , true , false , true } ,
{ S8_MAX , S8_MAX , - 2 , 0 , 1 , true , false , true } ,
{ - 4 , - 32 , - 36 , 28 , - 128 , false , false , true } ,
{ - 4 , 32 , 28 , - 36 , - 128 , false , false , false } ,
} ;
DEFINE_TEST_ARRAY ( s16 ) = {
{ 0 , 0 , 0 , 0 , 0 , false , false , false } ,
{ 0 , S16_MAX , S16_MAX , - S16_MAX , 0 , false , false , false } ,
{ S16_MAX , 0 , S16_MAX , S16_MAX , 0 , false , false , false } ,
{ 0 , S16_MIN , S16_MIN , S16_MIN , 0 , false , true , false } ,
{ S16_MIN , 0 , S16_MIN , S16_MIN , 0 , false , false , false } ,
{ - 1 , S16_MIN , S16_MAX , S16_MAX , S16_MIN , true , false , true } ,
{ S16_MIN , - 1 , S16_MAX , - S16_MAX , S16_MIN , true , false , true } ,
{ - 1 , S16_MAX , S16_MAX - 1 , S16_MIN , - S16_MAX , false , false , false } ,
{ S16_MAX , - 1 , S16_MAX - 1 , S16_MIN , - S16_MAX , false , true , false } ,
{ - 1 , - S16_MAX , S16_MIN , S16_MAX - 1 , S16_MAX , false , false , false } ,
{ - S16_MAX , - 1 , S16_MIN , S16_MIN + 2 , S16_MAX , false , false , false } ,
{ 1 , S16_MIN , - S16_MAX , - S16_MAX , S16_MIN , false , true , false } ,
{ S16_MIN , 1 , - S16_MAX , S16_MAX , S16_MIN , false , true , false } ,
{ 1 , S16_MAX , S16_MIN , S16_MIN + 2 , S16_MAX , true , false , false } ,
{ S16_MAX , 1 , S16_MIN , S16_MAX - 1 , S16_MAX , true , false , false } ,
{ S16_MIN , S16_MIN , 0 , 0 , 0 , true , false , true } ,
{ S16_MAX , S16_MAX , - 2 , 0 , 1 , true , false , true } ,
} ;
DEFINE_TEST_ARRAY ( s32 ) = {
{ 0 , 0 , 0 , 0 , 0 , false , false , false } ,
{ 0 , S32_MAX , S32_MAX , - S32_MAX , 0 , false , false , false } ,
{ S32_MAX , 0 , S32_MAX , S32_MAX , 0 , false , false , false } ,
{ 0 , S32_MIN , S32_MIN , S32_MIN , 0 , false , true , false } ,
{ S32_MIN , 0 , S32_MIN , S32_MIN , 0 , false , false , false } ,
{ - 1 , S32_MIN , S32_MAX , S32_MAX , S32_MIN , true , false , true } ,
{ S32_MIN , - 1 , S32_MAX , - S32_MAX , S32_MIN , true , false , true } ,
{ - 1 , S32_MAX , S32_MAX - 1 , S32_MIN , - S32_MAX , false , false , false } ,
{ S32_MAX , - 1 , S32_MAX - 1 , S32_MIN , - S32_MAX , false , true , false } ,
{ - 1 , - S32_MAX , S32_MIN , S32_MAX - 1 , S32_MAX , false , false , false } ,
{ - S32_MAX , - 1 , S32_MIN , S32_MIN + 2 , S32_MAX , false , false , false } ,
{ 1 , S32_MIN , - S32_MAX , - S32_MAX , S32_MIN , false , true , false } ,
{ S32_MIN , 1 , - S32_MAX , S32_MAX , S32_MIN , false , true , false } ,
{ 1 , S32_MAX , S32_MIN , S32_MIN + 2 , S32_MAX , true , false , false } ,
{ S32_MAX , 1 , S32_MIN , S32_MAX - 1 , S32_MAX , true , false , false } ,
{ S32_MIN , S32_MIN , 0 , 0 , 0 , true , false , true } ,
{ S32_MAX , S32_MAX , - 2 , 0 , 1 , true , false , true } ,
} ;
2022-05-11 20:40:43 +03:00
# if BITS_PER_LONG == 64
2018-05-08 01:36:28 +03:00
DEFINE_TEST_ARRAY ( s64 ) = {
{ 0 , 0 , 0 , 0 , 0 , false , false , false } ,
{ 0 , S64_MAX , S64_MAX , - S64_MAX , 0 , false , false , false } ,
{ S64_MAX , 0 , S64_MAX , S64_MAX , 0 , false , false , false } ,
{ 0 , S64_MIN , S64_MIN , S64_MIN , 0 , false , true , false } ,
{ S64_MIN , 0 , S64_MIN , S64_MIN , 0 , false , false , false } ,
{ - 1 , S64_MIN , S64_MAX , S64_MAX , S64_MIN , true , false , true } ,
{ S64_MIN , - 1 , S64_MAX , - S64_MAX , S64_MIN , true , false , true } ,
{ - 1 , S64_MAX , S64_MAX - 1 , S64_MIN , - S64_MAX , false , false , false } ,
{ S64_MAX , - 1 , S64_MAX - 1 , S64_MIN , - S64_MAX , false , true , false } ,
{ - 1 , - S64_MAX , S64_MIN , S64_MAX - 1 , S64_MAX , false , false , false } ,
{ - S64_MAX , - 1 , S64_MIN , S64_MIN + 2 , S64_MAX , false , false , false } ,
{ 1 , S64_MIN , - S64_MAX , - S64_MAX , S64_MIN , false , true , false } ,
{ S64_MIN , 1 , - S64_MAX , S64_MAX , S64_MIN , false , true , false } ,
{ 1 , S64_MAX , S64_MIN , S64_MIN + 2 , S64_MAX , true , false , false } ,
{ S64_MAX , 1 , S64_MIN , S64_MAX - 1 , S64_MAX , true , false , false } ,
{ S64_MIN , S64_MIN , 0 , 0 , 0 , true , false , true } ,
{ S64_MAX , S64_MAX , - 2 , 0 , 1 , true , false , true } ,
{ - 1 , - 1 , - 2 , 0 , 1 , false , false , false } ,
{ - 1 , - 128 , - 129 , 127 , 128 , false , false , false } ,
{ - 128 , - 1 , - 129 , - 127 , 128 , false , false , false } ,
{ 0 , - S64_MAX , - S64_MAX , S64_MAX , 0 , false , false , false } ,
} ;
2022-05-11 20:40:43 +03:00
# endif
2018-05-08 01:36:28 +03:00
2018-06-04 09:41:27 +03:00
# define check_one_op(t, fmt, op, sym, a, b, r, of) do { \
t _r ; \
bool _of ; \
\
_of = check_ # # op # # _overflow ( a , b , & _r ) ; \
2022-02-17 01:17:49 +03:00
KUNIT_EXPECT_EQ_MSG ( test , _of , of , \
" expected " fmt " " sym " " fmt " to%s overflow (type %s) \n " , \
a , b , of ? " " : " not " , # t ) ; \
KUNIT_EXPECT_EQ_MSG ( test , _r , r , \
" expected " fmt " " sym " " fmt " == " fmt " , got " fmt " (type %s) \n " , \
a , b , r , _r , # t ) ; \
2018-06-04 09:41:27 +03:00
} while ( 0 )
2018-05-08 01:36:28 +03:00
# define DEFINE_TEST_FUNC(t, fmt) \
2022-02-17 01:17:49 +03:00
static void do_test_ # # t ( struct kunit * test , const struct test_ # # t * p ) \
2018-05-08 01:36:28 +03:00
{ \
2018-06-04 09:41:27 +03:00
check_one_op ( t , fmt , add , " + " , p - > a , p - > b , p - > sum , p - > s_of ) ; \
check_one_op ( t , fmt , add , " + " , p - > b , p - > a , p - > sum , p - > s_of ) ; \
check_one_op ( t , fmt , sub , " - " , p - > a , p - > b , p - > diff , p - > d_of ) ; \
check_one_op ( t , fmt , mul , " * " , p - > a , p - > b , p - > prod , p - > p_of ) ; \
check_one_op ( t , fmt , mul , " * " , p - > b , p - > a , p - > prod , p - > p_of ) ; \
2018-05-08 01:36:28 +03:00
} \
\
2022-02-17 01:17:49 +03:00
static void t # # _overflow_test ( struct kunit * test ) { \
2018-05-08 01:36:28 +03:00
unsigned i ; \
\
for ( i = 0 ; i < ARRAY_SIZE ( t # # _tests ) ; + + i ) \
2022-02-17 01:17:49 +03:00
do_test_ # # t ( test , & t # # _tests [ i ] ) ; \
kunit_info ( test , " %zu %s arithmetic tests finished \n " , \
2021-09-20 20:27:16 +03:00
ARRAY_SIZE ( t # # _tests ) , # t ) ; \
2018-05-08 01:36:28 +03:00
}
DEFINE_TEST_FUNC ( u8 , " %d " ) ;
DEFINE_TEST_FUNC ( s8 , " %d " ) ;
DEFINE_TEST_FUNC ( u16 , " %d " ) ;
DEFINE_TEST_FUNC ( s16 , " %d " ) ;
DEFINE_TEST_FUNC ( u32 , " %u " ) ;
DEFINE_TEST_FUNC ( s32 , " %d " ) ;
# if BITS_PER_LONG == 64
DEFINE_TEST_FUNC ( u64 , " %llu " ) ;
DEFINE_TEST_FUNC ( s64 , " %lld " ) ;
# endif
2022-02-17 01:17:49 +03:00
static void overflow_shift_test ( struct kunit * test )
2018-05-08 01:36:28 +03:00
{
2021-09-20 20:27:16 +03:00
int count = 0 ;
2018-08-02 00:25:40 +03:00
/* Args are: value, shift, type, expected result, overflow expected */
2022-02-17 01:17:49 +03:00
# define TEST_ONE_SHIFT(a, s, t, expect, of) do { \
2018-08-02 00:25:40 +03:00
typeof ( a ) __a = ( a ) ; \
typeof ( s ) __s = ( s ) ; \
t __e = ( expect ) ; \
t __d ; \
bool __of = check_shl_overflow ( __a , __s , & __d ) ; \
if ( __of ! = of ) { \
2022-02-17 01:17:49 +03:00
KUNIT_EXPECT_EQ_MSG ( test , __of , of , \
" expected (%s)(%s << %s) to%s overflow \n " , \
2018-08-02 00:25:40 +03:00
# t, #a, #s, of ? "" : " not"); \
} else if ( ! __of & & __d ! = __e ) { \
2022-02-17 01:17:49 +03:00
KUNIT_EXPECT_EQ_MSG ( test , __d , __e , \
" expected (%s)(%s << %s) == %s \n " , \
2018-08-02 00:25:40 +03:00
# t, #a, #s, #expect); \
if ( ( t ) - 1 < 0 ) \
2022-02-17 01:17:49 +03:00
kunit_info ( test , " got %lld \n " , ( s64 ) __d ) ; \
2018-08-02 00:25:40 +03:00
else \
2022-02-17 01:17:49 +03:00
kunit_info ( test , " got %llu \n " , ( u64 ) __d ) ; \
2018-08-02 00:25:40 +03:00
} \
2021-09-20 20:27:16 +03:00
count + + ; \
2022-02-17 01:17:49 +03:00
} while ( 0 )
2018-08-02 00:25:40 +03:00
/* Sane shifts. */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 1 , 0 , u8 , 1 < < 0 , false ) ;
TEST_ONE_SHIFT ( 1 , 4 , u8 , 1 < < 4 , false ) ;
TEST_ONE_SHIFT ( 1 , 7 , u8 , 1 < < 7 , false ) ;
TEST_ONE_SHIFT ( 0xF , 4 , u8 , 0xF < < 4 , false ) ;
TEST_ONE_SHIFT ( 1 , 0 , u16 , 1 < < 0 , false ) ;
TEST_ONE_SHIFT ( 1 , 10 , u16 , 1 < < 10 , false ) ;
TEST_ONE_SHIFT ( 1 , 15 , u16 , 1 < < 15 , false ) ;
TEST_ONE_SHIFT ( 0xFF , 8 , u16 , 0xFF < < 8 , false ) ;
TEST_ONE_SHIFT ( 1 , 0 , int , 1 < < 0 , false ) ;
TEST_ONE_SHIFT ( 1 , 16 , int , 1 < < 16 , false ) ;
TEST_ONE_SHIFT ( 1 , 30 , int , 1 < < 30 , false ) ;
TEST_ONE_SHIFT ( 1 , 0 , s32 , 1 < < 0 , false ) ;
TEST_ONE_SHIFT ( 1 , 16 , s32 , 1 < < 16 , false ) ;
TEST_ONE_SHIFT ( 1 , 30 , s32 , 1 < < 30 , false ) ;
TEST_ONE_SHIFT ( 1 , 0 , unsigned int , 1U < < 0 , false ) ;
TEST_ONE_SHIFT ( 1 , 20 , unsigned int , 1U < < 20 , false ) ;
TEST_ONE_SHIFT ( 1 , 31 , unsigned int , 1U < < 31 , false ) ;
TEST_ONE_SHIFT ( 0xFFFFU , 16 , unsigned int , 0xFFFFU < < 16 , false ) ;
TEST_ONE_SHIFT ( 1 , 0 , u32 , 1U < < 0 , false ) ;
TEST_ONE_SHIFT ( 1 , 20 , u32 , 1U < < 20 , false ) ;
TEST_ONE_SHIFT ( 1 , 31 , u32 , 1U < < 31 , false ) ;
TEST_ONE_SHIFT ( 0xFFFFU , 16 , u32 , 0xFFFFU < < 16 , false ) ;
TEST_ONE_SHIFT ( 1 , 0 , u64 , 1ULL < < 0 , false ) ;
TEST_ONE_SHIFT ( 1 , 40 , u64 , 1ULL < < 40 , false ) ;
TEST_ONE_SHIFT ( 1 , 63 , u64 , 1ULL < < 63 , false ) ;
TEST_ONE_SHIFT ( 0xFFFFFFFFULL , 32 , u64 , 0xFFFFFFFFULL < < 32 , false ) ;
2018-08-02 00:25:40 +03:00
/* Sane shift: start and end with 0, without a too-wide shift. */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 0 , 7 , u8 , 0 , false ) ;
TEST_ONE_SHIFT ( 0 , 15 , u16 , 0 , false ) ;
TEST_ONE_SHIFT ( 0 , 31 , unsigned int , 0 , false ) ;
TEST_ONE_SHIFT ( 0 , 31 , u32 , 0 , false ) ;
TEST_ONE_SHIFT ( 0 , 63 , u64 , 0 , false ) ;
2018-08-02 00:25:40 +03:00
/* Sane shift: start and end with 0, without reaching signed bit. */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 0 , 6 , s8 , 0 , false ) ;
TEST_ONE_SHIFT ( 0 , 14 , s16 , 0 , false ) ;
TEST_ONE_SHIFT ( 0 , 30 , int , 0 , false ) ;
TEST_ONE_SHIFT ( 0 , 30 , s32 , 0 , false ) ;
TEST_ONE_SHIFT ( 0 , 62 , s64 , 0 , false ) ;
2018-08-02 00:25:40 +03:00
/* Overflow: shifted the bit off the end. */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 1 , 8 , u8 , 0 , true ) ;
TEST_ONE_SHIFT ( 1 , 16 , u16 , 0 , true ) ;
TEST_ONE_SHIFT ( 1 , 32 , unsigned int , 0 , true ) ;
TEST_ONE_SHIFT ( 1 , 32 , u32 , 0 , true ) ;
TEST_ONE_SHIFT ( 1 , 64 , u64 , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* Overflow: shifted into the signed bit. */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 1 , 7 , s8 , 0 , true ) ;
TEST_ONE_SHIFT ( 1 , 15 , s16 , 0 , true ) ;
TEST_ONE_SHIFT ( 1 , 31 , int , 0 , true ) ;
TEST_ONE_SHIFT ( 1 , 31 , s32 , 0 , true ) ;
TEST_ONE_SHIFT ( 1 , 63 , s64 , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* Overflow: high bit falls off unsigned types. */
/* 10010110 */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 150 , 1 , u8 , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* 1000100010010110 */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 34966 , 1 , u16 , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* 10000100000010001000100010010110 */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 2215151766U , 1 , u32 , 0 , true ) ;
TEST_ONE_SHIFT ( 2215151766U , 1 , unsigned int , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* 1000001000010000010000000100000010000100000010001000100010010110 */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 9372061470395238550ULL , 1 , u64 , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* Overflow: bit shifted into signed bit on signed types. */
/* 01001011 */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 75 , 1 , s8 , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* 0100010001001011 */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 17483 , 1 , s16 , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* 01000010000001000100010001001011 */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 1107575883 , 1 , s32 , 0 , true ) ;
TEST_ONE_SHIFT ( 1107575883 , 1 , int , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* 0100000100001000001000000010000001000010000001000100010001001011 */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 4686030735197619275LL , 1 , s64 , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* Overflow: bit shifted past signed bit on signed types. */
/* 01001011 */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 75 , 2 , s8 , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* 0100010001001011 */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 17483 , 2 , s16 , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* 01000010000001000100010001001011 */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 1107575883 , 2 , s32 , 0 , true ) ;
TEST_ONE_SHIFT ( 1107575883 , 2 , int , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* 0100000100001000001000000010000001000010000001000100010001001011 */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 4686030735197619275LL , 2 , s64 , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* Overflow: values larger than destination type. */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 0x100 , 0 , u8 , 0 , true ) ;
TEST_ONE_SHIFT ( 0xFF , 0 , s8 , 0 , true ) ;
TEST_ONE_SHIFT ( 0x10000U , 0 , u16 , 0 , true ) ;
TEST_ONE_SHIFT ( 0xFFFFU , 0 , s16 , 0 , true ) ;
TEST_ONE_SHIFT ( 0x100000000ULL , 0 , u32 , 0 , true ) ;
TEST_ONE_SHIFT ( 0x100000000ULL , 0 , unsigned int , 0 , true ) ;
TEST_ONE_SHIFT ( 0xFFFFFFFFUL , 0 , s32 , 0 , true ) ;
TEST_ONE_SHIFT ( 0xFFFFFFFFUL , 0 , int , 0 , true ) ;
TEST_ONE_SHIFT ( 0xFFFFFFFFFFFFFFFFULL , 0 , s64 , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* Nonsense: negative initial value. */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( - 1 , 0 , s8 , 0 , true ) ;
TEST_ONE_SHIFT ( - 1 , 0 , u8 , 0 , true ) ;
TEST_ONE_SHIFT ( - 5 , 0 , s16 , 0 , true ) ;
TEST_ONE_SHIFT ( - 5 , 0 , u16 , 0 , true ) ;
TEST_ONE_SHIFT ( - 10 , 0 , int , 0 , true ) ;
TEST_ONE_SHIFT ( - 10 , 0 , unsigned int , 0 , true ) ;
TEST_ONE_SHIFT ( - 100 , 0 , s32 , 0 , true ) ;
TEST_ONE_SHIFT ( - 100 , 0 , u32 , 0 , true ) ;
TEST_ONE_SHIFT ( - 10000 , 0 , s64 , 0 , true ) ;
TEST_ONE_SHIFT ( - 10000 , 0 , u64 , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* Nonsense: negative shift values. */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 0 , - 5 , s8 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , - 5 , u8 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , - 10 , s16 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , - 10 , u16 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , - 15 , int , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , - 15 , unsigned int , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , - 20 , s32 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , - 20 , u32 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , - 30 , s64 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , - 30 , u64 , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/* Overflow: shifted at or beyond entire type's bit width. */
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 0 , 8 , u8 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 9 , u8 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 8 , s8 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 9 , s8 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 16 , u16 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 17 , u16 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 16 , s16 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 17 , s16 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 32 , u32 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 33 , u32 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 32 , int , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 33 , int , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 32 , s32 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 33 , s32 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 64 , u64 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 65 , u64 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 64 , s64 , 0 , true ) ;
TEST_ONE_SHIFT ( 0 , 65 , s64 , 0 , true ) ;
2018-08-02 00:25:40 +03:00
/*
* Corner case : for unsigned types , we fail when we ' ve shifted
* through the entire width of bits . For signed types , we might
* want to match this behavior , but that would mean noticing if
* we shift through all but the signed bit , and this is not
* currently detected ( but we ' ll notice an overflow into the
* signed bit ) . So , for now , we will test this condition but
* mark it as not expected to overflow .
*/
2022-02-17 01:17:49 +03:00
TEST_ONE_SHIFT ( 0 , 7 , s8 , 0 , false ) ;
TEST_ONE_SHIFT ( 0 , 15 , s16 , 0 , false ) ;
TEST_ONE_SHIFT ( 0 , 31 , int , 0 , false ) ;
TEST_ONE_SHIFT ( 0 , 31 , s32 , 0 , false ) ;
TEST_ONE_SHIFT ( 0 , 63 , s64 , 0 , false ) ;
2021-09-20 20:27:16 +03:00
2022-02-17 01:17:49 +03:00
kunit_info ( test , " %d shift tests finished \n " , count ) ;
2021-09-20 20:27:16 +03:00
# undef TEST_ONE_SHIFT
2018-08-02 00:25:40 +03:00
}
2018-05-11 02:40:03 +03:00
/*
* Deal with the various forms of allocator arguments . See comments above
* the DEFINE_TEST_ALLOC ( ) instances for mapping of the " bits " .
*/
2019-07-17 02:27:24 +03:00
# define alloc_GFP (GFP_KERNEL | __GFP_NOWARN)
# define alloc010(alloc, arg, sz) alloc(sz, alloc_GFP)
# define alloc011(alloc, arg, sz) alloc(sz, alloc_GFP, NUMA_NO_NODE)
2018-05-11 02:40:03 +03:00
# define alloc000(alloc, arg, sz) alloc(sz)
# define alloc001(alloc, arg, sz) alloc(sz, NUMA_NO_NODE)
2019-07-17 02:27:24 +03:00
# define alloc110(alloc, arg, sz) alloc(arg, sz, alloc_GFP)
2018-05-11 02:40:03 +03:00
# define free0(free, arg, ptr) free(ptr)
# define free1(free, arg, ptr) free(arg, ptr)
2019-07-17 02:27:24 +03:00
/* Wrap around to 16K */
# define TEST_SIZE (5 * 4096)
2018-05-11 02:40:03 +03:00
# define DEFINE_TEST_ALLOC(func, free_func, want_arg, want_gfp, want_node)\
2022-02-17 01:17:49 +03:00
static void test_ # # func ( struct kunit * test , void * arg ) \
2018-05-11 02:40:03 +03:00
{ \
volatile size_t a = TEST_SIZE ; \
volatile size_t b = ( SIZE_MAX / TEST_SIZE ) + 1 ; \
void * ptr ; \
\
/* Tiny allocation test. */ \
ptr = alloc # # want_arg # # want_gfp # # want_node ( func , arg , 1 ) ; \
2022-02-17 01:17:49 +03:00
KUNIT_ASSERT_NOT_ERR_OR_NULL_MSG ( test , ptr , \
# func " failed regular allocation?!\n"); \
2018-05-11 02:40:03 +03:00
free # # want_arg ( free_func , arg , ptr ) ; \
\
/* Wrapped allocation test. */ \
ptr = alloc # # want_arg # # want_gfp # # want_node ( func , arg , \
a * b ) ; \
2022-02-17 01:17:49 +03:00
KUNIT_ASSERT_NOT_ERR_OR_NULL_MSG ( test , ptr , \
# func " unexpectedly failed bad wrapping?!\n"); \
2018-05-11 02:40:03 +03:00
free # # want_arg ( free_func , arg , ptr ) ; \
\
/* Saturated allocation test. */ \
ptr = alloc # # want_arg # # want_gfp # # want_node ( func , arg , \
array_size ( a , b ) ) ; \
if ( ptr ) { \
2022-02-17 01:17:49 +03:00
KUNIT_FAIL ( test , # func " missed saturation! \n " ) ; \
2018-05-11 02:40:03 +03:00
free # # want_arg ( free_func , arg , ptr ) ; \
} \
}
/*
* Allocator uses a trailing node argument - - - - - - - - + ( e . g . kmalloc_node ( ) )
* Allocator uses the gfp_t argument - - - - - - - - - - - + | ( e . g . kmalloc ( ) )
* Allocator uses a special leading argument + | | ( e . g . devm_kmalloc ( ) )
* | | |
*/
DEFINE_TEST_ALLOC ( kmalloc , kfree , 0 , 1 , 0 ) ;
DEFINE_TEST_ALLOC ( kmalloc_node , kfree , 0 , 1 , 1 ) ;
DEFINE_TEST_ALLOC ( kzalloc , kfree , 0 , 1 , 0 ) ;
DEFINE_TEST_ALLOC ( kzalloc_node , kfree , 0 , 1 , 1 ) ;
2021-09-20 20:27:16 +03:00
DEFINE_TEST_ALLOC ( __vmalloc , vfree , 0 , 1 , 0 ) ;
2018-05-11 02:40:03 +03:00
DEFINE_TEST_ALLOC ( kvmalloc , kvfree , 0 , 1 , 0 ) ;
DEFINE_TEST_ALLOC ( kvmalloc_node , kvfree , 0 , 1 , 1 ) ;
DEFINE_TEST_ALLOC ( kvzalloc , kvfree , 0 , 1 , 0 ) ;
DEFINE_TEST_ALLOC ( kvzalloc_node , kvfree , 0 , 1 , 1 ) ;
DEFINE_TEST_ALLOC ( devm_kmalloc , devm_kfree , 1 , 1 , 0 ) ;
DEFINE_TEST_ALLOC ( devm_kzalloc , devm_kfree , 1 , 1 , 0 ) ;
2022-02-17 01:17:49 +03:00
static void overflow_allocation_test ( struct kunit * test )
2018-05-11 02:40:03 +03:00
{
const char device_name [ ] = " overflow-test " ;
struct device * dev ;
2021-09-20 20:27:16 +03:00
int count = 0 ;
2018-05-11 02:40:03 +03:00
2022-02-17 01:17:49 +03:00
# define check_allocation_overflow(alloc) do { \
2021-09-20 20:27:16 +03:00
count + + ; \
2022-02-17 01:17:49 +03:00
test_ # # alloc ( test , dev ) ; \
} while ( 0 )
2021-09-20 20:27:16 +03:00
2018-05-11 02:40:03 +03:00
/* Create dummy device for devm_kmalloc()-family tests. */
dev = root_device_register ( device_name ) ;
2022-02-17 01:17:49 +03:00
KUNIT_ASSERT_FALSE_MSG ( test , IS_ERR ( dev ) ,
" Cannot register test device \n " ) ;
check_allocation_overflow ( kmalloc ) ;
check_allocation_overflow ( kmalloc_node ) ;
check_allocation_overflow ( kzalloc ) ;
check_allocation_overflow ( kzalloc_node ) ;
check_allocation_overflow ( __vmalloc ) ;
check_allocation_overflow ( kvmalloc ) ;
check_allocation_overflow ( kvmalloc_node ) ;
check_allocation_overflow ( kvzalloc ) ;
check_allocation_overflow ( kvzalloc_node ) ;
check_allocation_overflow ( devm_kmalloc ) ;
check_allocation_overflow ( devm_kzalloc ) ;
2018-05-11 02:40:03 +03:00
device_unregister ( dev ) ;
2022-02-17 01:17:49 +03:00
kunit_info ( test , " %d allocation overflow tests finished \n " , count ) ;
2021-09-20 20:27:16 +03:00
# undef check_allocation_overflow
2018-05-11 02:40:03 +03:00
}
overflow: Implement size_t saturating arithmetic helpers
In order to perform more open-coded replacements of common allocation
size arithmetic, the kernel needs saturating (SIZE_MAX) helpers for
multiplication, addition, and subtraction. For example, it is common in
allocators, especially on realloc, to add to an existing size:
p = krealloc(map->patch,
sizeof(struct reg_sequence) * (map->patch_regs + num_regs),
GFP_KERNEL);
There is no existing saturating replacement for this calculation, and
just leaving the addition open coded inside array_size() could
potentially overflow as well. For example, an overflow in an expression
for a size_t argument might wrap to zero:
array_size(anything, something_at_size_max + 1) == 0
Introduce size_mul(), size_add(), and size_sub() helpers that
implicitly promote arguments to size_t and saturated calculations for
use in allocations. With these helpers it is also possible to redefine
array_size(), array3_size(), flex_array_size(), and struct_size() in
terms of the new helpers.
As with the check_*_overflow() helpers, the new helpers use __must_check,
though what is really desired is a way to make sure that assignment is
only to a size_t lvalue. Without this, it's still possible to introduce
overflow/underflow via type conversion (i.e. from size_t to int).
Enforcing this will currently need to be left to static analysis or
future use of -Wconversion.
Additionally update the overflow unit tests to force runtime evaluation
for the pathological cases.
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Gustavo A. R. Silva <gustavoars@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Keith Busch <kbusch@kernel.org>
Cc: Len Baker <len.baker@gmx.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
2021-09-19 01:17:53 +03:00
struct __test_flex_array {
unsigned long flags ;
size_t count ;
unsigned long data [ ] ;
} ;
2022-02-17 01:17:49 +03:00
static void overflow_size_helpers_test ( struct kunit * test )
overflow: Implement size_t saturating arithmetic helpers
In order to perform more open-coded replacements of common allocation
size arithmetic, the kernel needs saturating (SIZE_MAX) helpers for
multiplication, addition, and subtraction. For example, it is common in
allocators, especially on realloc, to add to an existing size:
p = krealloc(map->patch,
sizeof(struct reg_sequence) * (map->patch_regs + num_regs),
GFP_KERNEL);
There is no existing saturating replacement for this calculation, and
just leaving the addition open coded inside array_size() could
potentially overflow as well. For example, an overflow in an expression
for a size_t argument might wrap to zero:
array_size(anything, something_at_size_max + 1) == 0
Introduce size_mul(), size_add(), and size_sub() helpers that
implicitly promote arguments to size_t and saturated calculations for
use in allocations. With these helpers it is also possible to redefine
array_size(), array3_size(), flex_array_size(), and struct_size() in
terms of the new helpers.
As with the check_*_overflow() helpers, the new helpers use __must_check,
though what is really desired is a way to make sure that assignment is
only to a size_t lvalue. Without this, it's still possible to introduce
overflow/underflow via type conversion (i.e. from size_t to int).
Enforcing this will currently need to be left to static analysis or
future use of -Wconversion.
Additionally update the overflow unit tests to force runtime evaluation
for the pathological cases.
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Gustavo A. R. Silva <gustavoars@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Keith Busch <kbusch@kernel.org>
Cc: Len Baker <len.baker@gmx.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
2021-09-19 01:17:53 +03:00
{
2022-02-10 03:40:41 +03:00
/* Make sure struct_size() can be used in a constant expression. */
u8 ce_array [ struct_size ( ( struct __test_flex_array * ) 0 , data , 55 ) ] ;
overflow: Implement size_t saturating arithmetic helpers
In order to perform more open-coded replacements of common allocation
size arithmetic, the kernel needs saturating (SIZE_MAX) helpers for
multiplication, addition, and subtraction. For example, it is common in
allocators, especially on realloc, to add to an existing size:
p = krealloc(map->patch,
sizeof(struct reg_sequence) * (map->patch_regs + num_regs),
GFP_KERNEL);
There is no existing saturating replacement for this calculation, and
just leaving the addition open coded inside array_size() could
potentially overflow as well. For example, an overflow in an expression
for a size_t argument might wrap to zero:
array_size(anything, something_at_size_max + 1) == 0
Introduce size_mul(), size_add(), and size_sub() helpers that
implicitly promote arguments to size_t and saturated calculations for
use in allocations. With these helpers it is also possible to redefine
array_size(), array3_size(), flex_array_size(), and struct_size() in
terms of the new helpers.
As with the check_*_overflow() helpers, the new helpers use __must_check,
though what is really desired is a way to make sure that assignment is
only to a size_t lvalue. Without this, it's still possible to introduce
overflow/underflow via type conversion (i.e. from size_t to int).
Enforcing this will currently need to be left to static analysis or
future use of -Wconversion.
Additionally update the overflow unit tests to force runtime evaluation
for the pathological cases.
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Gustavo A. R. Silva <gustavoars@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Keith Busch <kbusch@kernel.org>
Cc: Len Baker <len.baker@gmx.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
2021-09-19 01:17:53 +03:00
struct __test_flex_array * obj ;
int count = 0 ;
int var ;
2022-02-10 03:40:41 +03:00
volatile int unconst = 0 ;
/* Verify constant expression against runtime version. */
var = 55 ;
OPTIMIZER_HIDE_VAR ( var ) ;
2022-02-17 01:17:49 +03:00
KUNIT_EXPECT_EQ ( test , sizeof ( ce_array ) , struct_size ( obj , data , var ) ) ;
overflow: Implement size_t saturating arithmetic helpers
In order to perform more open-coded replacements of common allocation
size arithmetic, the kernel needs saturating (SIZE_MAX) helpers for
multiplication, addition, and subtraction. For example, it is common in
allocators, especially on realloc, to add to an existing size:
p = krealloc(map->patch,
sizeof(struct reg_sequence) * (map->patch_regs + num_regs),
GFP_KERNEL);
There is no existing saturating replacement for this calculation, and
just leaving the addition open coded inside array_size() could
potentially overflow as well. For example, an overflow in an expression
for a size_t argument might wrap to zero:
array_size(anything, something_at_size_max + 1) == 0
Introduce size_mul(), size_add(), and size_sub() helpers that
implicitly promote arguments to size_t and saturated calculations for
use in allocations. With these helpers it is also possible to redefine
array_size(), array3_size(), flex_array_size(), and struct_size() in
terms of the new helpers.
As with the check_*_overflow() helpers, the new helpers use __must_check,
though what is really desired is a way to make sure that assignment is
only to a size_t lvalue. Without this, it's still possible to introduce
overflow/underflow via type conversion (i.e. from size_t to int).
Enforcing this will currently need to be left to static analysis or
future use of -Wconversion.
Additionally update the overflow unit tests to force runtime evaluation
for the pathological cases.
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Gustavo A. R. Silva <gustavoars@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Keith Busch <kbusch@kernel.org>
Cc: Len Baker <len.baker@gmx.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
2021-09-19 01:17:53 +03:00
2022-02-17 01:17:49 +03:00
# define check_one_size_helper(expected, func, args...) do { \
size_t _r = func ( args ) ; \
KUNIT_EXPECT_EQ_MSG ( test , _r , expected , \
" expected " # func " ( " # args " ) to return %zu but got %zu instead \n " , \
( size_t ) ( expected ) , _r ) ; \
overflow: Implement size_t saturating arithmetic helpers
In order to perform more open-coded replacements of common allocation
size arithmetic, the kernel needs saturating (SIZE_MAX) helpers for
multiplication, addition, and subtraction. For example, it is common in
allocators, especially on realloc, to add to an existing size:
p = krealloc(map->patch,
sizeof(struct reg_sequence) * (map->patch_regs + num_regs),
GFP_KERNEL);
There is no existing saturating replacement for this calculation, and
just leaving the addition open coded inside array_size() could
potentially overflow as well. For example, an overflow in an expression
for a size_t argument might wrap to zero:
array_size(anything, something_at_size_max + 1) == 0
Introduce size_mul(), size_add(), and size_sub() helpers that
implicitly promote arguments to size_t and saturated calculations for
use in allocations. With these helpers it is also possible to redefine
array_size(), array3_size(), flex_array_size(), and struct_size() in
terms of the new helpers.
As with the check_*_overflow() helpers, the new helpers use __must_check,
though what is really desired is a way to make sure that assignment is
only to a size_t lvalue. Without this, it's still possible to introduce
overflow/underflow via type conversion (i.e. from size_t to int).
Enforcing this will currently need to be left to static analysis or
future use of -Wconversion.
Additionally update the overflow unit tests to force runtime evaluation
for the pathological cases.
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Gustavo A. R. Silva <gustavoars@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Keith Busch <kbusch@kernel.org>
Cc: Len Baker <len.baker@gmx.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
2021-09-19 01:17:53 +03:00
count + + ; \
2022-02-17 01:17:49 +03:00
} while ( 0 )
overflow: Implement size_t saturating arithmetic helpers
In order to perform more open-coded replacements of common allocation
size arithmetic, the kernel needs saturating (SIZE_MAX) helpers for
multiplication, addition, and subtraction. For example, it is common in
allocators, especially on realloc, to add to an existing size:
p = krealloc(map->patch,
sizeof(struct reg_sequence) * (map->patch_regs + num_regs),
GFP_KERNEL);
There is no existing saturating replacement for this calculation, and
just leaving the addition open coded inside array_size() could
potentially overflow as well. For example, an overflow in an expression
for a size_t argument might wrap to zero:
array_size(anything, something_at_size_max + 1) == 0
Introduce size_mul(), size_add(), and size_sub() helpers that
implicitly promote arguments to size_t and saturated calculations for
use in allocations. With these helpers it is also possible to redefine
array_size(), array3_size(), flex_array_size(), and struct_size() in
terms of the new helpers.
As with the check_*_overflow() helpers, the new helpers use __must_check,
though what is really desired is a way to make sure that assignment is
only to a size_t lvalue. Without this, it's still possible to introduce
overflow/underflow via type conversion (i.e. from size_t to int).
Enforcing this will currently need to be left to static analysis or
future use of -Wconversion.
Additionally update the overflow unit tests to force runtime evaluation
for the pathological cases.
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Gustavo A. R. Silva <gustavoars@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Keith Busch <kbusch@kernel.org>
Cc: Len Baker <len.baker@gmx.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
2021-09-19 01:17:53 +03:00
var = 4 ;
2022-02-17 01:17:49 +03:00
check_one_size_helper ( 20 , size_mul , var + + , 5 ) ;
check_one_size_helper ( 20 , size_mul , 4 , var + + ) ;
check_one_size_helper ( 0 , size_mul , 0 , 3 ) ;
check_one_size_helper ( 0 , size_mul , 3 , 0 ) ;
check_one_size_helper ( 6 , size_mul , 2 , 3 ) ;
check_one_size_helper ( SIZE_MAX , size_mul , SIZE_MAX , 1 ) ;
check_one_size_helper ( SIZE_MAX , size_mul , SIZE_MAX , 3 ) ;
check_one_size_helper ( SIZE_MAX , size_mul , SIZE_MAX , - 3 ) ;
overflow: Implement size_t saturating arithmetic helpers
In order to perform more open-coded replacements of common allocation
size arithmetic, the kernel needs saturating (SIZE_MAX) helpers for
multiplication, addition, and subtraction. For example, it is common in
allocators, especially on realloc, to add to an existing size:
p = krealloc(map->patch,
sizeof(struct reg_sequence) * (map->patch_regs + num_regs),
GFP_KERNEL);
There is no existing saturating replacement for this calculation, and
just leaving the addition open coded inside array_size() could
potentially overflow as well. For example, an overflow in an expression
for a size_t argument might wrap to zero:
array_size(anything, something_at_size_max + 1) == 0
Introduce size_mul(), size_add(), and size_sub() helpers that
implicitly promote arguments to size_t and saturated calculations for
use in allocations. With these helpers it is also possible to redefine
array_size(), array3_size(), flex_array_size(), and struct_size() in
terms of the new helpers.
As with the check_*_overflow() helpers, the new helpers use __must_check,
though what is really desired is a way to make sure that assignment is
only to a size_t lvalue. Without this, it's still possible to introduce
overflow/underflow via type conversion (i.e. from size_t to int).
Enforcing this will currently need to be left to static analysis or
future use of -Wconversion.
Additionally update the overflow unit tests to force runtime evaluation
for the pathological cases.
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Gustavo A. R. Silva <gustavoars@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Keith Busch <kbusch@kernel.org>
Cc: Len Baker <len.baker@gmx.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
2021-09-19 01:17:53 +03:00
var = 4 ;
2022-02-17 01:17:49 +03:00
check_one_size_helper ( 9 , size_add , var + + , 5 ) ;
check_one_size_helper ( 9 , size_add , 4 , var + + ) ;
check_one_size_helper ( 9 , size_add , 9 , 0 ) ;
check_one_size_helper ( 9 , size_add , 0 , 9 ) ;
check_one_size_helper ( 5 , size_add , 2 , 3 ) ;
check_one_size_helper ( SIZE_MAX , size_add , SIZE_MAX , 1 ) ;
check_one_size_helper ( SIZE_MAX , size_add , SIZE_MAX , 3 ) ;
check_one_size_helper ( SIZE_MAX , size_add , SIZE_MAX , - 3 ) ;
overflow: Implement size_t saturating arithmetic helpers
In order to perform more open-coded replacements of common allocation
size arithmetic, the kernel needs saturating (SIZE_MAX) helpers for
multiplication, addition, and subtraction. For example, it is common in
allocators, especially on realloc, to add to an existing size:
p = krealloc(map->patch,
sizeof(struct reg_sequence) * (map->patch_regs + num_regs),
GFP_KERNEL);
There is no existing saturating replacement for this calculation, and
just leaving the addition open coded inside array_size() could
potentially overflow as well. For example, an overflow in an expression
for a size_t argument might wrap to zero:
array_size(anything, something_at_size_max + 1) == 0
Introduce size_mul(), size_add(), and size_sub() helpers that
implicitly promote arguments to size_t and saturated calculations for
use in allocations. With these helpers it is also possible to redefine
array_size(), array3_size(), flex_array_size(), and struct_size() in
terms of the new helpers.
As with the check_*_overflow() helpers, the new helpers use __must_check,
though what is really desired is a way to make sure that assignment is
only to a size_t lvalue. Without this, it's still possible to introduce
overflow/underflow via type conversion (i.e. from size_t to int).
Enforcing this will currently need to be left to static analysis or
future use of -Wconversion.
Additionally update the overflow unit tests to force runtime evaluation
for the pathological cases.
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Gustavo A. R. Silva <gustavoars@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Keith Busch <kbusch@kernel.org>
Cc: Len Baker <len.baker@gmx.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
2021-09-19 01:17:53 +03:00
var = 4 ;
2022-02-17 01:17:49 +03:00
check_one_size_helper ( 1 , size_sub , var - - , 3 ) ;
check_one_size_helper ( 1 , size_sub , 4 , var - - ) ;
check_one_size_helper ( 1 , size_sub , 3 , 2 ) ;
check_one_size_helper ( 9 , size_sub , 9 , 0 ) ;
check_one_size_helper ( SIZE_MAX , size_sub , 9 , - 3 ) ;
check_one_size_helper ( SIZE_MAX , size_sub , 0 , 9 ) ;
check_one_size_helper ( SIZE_MAX , size_sub , 2 , 3 ) ;
check_one_size_helper ( SIZE_MAX , size_sub , SIZE_MAX , 0 ) ;
check_one_size_helper ( SIZE_MAX , size_sub , SIZE_MAX , 10 ) ;
check_one_size_helper ( SIZE_MAX , size_sub , 0 , SIZE_MAX ) ;
check_one_size_helper ( SIZE_MAX , size_sub , 14 , SIZE_MAX ) ;
check_one_size_helper ( SIZE_MAX - 2 , size_sub , SIZE_MAX - 1 , 1 ) ;
check_one_size_helper ( SIZE_MAX - 4 , size_sub , SIZE_MAX - 1 , 3 ) ;
check_one_size_helper ( 1 , size_sub , SIZE_MAX - 1 , - 3 ) ;
overflow: Implement size_t saturating arithmetic helpers
In order to perform more open-coded replacements of common allocation
size arithmetic, the kernel needs saturating (SIZE_MAX) helpers for
multiplication, addition, and subtraction. For example, it is common in
allocators, especially on realloc, to add to an existing size:
p = krealloc(map->patch,
sizeof(struct reg_sequence) * (map->patch_regs + num_regs),
GFP_KERNEL);
There is no existing saturating replacement for this calculation, and
just leaving the addition open coded inside array_size() could
potentially overflow as well. For example, an overflow in an expression
for a size_t argument might wrap to zero:
array_size(anything, something_at_size_max + 1) == 0
Introduce size_mul(), size_add(), and size_sub() helpers that
implicitly promote arguments to size_t and saturated calculations for
use in allocations. With these helpers it is also possible to redefine
array_size(), array3_size(), flex_array_size(), and struct_size() in
terms of the new helpers.
As with the check_*_overflow() helpers, the new helpers use __must_check,
though what is really desired is a way to make sure that assignment is
only to a size_t lvalue. Without this, it's still possible to introduce
overflow/underflow via type conversion (i.e. from size_t to int).
Enforcing this will currently need to be left to static analysis or
future use of -Wconversion.
Additionally update the overflow unit tests to force runtime evaluation
for the pathological cases.
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Gustavo A. R. Silva <gustavoars@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Keith Busch <kbusch@kernel.org>
Cc: Len Baker <len.baker@gmx.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
2021-09-19 01:17:53 +03:00
var = 4 ;
2022-02-17 01:17:49 +03:00
check_one_size_helper ( 4 * sizeof ( * obj - > data ) ,
flex_array_size , obj , data , var + + ) ;
check_one_size_helper ( 5 * sizeof ( * obj - > data ) ,
flex_array_size , obj , data , var + + ) ;
check_one_size_helper ( 0 , flex_array_size , obj , data , 0 + unconst ) ;
check_one_size_helper ( sizeof ( * obj - > data ) ,
flex_array_size , obj , data , 1 + unconst ) ;
check_one_size_helper ( 7 * sizeof ( * obj - > data ) ,
flex_array_size , obj , data , 7 + unconst ) ;
check_one_size_helper ( SIZE_MAX ,
flex_array_size , obj , data , - 1 + unconst ) ;
check_one_size_helper ( SIZE_MAX ,
flex_array_size , obj , data , SIZE_MAX - 4 + unconst ) ;
overflow: Implement size_t saturating arithmetic helpers
In order to perform more open-coded replacements of common allocation
size arithmetic, the kernel needs saturating (SIZE_MAX) helpers for
multiplication, addition, and subtraction. For example, it is common in
allocators, especially on realloc, to add to an existing size:
p = krealloc(map->patch,
sizeof(struct reg_sequence) * (map->patch_regs + num_regs),
GFP_KERNEL);
There is no existing saturating replacement for this calculation, and
just leaving the addition open coded inside array_size() could
potentially overflow as well. For example, an overflow in an expression
for a size_t argument might wrap to zero:
array_size(anything, something_at_size_max + 1) == 0
Introduce size_mul(), size_add(), and size_sub() helpers that
implicitly promote arguments to size_t and saturated calculations for
use in allocations. With these helpers it is also possible to redefine
array_size(), array3_size(), flex_array_size(), and struct_size() in
terms of the new helpers.
As with the check_*_overflow() helpers, the new helpers use __must_check,
though what is really desired is a way to make sure that assignment is
only to a size_t lvalue. Without this, it's still possible to introduce
overflow/underflow via type conversion (i.e. from size_t to int).
Enforcing this will currently need to be left to static analysis or
future use of -Wconversion.
Additionally update the overflow unit tests to force runtime evaluation
for the pathological cases.
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Gustavo A. R. Silva <gustavoars@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Keith Busch <kbusch@kernel.org>
Cc: Len Baker <len.baker@gmx.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
2021-09-19 01:17:53 +03:00
var = 4 ;
2022-02-17 01:17:49 +03:00
check_one_size_helper ( sizeof ( * obj ) + ( 4 * sizeof ( * obj - > data ) ) ,
struct_size , obj , data , var + + ) ;
check_one_size_helper ( sizeof ( * obj ) + ( 5 * sizeof ( * obj - > data ) ) ,
struct_size , obj , data , var + + ) ;
check_one_size_helper ( sizeof ( * obj ) , struct_size , obj , data , 0 + unconst ) ;
check_one_size_helper ( sizeof ( * obj ) + sizeof ( * obj - > data ) ,
struct_size , obj , data , 1 + unconst ) ;
check_one_size_helper ( SIZE_MAX ,
struct_size , obj , data , - 3 + unconst ) ;
check_one_size_helper ( SIZE_MAX ,
struct_size , obj , data , SIZE_MAX - 3 + unconst ) ;
kunit_info ( test , " %d overflow size helper tests finished \n " , count ) ;
# undef check_one_size_helper
overflow: Implement size_t saturating arithmetic helpers
In order to perform more open-coded replacements of common allocation
size arithmetic, the kernel needs saturating (SIZE_MAX) helpers for
multiplication, addition, and subtraction. For example, it is common in
allocators, especially on realloc, to add to an existing size:
p = krealloc(map->patch,
sizeof(struct reg_sequence) * (map->patch_regs + num_regs),
GFP_KERNEL);
There is no existing saturating replacement for this calculation, and
just leaving the addition open coded inside array_size() could
potentially overflow as well. For example, an overflow in an expression
for a size_t argument might wrap to zero:
array_size(anything, something_at_size_max + 1) == 0
Introduce size_mul(), size_add(), and size_sub() helpers that
implicitly promote arguments to size_t and saturated calculations for
use in allocations. With these helpers it is also possible to redefine
array_size(), array3_size(), flex_array_size(), and struct_size() in
terms of the new helpers.
As with the check_*_overflow() helpers, the new helpers use __must_check,
though what is really desired is a way to make sure that assignment is
only to a size_t lvalue. Without this, it's still possible to introduce
overflow/underflow via type conversion (i.e. from size_t to int).
Enforcing this will currently need to be left to static analysis or
future use of -Wconversion.
Additionally update the overflow unit tests to force runtime evaluation
for the pathological cases.
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Gustavo A. R. Silva <gustavoars@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Keith Busch <kbusch@kernel.org>
Cc: Len Baker <len.baker@gmx.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
2021-09-19 01:17:53 +03:00
}
2022-02-17 01:17:49 +03:00
static struct kunit_case overflow_test_cases [ ] = {
KUNIT_CASE ( u8_overflow_test ) ,
KUNIT_CASE ( s8_overflow_test ) ,
KUNIT_CASE ( u16_overflow_test ) ,
KUNIT_CASE ( s16_overflow_test ) ,
KUNIT_CASE ( u32_overflow_test ) ,
KUNIT_CASE ( s32_overflow_test ) ,
2022-05-11 20:40:43 +03:00
/* Clang 13 and earlier generate unwanted libcalls on 32-bit. */
2022-02-17 01:17:49 +03:00
# if BITS_PER_LONG == 64
KUNIT_CASE ( u64_overflow_test ) ,
KUNIT_CASE ( s64_overflow_test ) ,
# endif
KUNIT_CASE ( overflow_shift_test ) ,
KUNIT_CASE ( overflow_allocation_test ) ,
KUNIT_CASE ( overflow_size_helpers_test ) ,
{ }
} ;
2018-05-08 01:36:28 +03:00
2022-02-17 01:17:49 +03:00
static struct kunit_suite overflow_test_suite = {
. name = " overflow " ,
. test_cases = overflow_test_cases ,
} ;
2018-05-08 01:36:28 +03:00
2022-02-17 01:17:49 +03:00
kunit_test_suite ( overflow_test_suite ) ;
2018-05-08 01:36:28 +03:00
MODULE_LICENSE ( " Dual MIT/GPL " ) ;