Message ID | 20220210004326.776574-1-keescook@chromium.org (mailing list archive) |
---|---|
State | Mainlined |
Commit | 1c1d836b96ba1bd773881c7f4784c77b94d58e25 |
Headers | show |
Series | overflow: Provide constant expression struct_size | expand |
On Wed, Feb 09, 2022 at 04:43:26PM -0800, Kees Cook wrote: > There have been cases where struct_size() (or flex_array_size()) needs > to be calculated for an initializer, which requires it be a constant > expression. This is possible when the "count" argument is a constant > expression, so provide this ability for the helpers. > > Signed-off-by: Kees Cook <keescook@chromium.org> Reviewed-by: Gustavo A. R. Silva <gustavoars@kernel.org> Tested-by: Gustavo A. R. Silva <gustavoars@kernel.org> Thanks! -- Gustavo > --- > include/linux/overflow.h | 10 +++++++--- > lib/test_overflow.c | 7 +++++++ > 2 files changed, 14 insertions(+), 3 deletions(-) > > diff --git a/include/linux/overflow.h b/include/linux/overflow.h > index 59d7228104d0..f1221d11f8e5 100644 > --- a/include/linux/overflow.h > +++ b/include/linux/overflow.h > @@ -4,6 +4,7 @@ > > #include <linux/compiler.h> > #include <linux/limits.h> > +#include <linux/const.h> > > /* > * We need to compute the minimum and maximum values representable in a given > @@ -221,8 +222,9 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend) > * Return: number of bytes needed or SIZE_MAX on overflow. > */ > #define flex_array_size(p, member, count) \ > - size_mul(count, \ > - sizeof(*(p)->member) + __must_be_array((p)->member)) > + __builtin_choose_expr(__is_constexpr(count), \ > + (count) * sizeof(*(p)->member) + __must_be_array((p)->member), \ > + size_mul(count, sizeof(*(p)->member) + __must_be_array((p)->member))) > > /** > * struct_size() - Calculate size of structure with trailing flexible array. > @@ -237,6 +239,8 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend) > * Return: number of bytes needed or SIZE_MAX on overflow. > */ > #define struct_size(p, member, count) \ > - size_add(sizeof(*(p)), flex_array_size(p, member, count)) > + __builtin_choose_expr(__is_constexpr(count), \ > + sizeof(*(p)) + flex_array_size(p, member, count), \ > + size_add(sizeof(*(p)), flex_array_size(p, member, count))) > > #endif /* __LINUX_OVERFLOW_H */ > diff --git a/lib/test_overflow.c b/lib/test_overflow.c > index 712fb2351c27..d488ffaf56be 100644 > --- a/lib/test_overflow.c > +++ b/lib/test_overflow.c > @@ -602,11 +602,18 @@ struct __test_flex_array { > > static int __init test_overflow_size_helpers(void) > { > + /* Make sure struct_size() can be used in a constant expression. */ > + u8 ce_array[struct_size((struct __test_flex_array *)0, data, 55)]; > struct __test_flex_array *obj; > int count = 0; > int err = 0; > int var; > > + /* Verify constant expression against runtime version. */ > + var = 55; > + OPTIMIZER_HIDE_VAR(var); > + err |= sizeof(ce_array) != struct_size(obj, data, var); > + > #define check_one_size_helper(expected, func, args...) ({ \ > bool __failure = false; \ > size_t _r; \ > -- > 2.30.2 >
diff --git a/include/linux/overflow.h b/include/linux/overflow.h index 59d7228104d0..f1221d11f8e5 100644 --- a/include/linux/overflow.h +++ b/include/linux/overflow.h @@ -4,6 +4,7 @@ #include <linux/compiler.h> #include <linux/limits.h> +#include <linux/const.h> /* * We need to compute the minimum and maximum values representable in a given @@ -221,8 +222,9 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend) * Return: number of bytes needed or SIZE_MAX on overflow. */ #define flex_array_size(p, member, count) \ - size_mul(count, \ - sizeof(*(p)->member) + __must_be_array((p)->member)) + __builtin_choose_expr(__is_constexpr(count), \ + (count) * sizeof(*(p)->member) + __must_be_array((p)->member), \ + size_mul(count, sizeof(*(p)->member) + __must_be_array((p)->member))) /** * struct_size() - Calculate size of structure with trailing flexible array. @@ -237,6 +239,8 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend) * Return: number of bytes needed or SIZE_MAX on overflow. */ #define struct_size(p, member, count) \ - size_add(sizeof(*(p)), flex_array_size(p, member, count)) + __builtin_choose_expr(__is_constexpr(count), \ + sizeof(*(p)) + flex_array_size(p, member, count), \ + size_add(sizeof(*(p)), flex_array_size(p, member, count))) #endif /* __LINUX_OVERFLOW_H */ diff --git a/lib/test_overflow.c b/lib/test_overflow.c index 712fb2351c27..d488ffaf56be 100644 --- a/lib/test_overflow.c +++ b/lib/test_overflow.c @@ -602,11 +602,18 @@ struct __test_flex_array { static int __init test_overflow_size_helpers(void) { + /* Make sure struct_size() can be used in a constant expression. */ + u8 ce_array[struct_size((struct __test_flex_array *)0, data, 55)]; struct __test_flex_array *obj; int count = 0; int err = 0; int var; + /* Verify constant expression against runtime version. */ + var = 55; + OPTIMIZER_HIDE_VAR(var); + err |= sizeof(ce_array) != struct_size(obj, data, var); + #define check_one_size_helper(expected, func, args...) ({ \ bool __failure = false; \ size_t _r; \
There have been cases where struct_size() (or flex_array_size()) needs to be calculated for an initializer, which requires it be a constant expression. This is possible when the "count" argument is a constant expression, so provide this ability for the helpers. Signed-off-by: Kees Cook <keescook@chromium.org> --- include/linux/overflow.h | 10 +++++++--- lib/test_overflow.c | 7 +++++++ 2 files changed, 14 insertions(+), 3 deletions(-)