firmware: coreboot: Check size of table entry and split memcpy
PATCH v2 1/1 firmware: coreboot: Check size of table entry and split memcpy
The memcpy() of the data following a coreboot_table_entry couldn't be evaluated by the compiler under CONFIG_FORTIFY_SOURCE. To make it easier to reason about, add an explicit flexible array member to struct coreboot_device so the entire entry can be copied at once. Additionally, validate the sizes before copying. Avoids this run-time false positive warning:
memcpy: detected field-spanning write (size 168) of single field "&device->entry" at drivers/firmware/google/coreboot_table.c:103 (size 8)
---
v2: move flex array to struct coreboot_device (julius)
v1: https://lore.kernel.org/lkml/[email protected]
--- drivers/firmware/google/coreboot_table.c | 9 +++++++-- drivers/firmware/google/coreboot_table.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-)
drivers/firmware/google/coreboot_table.c +7 -2
@@ -93,14 +93,19 @@ static int coreboot_table_populate(struct device *dev, void *ptr)for (i =0 ; i < header->table_entries; i++) { entry = ptr_entry; - device =kzalloc (sizeof (struct device ) + entry->size,GFP_KERNEL ); +if (entry->size <sizeof (*entry)) { +dev_warn (dev,"coreboot table entry too small!\n" ); +return -EINVAL ; + } + + device =kzalloc (sizeof (device->dev) + entry->size,GFP_KERNEL );if (!device)return -ENOMEM ; device->dev.parent = dev; device->dev.bus = &coreboot_bus_type; device->dev.release = coreboot_device_release; -memcpy (&device->entry, ptr_entry, entry->size); +memcpy (device->raw, entry, entry->size);switch (device->entry.tag) {case LB_TAG_CBMEM_ENTRY :
drivers/firmware/google/coreboot_table.h +1 -0
@@ -79,6 +79,7 @@ struct coreboot_device {struct lb_cbmem_ref cbmem_ref;struct lb_cbmem_entry cbmem_entry;struct lb_framebuffer framebuffer; +DECLARE_FLEX_ARRAY (u8, raw); }; };
Signature · 1 line
2.34.1
Quoted 10 lines · Kees Cook
The
memcpy()of the data following acoreboot_table_entrycouldn't be evaluated by the compiler underCONFIG_FORTIFY_SOURCE. To make it easier to reason about, add an explicit flexible array member to structcoreboot_deviceso the entire entry can be copied at once. Additionally, validate the sizes before copying. Avoids this run-time false positive warning:memcpy: detected field-spanning write (size 168) of single field "
&device->entry" atdrivers/firmware/google/coreboot_table.c:103(size 8)
Quoted 9 lines
Reported-by Paul Menzel <[email protected]>Cc Jack Rosenthal <[email protected]>Cc Guenter Roeck <[email protected]>Cc Julius Werner <[email protected]>Cc Brian Norris <[email protected]>Cc Stephen Boyd <[email protected]>Cc Greg Kroah-Hartman <[email protected]>Signed-off-by Kees Cook <[email protected]>
Quoted 49 lines
---
v2: move flex array to structcoreboot_device(julius)
v1: https://lore.kernel.org/lkml/[email protected]--- drivers/firmware/google/coreboot_table.c | 9 +++++++-- drivers/firmware/google/coreboot_table.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-)drivers/firmware/google/coreboot_table.c +7
-2@@ -93,14 +93,19 @@ static int coreboot_table_populate(struct device *dev, void *ptr)for (i =0 ; i < header->table_entries; i++) { entry = ptr_entry; - device =kzalloc (sizeof (struct device ) + entry->size,GFP_KERNEL ); +if (entry->size <sizeof (*entry)) { +dev_warn (dev,"coreboot table entry too small!\n" ); +return -EINVAL ; + } + + device =kzalloc (sizeof (device->dev) + entry->size,GFP_KERNEL );if (!device)return -ENOMEM ; device->dev.parent = dev; device->dev.bus = &coreboot_bus_type; device->dev.release = coreboot_device_release; -memcpy (&device->entry, ptr_entry, entry->size); +memcpy (device->raw, entry, entry->size);switch (device->entry.tag) {case LB_TAG_CBMEM_ENTRY :drivers/firmware/google/coreboot_table.h +1
-1@@ -79,6 +79,7 @@ struct coreboot_device {struct lb_cbmem_ref cbmem_ref;struct lb_cbmem_entry cbmem_entry;struct lb_framebuffer framebuffer; +DECLARE_FLEX_ARRAY (u8, raw); }; }; --2.34.1
drivers/firmware/google/coreboot_table.c static int coreboot_table_populate(struct device *dev, void *ptr) · line 108
Quoted 2 lines
drivers/firmware/google/coreboot_table.c +1
-1-memcpy (&device->entry, ptr_entry, entry->size); +memcpy (device->raw, entry, entry->size);
nit: It's a bit odd to change the source pointer from ptr_entry to entry here. Technically the static analyzer would be within its rights to give you a warning for that as well, because you're now "overrunning" the source struct instead of the destination one.
Quoted 9 lines · Julius Werner
Reviewed-by Julius Werner <[email protected]>drivers/firmware/google/coreboot_table.c static int coreboot_table_populate(struct device *dev, void *ptr) · line 108
Quoted 2 lines
drivers/firmware/google/coreboot_table.c +1
-1-memcpy (&device->entry, ptr_entry, entry->size); +memcpy (device->raw, entry, entry->size);nit: It's a bit odd to change the source pointer from
ptr_entryto entry here. Technically the static analyzer would be within its rights to give you a warning for that as well, because you're now "overrunning" the source struct instead of the destination one.
True. We've been focused on write overflows, but yeah, since the location of the flex array changed, I'll switch this back to ptr_entry.
Signature · 1 line
Kees Cook