Skip to content

Commit 610b15c

Browse files
committed
overflow.h: Add allocation size calculation helpers
In preparation for replacing unchecked overflows for memory allocations, this creates helpers for the 3 most common calculations: array_size(a, b): 2-dimensional array array3_size(a, b, c): 3-dimensional array struct_size(ptr, member, n): struct followed by n-many trailing members Each of these return SIZE_MAX on overflow instead of wrapping around. (Additionally renames a variable named "array_size" to avoid future collision.) Co-developed-by: Matthew Wilcox <[email protected]> Signed-off-by: Kees Cook <[email protected]>
1 parent 8fee81a commit 610b15c

File tree

2 files changed

+78
-5
lines changed

2 files changed

+78
-5
lines changed

drivers/md/dm-table.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -548,23 +548,23 @@ static int adjoin(struct dm_table *table, struct dm_target *ti)
548548
* On the other hand, dm-switch needs to process bulk data using messages and
549549
* excessive use of GFP_NOIO could cause trouble.
550550
*/
551-
static char **realloc_argv(unsigned *array_size, char **old_argv)
551+
static char **realloc_argv(unsigned *size, char **old_argv)
552552
{
553553
char **argv;
554554
unsigned new_size;
555555
gfp_t gfp;
556556

557-
if (*array_size) {
558-
new_size = *array_size * 2;
557+
if (*size) {
558+
new_size = *size * 2;
559559
gfp = GFP_KERNEL;
560560
} else {
561561
new_size = 8;
562562
gfp = GFP_NOIO;
563563
}
564564
argv = kmalloc(new_size * sizeof(*argv), gfp);
565565
if (argv) {
566-
memcpy(argv, old_argv, *array_size * sizeof(*argv));
567-
*array_size = new_size;
566+
memcpy(argv, old_argv, *size * sizeof(*argv));
567+
*size = new_size;
568568
}
569569

570570
kfree(old_argv);

include/linux/overflow.h

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,4 +202,77 @@
202202

203203
#endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */
204204

205+
/**
206+
* array_size() - Calculate size of 2-dimensional array.
207+
*
208+
* @a: dimension one
209+
* @b: dimension two
210+
*
211+
* Calculates size of 2-dimensional array: @a * @b.
212+
*
213+
* Returns: number of bytes needed to represent the array or SIZE_MAX on
214+
* overflow.
215+
*/
216+
static inline __must_check size_t array_size(size_t a, size_t b)
217+
{
218+
size_t bytes;
219+
220+
if (check_mul_overflow(a, b, &bytes))
221+
return SIZE_MAX;
222+
223+
return bytes;
224+
}
225+
226+
/**
227+
* array3_size() - Calculate size of 3-dimensional array.
228+
*
229+
* @a: dimension one
230+
* @b: dimension two
231+
* @c: dimension three
232+
*
233+
* Calculates size of 3-dimensional array: @a * @b * @c.
234+
*
235+
* Returns: number of bytes needed to represent the array or SIZE_MAX on
236+
* overflow.
237+
*/
238+
static inline __must_check size_t array3_size(size_t a, size_t b, size_t c)
239+
{
240+
size_t bytes;
241+
242+
if (check_mul_overflow(a, b, &bytes))
243+
return SIZE_MAX;
244+
if (check_mul_overflow(bytes, c, &bytes))
245+
return SIZE_MAX;
246+
247+
return bytes;
248+
}
249+
250+
static inline __must_check size_t __ab_c_size(size_t n, size_t size, size_t c)
251+
{
252+
size_t bytes;
253+
254+
if (check_mul_overflow(n, size, &bytes))
255+
return SIZE_MAX;
256+
if (check_add_overflow(bytes, c, &bytes))
257+
return SIZE_MAX;
258+
259+
return bytes;
260+
}
261+
262+
/**
263+
* struct_size() - Calculate size of structure with trailing array.
264+
* @p: Pointer to the structure.
265+
* @member: Name of the array member.
266+
* @n: Number of elements in the array.
267+
*
268+
* Calculates size of memory needed for structure @p followed by an
269+
* array of @n @member elements.
270+
*
271+
* Return: number of bytes needed or SIZE_MAX on overflow.
272+
*/
273+
#define struct_size(p, member, n) \
274+
__ab_c_size(n, \
275+
sizeof(*(p)->member) + __must_be_array((p)->member),\
276+
sizeof(*(p)))
277+
205278
#endif /* __LINUX_OVERFLOW_H */

0 commit comments

Comments
 (0)