Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 676057c7 authored by Kees Cook's avatar Kees Cook Committed by Greg Kroah-Hartman
Browse files

overflow.h: Add allocation size calculation helpers



commit 610b15c50e86eb1e4b77274fabcaea29ac72d6a8 upstream.

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: default avatarMatthew Wilcox <mawilcox@microsoft.com>
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 28d3ae31
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -510,14 +510,14 @@ static int adjoin(struct dm_table *table, struct dm_target *ti)
 * On the other hand, dm-switch needs to process bulk data using messages and
 * excessive use of GFP_NOIO could cause trouble.
 */
static char **realloc_argv(unsigned *array_size, char **old_argv)
static char **realloc_argv(unsigned *size, char **old_argv)
{
	char **argv;
	unsigned new_size;
	gfp_t gfp;

	if (*array_size) {
		new_size = *array_size * 2;
	if (*size) {
		new_size = *size * 2;
		gfp = GFP_KERNEL;
	} else {
		new_size = 8;
@@ -525,8 +525,8 @@ static char **realloc_argv(unsigned *array_size, char **old_argv)
	}
	argv = kmalloc(new_size * sizeof(*argv), gfp);
	if (argv) {
		memcpy(argv, old_argv, *array_size * sizeof(*argv));
		*array_size = new_size;
		memcpy(argv, old_argv, *size * sizeof(*argv));
		*size = new_size;
	}

	kfree(old_argv);
+73 −0
Original line number Diff line number Diff line
@@ -233,4 +233,77 @@
		(*_d >> _to_shift) != _a);				\
})

/**
 * array_size() - Calculate size of 2-dimensional array.
 *
 * @a: dimension one
 * @b: dimension two
 *
 * Calculates size of 2-dimensional array: @a * @b.
 *
 * Returns: number of bytes needed to represent the array or SIZE_MAX on
 * overflow.
 */
static inline __must_check size_t array_size(size_t a, size_t b)
{
	size_t bytes;

	if (check_mul_overflow(a, b, &bytes))
		return SIZE_MAX;

	return bytes;
}

/**
 * array3_size() - Calculate size of 3-dimensional array.
 *
 * @a: dimension one
 * @b: dimension two
 * @c: dimension three
 *
 * Calculates size of 3-dimensional array: @a * @b * @c.
 *
 * Returns: number of bytes needed to represent the array or SIZE_MAX on
 * overflow.
 */
static inline __must_check size_t array3_size(size_t a, size_t b, size_t c)
{
	size_t bytes;

	if (check_mul_overflow(a, b, &bytes))
		return SIZE_MAX;
	if (check_mul_overflow(bytes, c, &bytes))
		return SIZE_MAX;

	return bytes;
}

static inline __must_check size_t __ab_c_size(size_t n, size_t size, size_t c)
{
	size_t bytes;

	if (check_mul_overflow(n, size, &bytes))
		return SIZE_MAX;
	if (check_add_overflow(bytes, c, &bytes))
		return SIZE_MAX;

	return bytes;
}

/**
 * struct_size() - Calculate size of structure with trailing array.
 * @p: Pointer to the structure.
 * @member: Name of the array member.
 * @n: Number of elements in the array.
 *
 * Calculates size of memory needed for structure @p followed by an
 * array of @n @member elements.
 *
 * Return: number of bytes needed or SIZE_MAX on overflow.
 */
#define struct_size(p, member, n)					\
	__ab_c_size(n,							\
		    sizeof(*(p)->member) + __must_be_array((p)->member),\
		    sizeof(*(p)))

#endif /* __LINUX_OVERFLOW_H */