Skip to content

Commit e1be43d

Browse files
committed
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>
1 parent 8e7c8ca commit e1be43d

3 files changed

Lines changed: 184 additions & 44 deletions

File tree

Documentation/process/deprecated.rst

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ Instead, the 2-factor form of the allocator should be used::
7171

7272
foo = kmalloc_array(count, size, GFP_KERNEL);
7373

74+
Specifically, kmalloc() can be replaced with kmalloc_array(), and
75+
kzalloc() can be replaced with kcalloc().
76+
7477
If no 2-factor form is available, the saturate-on-overflow helpers should
7578
be used::
7679

@@ -91,9 +94,20 @@ Instead, use the helper::
9194
array usage and switch to a `flexible array member
9295
<#zero-length-and-one-element-arrays>`_ instead.
9396

94-
See array_size(), array3_size(), and struct_size(),
95-
for more details as well as the related check_add_overflow() and
96-
check_mul_overflow() family of functions.
97+
For other calculations, please compose the use of the size_mul(),
98+
size_add(), and size_sub() helpers. For example, in the case of::
99+
100+
foo = krealloc(current_size + chunk_size * (count - 3), GFP_KERNEL);
101+
102+
Instead, use the helpers::
103+
104+
foo = krealloc(size_add(current_size,
105+
size_mul(chunk_size,
106+
size_sub(count, 3))), GFP_KERNEL);
107+
108+
For more details, also see array3_size() and flex_array_size(),
109+
as well as the related check_mul_overflow(), check_add_overflow(),
110+
check_sub_overflow(), and check_shl_overflow() family of functions.
97111

98112
simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
99113
----------------------------------------------------------------------

include/linux/overflow.h

Lines changed: 69 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -118,81 +118,94 @@ static inline bool __must_check __must_check_overflow(bool overflow)
118118
}))
119119

120120
/**
121-
* array_size() - Calculate size of 2-dimensional array.
122-
*
123-
* @a: dimension one
124-
* @b: dimension two
121+
* size_mul() - Calculate size_t multiplication with saturation at SIZE_MAX
125122
*
126-
* Calculates size of 2-dimensional array: @a * @b.
123+
* @factor1: first factor
124+
* @factor2: second factor
127125
*
128-
* Returns: number of bytes needed to represent the array or SIZE_MAX on
129-
* overflow.
126+
* Returns: calculate @factor1 * @factor2, both promoted to size_t,
127+
* with any overflow causing the return value to be SIZE_MAX. The
128+
* lvalue must be size_t to avoid implicit type conversion.
130129
*/
131-
static inline __must_check size_t array_size(size_t a, size_t b)
130+
static inline size_t __must_check size_mul(size_t factor1, size_t factor2)
132131
{
133132
size_t bytes;
134133

135-
if (check_mul_overflow(a, b, &bytes))
134+
if (check_mul_overflow(factor1, factor2, &bytes))
136135
return SIZE_MAX;
137136

138137
return bytes;
139138
}
140139

141140
/**
142-
* array3_size() - Calculate size of 3-dimensional array.
141+
* size_add() - Calculate size_t addition with saturation at SIZE_MAX
143142
*
144-
* @a: dimension one
145-
* @b: dimension two
146-
* @c: dimension three
147-
*
148-
* Calculates size of 3-dimensional array: @a * @b * @c.
143+
* @addend1: first addend
144+
* @addend2: second addend
149145
*
150-
* Returns: number of bytes needed to represent the array or SIZE_MAX on
151-
* overflow.
146+
* Returns: calculate @addend1 + @addend2, both promoted to size_t,
147+
* with any overflow causing the return value to be SIZE_MAX. The
148+
* lvalue must be size_t to avoid implicit type conversion.
152149
*/
153-
static inline __must_check size_t array3_size(size_t a, size_t b, size_t c)
150+
static inline size_t __must_check size_add(size_t addend1, size_t addend2)
154151
{
155152
size_t bytes;
156153

157-
if (check_mul_overflow(a, b, &bytes))
158-
return SIZE_MAX;
159-
if (check_mul_overflow(bytes, c, &bytes))
154+
if (check_add_overflow(addend1, addend2, &bytes))
160155
return SIZE_MAX;
161156

162157
return bytes;
163158
}
164159

