exofs: Avoid VLA in structures
PATCH v2 1/1 exofs: Avoid VLA in structures
On the quest to remove all VLAs from the kernel[1] this adjusts several cases where allocation is made after an array of structures that points back into the allocation. The allocations are changed to perform explicit calculations instead of using a Variable Length Array in a structure. Additionally, this lets Clang compile this code now, since Clang does not support VLAIS[2].
[1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com
[2] https://lkml.kernel.org/r/CA+55aFy6h1c3_rP_bXFedsTXzwW+9Q9MfJaW7GUmMBrAp-fJ9A@mail.gmail.com
---
v2:
- use DRY for easier to read stripe updates (ndesaulniers)
- add const to unchanging variable (ndesaulniers)
- update references with message-id URLs
- add Reviewed-by
--- fs/exofs/ore.c | 84 +++++++++++++++++++++++++++++++---------------------- fs/exofs/ore_raid.c | 75 ++++++++++++++++++++++++++++++++++------------- fs/exofs/super.c | 23 +++++++-------- 3 files changed, 115 insertions(+), 67 deletions(-)
fs/exofs/ore.c +49 -35
@@ -146,68 +146,82 @@ int _ore_get_io_state(struct ore_layout *layout, struct ore_io_state **pios) {struct ore_io_state *ios; -struct page **pages; -struct osd_sg_entry *sgilist; +size_t size_ios, size_extra, size_total; +void *ios_extra; + +/* +* The desired layout looks like this, with the extra_allocation +* items pointed at from fields within ios or per_dev: +struct __alloc_all_io_state { struct ore_io_state ios; struct ore_per_dev_state per_dev[numdevs]; union { struct osd_sg_entry sglist[sgs_per_dev * numdevs]; struct page *pages[num_par_pages]; - }; - } *_aios; - -if (likely (sizeof (*_aios) <=PAGE_SIZE )) { - _aios =kzalloc (sizeof (*_aios),GFP_KERNEL ); -if (unlikely (!_aios)) { -ORE_DBGMSG ("Failed kzalloc bytes=%zd\n" , -sizeof (*_aios)); +} extra_allocation; +} whole_allocation; + +*/ + +/* This should never happen, so abort early if it ever does. */ +if (sgs_per_dev && num_par_pages) { +ORE_DBGMSG ("Tried to use both pages and sglist\n" ); + *pios =NULL ; +return -EINVAL ; + } + +if (numdevs > (INT_MAX -sizeof (*ios)) / +sizeof (struct ore_per_dev_state )) +return -ENOMEM ; + size_ios =sizeof (*ios) +sizeof (struct ore_per_dev_state ) * numdevs; + +if (sgs_per_dev * numdevs >INT_MAX /sizeof (struct osd_sg_entry )) +return -ENOMEM ; +if (num_par_pages >INT_MAX /sizeof (struct page *)) +return -ENOMEM ; + size_extra =max (sizeof (struct osd_sg_entry ) * (sgs_per_dev * numdevs), +sizeof (struct page *) * num_par_pages); + + size_total = size_ios + size_extra; + +if (likely (size_total <=PAGE_SIZE )) { + ios =kzalloc (size_total,GFP_KERNEL ); +if (unlikely (!ios)) { +ORE_DBGMSG ("Failed kzalloc bytes=%zd\n" , size_total); *pios =NULL ;return -ENOMEM ; } - pages = num_par_pages ? _aios->pages :NULL ; - sgilist = sgs_per_dev ? _aios->sglist :NULL ; - ios = &_aios->ios; + ios_extra = (char *)ios + size_ios; }else { -struct __alloc_small_io_state { -struct ore_io_state ios; -struct ore_per_dev_state per_dev[numdevs]; - } *_aio_small; -union __extra_part { -struct osd_sg_entry sglist[sgs_per_dev * numdevs]; -struct page *pages[num_par_pages]; - } *extra_part; - - _aio_small =kzalloc (sizeof (*_aio_small),GFP_KERNEL ); -if (unlikely (!_aio_small)) { + ios =kzalloc (size_ios,GFP_KERNEL ); +if (unlikely (!ios)) {ORE_DBGMSG ("Failed alloc first part bytes=%zd\n" , -sizeof (*_aio_small)); + size_ios); *pios =NULL ;return -ENOMEM ; } - extra_part =kzalloc (sizeof (*extra_part),GFP_KERNEL ); -if (unlikely (!extra_part)) { + ios_extra =kzalloc (size_extra,GFP_KERNEL ); +if (unlikely (!ios_extra)) {ORE_DBGMSG ("Failed alloc second part bytes=%zd\n" , -sizeof (*extra_part)); -kfree (_aio_small); + size_extra); +kfree (ios); *pios =NULL ;return -ENOMEM ; } - pages = num_par_pages ? extra_part->pages :NULL ; - sgilist = sgs_per_dev ? extra_part->sglist :NULL ;/* In this case the per_dev[0].sgilist holds the pointer to * be freed */ - ios = &_aio_small->ios; ios->extra_part_alloc = true; } -if (pages) { - ios->parity_pages = pages; +if (num_par_pages) { + ios->parity_pages = ios_extra; ios->max_par_pages = num_par_pages; } -if (sgilist) { +if (sgs_per_dev) { +struct osd_sg_entry *sgilist = ios_extra;unsigned d;for (d =0 ; d < numdevs; ++d) {
fs/exofs/ore_raid.c +55 -20
116 lines not on this page · raw message
fs/exofs/super.c +11 -12
@@ -549,27 +549,26 @@ static int exofs_devs_2_odi(struct exofs_dt_device_info *dt_dev,static int __alloc_dev_table (struct exofs_sb_info *sbi,unsigned numdevs,struct exofs_dev **peds) { -struct __alloc_ore_devs_and_exofs_devs { -/* Twice bigger table: See exofs_init_comps() and comment at -* exofs_read_lookup_dev_table() -*/ -struct ore_dev *oreds[numdevs *2 -1 ]; -struct exofs_dev eds[numdevs]; - } *aoded; +/* Twice bigger table: See exofs_init_comps() and comment at +* exofs_read_lookup_dev_table() +*/ +const size_t numores = numdevs *2 -1 ;struct exofs_dev *eds;unsigned i; - aoded =kzalloc (sizeof (*aoded),GFP_KERNEL ); -if (unlikely (!aoded)) { + sbi->oc.ods =kzalloc (numores *sizeof (struct ore_dev *) + + numdevs *sizeof (struct exofs_dev ),GFP_KERNEL ); +if (unlikely (!sbi->oc.ods)) {EXOFS_ERR ("ERROR: failed allocating Device array[%d]\n" , numdevs);return -ENOMEM ; } - sbi->oc.ods = aoded->oreds; - *peds = eds = aoded->eds; +/* Start of allocated struct exofs_dev entries */ + *peds = eds = (void *)sbi->oc.ods[numores]; +/* Initialize pointers into struct exofs_dev */ for (i =0 ; i < numdevs; ++i) - aoded->oreds[i] = &eds[i].ored; + sbi->oc.ods[i] = &eds[i].ored;return 0 ; }
Signature · 6 lines
2.7.4 -- Kees Cook Pixel Security