From: Brooke Basile brookebasile@gmail.com
commit b1cd1b65afba95971fa457dfdb2c941c60d38c5b upstream.
size can potentially hold an overflowed value if its assigned expression is left unchecked, leading to a smaller than needed allocation when vla_group_size() is used by callers to allocate memory. To fix this, add a test for saturation before declaring variables and an overflow check to (n) * sizeof(type). If the expression results in overflow, vla_group_size() will return SIZE_MAX.
Reported-by: Ilja Van Sprundel ivansprundel@ioactive.com Suggested-by: Kees Cook keescook@chromium.org Signed-off-by: Brooke Basile brookebasile@gmail.com Acked-by: Felipe Balbi balbi@kernel.org Cc: stable stable@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/usb/gadget/u_f.h | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-)
--- a/drivers/usb/gadget/u_f.h +++ b/drivers/usb/gadget/u_f.h @@ -17,6 +17,7 @@ #define __U_F_H__
#include <linux/usb/gadget.h> +#include <linux/overflow.h>
/* Variable Length Array Macros **********************************************/ #define vla_group(groupname) size_t groupname##__next = 0 @@ -24,21 +25,36 @@
#define vla_item(groupname, type, name, n) \ size_t groupname##_##name##__offset = ({ \ - size_t align_mask = __alignof__(type) - 1; \ - size_t offset = (groupname##__next + align_mask) & ~align_mask;\ - size_t size = (n) * sizeof(type); \ - groupname##__next = offset + size; \ + size_t offset = 0; \ + if (groupname##__next != SIZE_MAX) { \ + size_t align_mask = __alignof__(type) - 1; \ + size_t offset = (groupname##__next + align_mask) \ + & ~align_mask; \ + size_t size = array_size(n, sizeof(type)); \ + if (check_add_overflow(offset, size, \ + &groupname##__next)) { \ + groupname##__next = SIZE_MAX; \ + offset = 0; \ + } \ + } \ offset; \ })
#define vla_item_with_sz(groupname, type, name, n) \ - size_t groupname##_##name##__sz = (n) * sizeof(type); \ - size_t groupname##_##name##__offset = ({ \ - size_t align_mask = __alignof__(type) - 1; \ - size_t offset = (groupname##__next + align_mask) & ~align_mask;\ - size_t size = groupname##_##name##__sz; \ - groupname##__next = offset + size; \ - offset; \ + size_t groupname##_##name##__sz = array_size(n, sizeof(type)); \ + size_t groupname##_##name##__offset = ({ \ + size_t offset = 0; \ + if (groupname##__next != SIZE_MAX) { \ + size_t align_mask = __alignof__(type) - 1; \ + size_t offset = (groupname##__next + align_mask) \ + & ~align_mask; \ + if (check_add_overflow(offset, groupname##_##name##__sz,\ + &groupname##__next)) { \ + groupname##__next = SIZE_MAX; \ + offset = 0; \ + } \ + } \ + offset; \ })
#define vla_ptr(ptr, groupname, name) \