165-
/*
166-
* Compute a*b+c, returning SIZE_MAX on overflow. Internal helper for
167-
* struct_size() below.
160+
/**
161+
* size_sub() - Calculate size_t subtraction with saturation at SIZE_MAX
162+
*
163+
* @minuend: value to subtract from
164+
* @subtrahend: value to subtract from @minuend
165+
*
166+
* Returns: calculate @minuend - @subtrahend, both promoted to size_t,
167+
* with any overflow causing the return value to be SIZE_MAX. For
168+
* composition with the size_add() and size_mul() helpers, neither
169+
* argument may be SIZE_MAX (or the result with be forced to SIZE_MAX).
170+
* The lvalue must be size_t to avoid implicit type conversion.
168171
*/
169-
static inline __must_check size_t __ab_c_size(size_t a, size_t b, size_t c)
172+
static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend)
170173
{
171174
size_t bytes;
172175

173-
if (check_mul_overflow(a, b, &bytes))
174-
return SIZE_MAX;
175-
if (check_add_overflow(bytes, c, &bytes))
176+
if (minuend == SIZE_MAX || subtrahend == SIZE_MAX ||
177+
check_sub_overflow(minuend, subtrahend, &bytes))
176178
return SIZE_MAX;
177179

178180
return bytes;
179181
}
180182

181183
/**
182-
* struct_size() - Calculate size of structure with trailing array.
183-
* @p: Pointer to the structure.
184-
* @member: Name of the array member.
185-
* @count: Number of elements in the array.
184+
* array_size() - Calculate size of 2-dimensional array.
186185
*
187-
* Calculates size of memory needed for structure @p followed by an
188-
* array of @count number of @member elements.
186+
* @a: dimension one
187+
* @b: dimension two
189188
*
190-
* Return: number of bytes needed or SIZE_MAX on overflow.
189+
* Calculates size of 2-dimensional array: @a * @b.
190+
*
191+
* Returns: number of bytes needed to represent the array or SIZE_MAX on
192+
* overflow.
191193
*/
192-
#define struct_size(p, member, count) \
193-
__ab_c_size(count, \
194-
sizeof(*(p)->member) + __must_be_array((p)->member),\
195-
sizeof(*(p)))
194+
#define array_size(a, b) size_mul(a, b)
195+
196+
/**
197+
* array3_size() - Calculate size of 3-dimensional array.
198+
*
199+
* @a: dimension one
200+
* @b: dimension two
201+
* @c: dimension three
202+
*
203+
* Calculates size of 3-dimensional array: @a * @b * @c.
204+
*
205+
* Returns: number of bytes needed to represent the array or SIZE_MAX on
206+
* overflow.
207+
*/
208+
#define array3_size(a, b, c) size_mul(size_mul(a, b), c)
196209

197210
/**
198211
* flex_array_size() - Calculate size of a flexible array member
@@ -208,7 +221,22 @@ static inline __must_check size_t __ab_c_size(size_t a, size_t b, size_t c)
208221
* Return: number of bytes needed or SIZE_MAX on overflow.
209222
*/
210223
#define flex_array_size(p, member, count) \
211-
array_size(count, \
212-
sizeof(*(p)->member) + __must_be_array((p)->member))
224+
size_mul(count, \
225+
sizeof(*(p)->member) + __must_be_array((p)->member))
226+
227+
/**
228+
* struct_size() - Calculate size of structure with trailing flexible array.
229+
*
230+
* @p: Pointer to the structure.
231+
* @member: Name of the array member.
232+
* @count: Number of elements in the array.
233+
*
234+
* Calculates size of memory needed for structure @p followed by an
235+
* array of @count number of @member elements.
236+
*
237+
* Return: number of bytes needed or SIZE_MAX on overflow.
238+
*/
239+
#define struct_size(p, member, count) \
240+
size_add(sizeof(*(p)), flex_array_size(p, member, count))
213241

214242
#endif /* __LINUX_OVERFLOW_H */

lib/test_overflow.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,12 +594,110 @@ static int __init test_overflow_allocation(void)
594594
return err;
595595
}
596596

