Re: [RFC PATCH] overflow: Add DECLARE_SIZED_FLEX() helper family
Jesse Taube <[email protected]> Tue, 21 Jul 2026 15:39:28 -0400
| Newsgroups | org.kernel.vger.linux-hardening,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <CADRr4bfDcJX7o6eVrrEG-wSX=Uivam6gOvrnUuRF+u+mEsmwQA@mail.gmail.com> |
On Fri, Jul 17, 2026 at 4:19 PM Gustavo A. R. Silva <[email protected]> wrote: > > Hi! > > On 7/17/26 10:17, Jesse Taube wrote: > > On Wed, Jul 15, 2026 at 12:12 PM Kees Cook <[email protected]> wrote: > >> > >> On Tue, Jul 14, 2026 at 11:18:18AM -0400, Jesse Taube wrote: > >>> Add new DECLARE_SIZED_FLEX() helper to set the default size of a > >>> flexible-array member. The code is identical to the declaration in > >>> __DEFINE_FLEX() which has also been changed to use DECLARE_SIZED_FLEX(). > >>> > >>> Add DECLARE_COUNTED_FLEX_ARRAY() helper which is a variant of > >>> DECLARE_FLEX_ARRAY() with a counted-by attribute. > >>> > >>> Also add default sized variants of > >>> DECLARE_FLEX_ARRAY(), DECLARE_SIZED_FLEX(), and > >>> DECLARE_COUNTED_FLEX_ARRAY(), DECLARE_COUNTED_SIZED_FLEX(). > >> > >> Where do you want to use these new helpers? > >> > >>> Signed-off-by: Jesse Taube <[email protected]> > >>> --- > >>> include/linux/overflow.h | 58 +++++++++++++++++++++++++++++++++++++--- > >>> 1 file changed, 54 insertions(+), 4 deletions(-) > >>> > >>> diff --git a/include/linux/overflow.h b/include/linux/overflow.h > >>> index a8cb6319b4fb..a3384cae49e5 100644 > >>> --- a/include/linux/overflow.h > >>> +++ b/include/linux/overflow.h > >>> @@ -464,6 +464,59 @@ static __always_inline size_t __must_check size_sub(size_t minuend, size_t subtr > >>> */ > >>> #define struct_offset(p, member) (offsetof(typeof(*(p)), member)) > >>> > >>> +/** > >>> + * __DECLARE_SIZED_FLEX() - helper macro for DECLARE_SIZED_FLEX() family. > >>> + * Allows for easily declaring a structure with a trailing flexible array member > >>> + * to have a specific size. > >>> + * > >>> + * @obj: object to be given a specific size > >>> + * @name: Name of the array member. > >>> + * @count: Number of elements in the array; must be compile-time const. > >>> + */ > >>> +#define __DECLARE_SIZED_FLEX(obj, name, count) \ > >>> + _Static_assert(__builtin_constant_p(count), \ > >>> + "default sized flex array members require compile-time const count"); \ > >>> + union { \ > >>> + u8 bytes[struct_size_t(obj, name, count)]; \ > >>> + obj; \ > >>> + } > >>> + > >>> +/** > >>> + * DECLARE_COUNTED_FLEX_ARRAY() - Declare a counted flexible array > >>> + * > >>> + * @type: Type name. > >>> + * @name: Name of the array member. > >>> + * @counter: Name of the __counted_by member. > >>> + */ > >>> +#define DECLARE_COUNTED_FLEX_ARRAY(type, name, counter)\ > >>> + struct { \ > >>> + size_t counter; \ > >>> + type name[] __counted_by(counter); \ > >>> + } > >>> + > >>> +/** > >>> + * DECLARE_SIZED_FLEX() - Declare a structure with a trailing flexible array > >>> + * member with a default size. > >>> + * > >>> + * @type: Type name. > >>> + * @name: Name of the array member. > >>> + * @count: Number of elements in the array; must be compile-time const. > >>> + */ > >>> +#define DECLARE_SIZED_FLEX(type, name, count) \ > >>> + __DECLARE_SIZED_FLEX(type name[], name, count) > >>> + > >>> +/** > >>> + * DECLARE_COUNTED_SIZED_FLEX() - Declare a structure with a trailing flexible > >>> + * array member counted by count, with a default size. > >>> + * > >>> + * @type: Type name. > >>> + * @name: Name of the array member. > >>> + * @counter: Name of the __counted_by member. > >>> + * @count: Number of elements in the array; must be compile-time const. > >>> + */ > >>> +#define DECLARE_COUNTED_SIZED_FLEX(type, name, counter, count) \ > >>> + __DECLARE_SIZED_FLEX(DECLARE_COUNTED_FLEX_ARRAY(type, name, counter), name, count) > >> > >> I ask about where these will be used because one of the things I want to > >> keep tied together is the "counter" and "count", which usually means the > >> declaration should be combined with an initializer in some way so that > >> the counter gets assigned, as DEFINE_FLEX() ultimately does. > >> > >> I'm worried that extracting the internal construction of __DEFINE_FLEX > >> means we may run the risk of increasing the risk of losing that tie. > > > > We can add a comment to make sure to set count, or use DEFINE_FLEX > > to allocate it. Im not sure if there is a way for this to be a compile time > > error though. > > > >> So, I'd love to understand how you want to use this, as that would help > >> my understanding and potentially shape the design so we can keep counter > >> and count strongly associated. > > > > Basically, I want to use `DECLARE_COUNTED_SIZED_FLEX` for a version of > > this patch that > > uses `__counted_by` > > https://lore.kernel.org/linux-scsi/[email protected]/ > > I have checked that it does always set the `counter` variable correctly. > > > > As for `DECLARE_COUNTED_FLEX_ARRAY` there is already `DECLARE_FLEX_ARRAY` and > > the counted variant is already used in a few places. A good example is > > `struct max77759_maxq_response` which subsiqently gets allocated with > > `DEFINE_FLEX` > > https://elixir.bootlin.com/linux/v7.2-rc1/source/include/linux/mfd/max77759.h#L253 > > > > I assume you are ok with adding `__DECLARE_SIZED_FLEX` and > > `DECLARE_SIZED_FLEX` as > > they are usefull in cases where keeping structure offsets is > > important, similar to > > TRAILING_OVERLAP. An example of where `__DECLARE_SIZED_FLEX` could be used is: > > https://lore.kernel.org/all/[email protected]/ > > Please show us examples of how exactly you'd use the helpers you propose > for the cases you mentioned above. Sorry for the late reply. Here is an example of DECLARE_COUNTED_FLEX_ARRAY, I notice now that the macro should be passed the count variable's type and not have it as size_t. ```c +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -136,21 +136,12 @@ struct bmi_cmd { struct { __le32 patch_id; } rompatch_uninstall; - struct { - __le32 count; - __le32 patch_ids[]; /* length of @count */ - } rompatch_activate; - struct { - __le32 count; - __le32 patch_ids[]; /* length of @count */ - } rompatch_deactivate; + DECLARE_COUNTED_FLEX_ARRAY(__le32, patch_ids, count) rompatch_activate; + DECLARE_COUNTED_FLEX_ARRAY(__le32, patch_ids, count) rompatch_deactivate; struct { __le32 addr; } lz_start; - struct { - __le32 len; /* max BMI_MAX_DATA_SIZE */ - u8 payload[]; /* length of @len */ - } lz_data; + DECLARE_COUNTED_FLEX_ARRAY(u8, payload, len) lz_data; struct { u8 name[BMI_NVRAM_SEG_NAME_SZ]; } nvram_process; ``` Here is where i want to use DECLARE_COUNTED_SIZED_FLEX, it would fix the "memcpy: detected field-spanning write (size 60) of single field". It seems like the only two places where a structure like this occurs is in qla2xxx and qla4xxx https://lore.kernel.org/linux-scsi/[email protected]/ ```c diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 5593ad7fad27..7241cf6e6c7e 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -4912,10 +4912,7 @@ struct purex_item { void (*process_item)(struct scsi_qla_host *vha, struct purex_item *pkt); atomic_t in_use; - uint16_t size; - struct { - uint8_t iocb[64]; - } iocb; + DECLARE_COUNTED_SIZED_FLEX(uint8_t, iocb, size, 64); }; ``` Here is an example of DECLARE_SIZED_FLEX: ```c #define DEFUALT_SIZE 64 struct flex_array { int some_element; DECLARE_SIZED_FLEX(uint8_t, payload, DEFUALT_SIZE); }; struct struct_with_flex_array { int some_element; struct flex_array flex_array; }; int main() { struct struct_with_flex_array my_struct; struct flex_array *my_struct2; uint8_t big_payload[100] = {}; /* Size of struct_with_flex_array: 72*/ printf("Size of struct_with_flex_array: %zu\n", sizeof(my_struct)); /* kzalloc_flex would need the size to be (sizeof(big_payload) - DEFUALT_SIZE) */ my_struct2 = kzalloc(sizeof(*my_struct2) + sizeof(big_payload) - DEFUALT_SIZE, GFP_KERNEL); /* Size of allocated flex_array: 104 */ printf("Size of allocated flex_array: %zu\n", sizeof(*my_struct2) + sizeof(big_payload) - DEFUALT_SIZE); /* Avoids "memcpy: detected field-spanning write (size 100) of single field" */ memcpy(my_struct.flex_array.payload, big_payload, sizeof(big_payload)); return 0; } ``` Thanks, Jesse Taube > > Thanks > -Gustavo > > > > > Thanks, > > Jesse Taube > > > >> > >>> + > >>> /** > >>> * __DEFINE_FLEX() - helper macro for DEFINE_FLEX() family. > >>> * Enables caller macro to pass arbitrary trailing expressions > >>> @@ -477,10 +530,7 @@ static __always_inline size_t __must_check size_sub(size_t minuend, size_t subtr > >>> #define __DEFINE_FLEX(type, name, member, count, trailer...) \ > >>> _Static_assert(__builtin_constant_p(count), \ > >>> "onstack flex array members require compile-time const count"); \ > >>> - union { \ > >>> - u8 bytes[struct_size_t(type, member, count)]; \ > >>> - type obj; \ > >>> - } name##_u trailer; \ > >>> + __DECLARE_SIZED_FLEX(type obj, member, count) name##_u trailer; \ > >>> type *name = (type *)&name##_u > >> > >> -Kees > >> > >> -- > >> Kees Cook > >> > > >