597+
struct __test_flex_array {
598+
unsigned long flags;
599+
size_t count;
600+
unsigned long data[];
601+
};
602+
603+
static int __init test_overflow_size_helpers(void)
604+
{
605+
struct __test_flex_array *obj;
606+
int count = 0;
607+
int err = 0;
608+
int var;
609+
610+
#define check_one_size_helper(expected, func, args...) ({ \
611+
bool __failure = false; \
612+
size_t _r; \
613+
\
614+
_r = func(args); \
615+
if (_r != (expected)) { \
616+
pr_warn("expected " #func "(" #args ") " \
617+
"to return %zu but got %zu instead\n", \
618+
(size_t)(expected), _r); \
619+
__failure = true; \
620+
} \
621+
count++; \
622+
__failure; \
623+
})
624+
625+
var = 4;
626+
err |= check_one_size_helper(20, size_mul, var++, 5);
627+
err |= check_one_size_helper(20, size_mul, 4, var++);
628+
err |= check_one_size_helper(0, size_mul, 0, 3);
629+
err |= check_one_size_helper(0, size_mul, 3, 0);
630+
err |= check_one_size_helper(6, size_mul, 2, 3);
631+
err |= check_one_size_helper(SIZE_MAX, size_mul, SIZE_MAX, 1);
632+
err |= check_one_size_helper(SIZE_MAX, size_mul, SIZE_MAX, 3);
633+
err |= check_one_size_helper(SIZE_MAX, size_mul, SIZE_MAX, -3);
634+
635+
var = 4;
636+
err |= check_one_size_helper(9, size_add, var++, 5);
637+
err |= check_one_size_helper(9, size_add, 4, var++);
638+
err |= check_one_size_helper(9, size_add, 9, 0);
639+
err |= check_one_size_helper(9, size_add, 0, 9);
640+
err |= check_one_size_helper(5, size_add, 2, 3);
641+
err |= check_one_size_helper(SIZE_MAX, size_add, SIZE_MAX, 1);
642+
err |= check_one_size_helper(SIZE_MAX, size_add, SIZE_MAX, 3);
643+
err |= check_one_size_helper(SIZE_MAX, size_add, SIZE_MAX, -3);
644+
645+
var = 4;
646+
err |= check_one_size_helper(1, size_sub, var--, 3);
647+
err |= check_one_size_helper(1, size_sub, 4, var--);
648+
err |= check_one_size_helper(1, size_sub, 3, 2);
649+
err |= check_one_size_helper(9, size_sub, 9, 0);
650+
err |= check_one_size_helper(SIZE_MAX, size_sub, 9, -3);
651+
err |= check_one_size_helper(SIZE_MAX, size_sub, 0, 9);
652+
err |= check_one_size_helper(SIZE_MAX, size_sub, 2, 3);
653+
err |= check_one_size_helper(SIZE_MAX, size_sub, SIZE_MAX, 0);
654+
err |= check_one_size_helper(SIZE_MAX, size_sub, SIZE_MAX, 10);
655+
err |= check_one_size_helper(SIZE_MAX, size_sub, 0, SIZE_MAX);
656+
err |= check_one_size_helper(SIZE_MAX, size_sub, 14, SIZE_MAX);
657+
err |= check_one_size_helper(SIZE_MAX - 2, size_sub, SIZE_MAX - 1, 1);
658+
err |= check_one_size_helper(SIZE_MAX - 4, size_sub, SIZE_MAX - 1, 3);
659+
err |= check_one_size_helper(1, size_sub, SIZE_MAX - 1, -3);
660+
661+
var = 4;
662+
err |= check_one_size_helper(4 * sizeof(*obj->data),
663+
flex_array_size, obj, data, var++);
664+
err |= check_one_size_helper(5 * sizeof(*obj->data),
665+
flex_array_size, obj, data, var++);
666+
err |= check_one_size_helper(0, flex_array_size, obj, data, 0);
667+
err |= check_one_size_helper(sizeof(*obj->data),
668+
flex_array_size, obj, data, 1);
669+
err |= check_one_size_helper(7 * sizeof(*obj->data),
670+
flex_array_size, obj, data, 7);
671+
err |= check_one_size_helper(SIZE_MAX,
672+
flex_array_size, obj, data, -1);
673+
err |= check_one_size_helper(SIZE_MAX,
674+
flex_array_size, obj, data, SIZE_MAX - 4);
675+
676+
var = 4;
677+
err |= check_one_size_helper(sizeof(*obj) + (4 * sizeof(*obj->data)),
678+
struct_size, obj, data, var++);
679+
err |= check_one_size_helper(sizeof(*obj) + (5 * sizeof(*obj->data)),
680+
struct_size, obj, data, var++);
681+
err |= check_one_size_helper(sizeof(*obj), struct_size, obj, data, 0);
682+
err |= check_one_size_helper(sizeof(*obj) + sizeof(*obj->data),
683+
struct_size, obj, data, 1);
684+
err |= check_one_size_helper(SIZE_MAX,
685+
struct_size, obj, data, -3);
686+
err |= check_one_size_helper(SIZE_MAX,
687+
struct_size, obj, data, SIZE_MAX - 3);
688+
689+
pr_info("%d overflow size helper tests finished\n", count);
690+
691+
return err;
692+
}
693+
597694
static int __init test_module_init(void)
598695
{
599696
int err = 0;
600697

601698
err |= test_overflow_calculation();
602699
err |= test_overflow_shift();
700+
err |= test_overflow_size_helpers();
603701
err |= test_overflow_allocation();
604702

605703
if (err) {

0 commit comments

Comments
 (0)