diff options
Diffstat (limited to 'drivers/firmware/google/coreboot_table.c')
| -rw-r--r-- | drivers/firmware/google/coreboot_table.c | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index 882db32e51be..e63933ff6747 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c @@ -14,6 +14,7 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/kernel.h> +#include <linux/device-id/coreboot.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> @@ -21,6 +22,16 @@ #include "coreboot_table.h" +/* Coreboot table header structure */ +struct coreboot_table_header { + char signature[4]; + u32 header_bytes; + u32 header_checksum; + u32 table_bytes; + u32 table_checksum; + u32 table_entries; +}; + #define CB_DEV(d) container_of(d, struct coreboot_device, dev) #define CB_DRV(d) container_of_const(d, struct coreboot_driver, drv) @@ -101,16 +112,20 @@ void coreboot_driver_unregister(struct coreboot_driver *driver) } EXPORT_SYMBOL(coreboot_driver_unregister); -static int coreboot_table_populate(struct device *dev, void *ptr) +static int coreboot_table_populate(struct device *dev, void *ptr, resource_size_t len) { int i, ret; void *ptr_entry; struct coreboot_device *device; struct coreboot_table_entry *entry; struct coreboot_table_header *header = ptr; + void *ptr_end; + ptr_end = ptr + len; ptr_entry = ptr + header->header_bytes; for (i = 0; i < header->table_entries; i++) { + if (ptr_entry + sizeof(*entry) > ptr_end) + return -EINVAL; entry = ptr_entry; if (entry->size < sizeof(*entry)) { @@ -118,6 +133,9 @@ static int coreboot_table_populate(struct device *dev, void *ptr) return -EINVAL; } + if (ptr_entry + entry->size > ptr_end) + return -EINVAL; + device = kzalloc(sizeof(device->dev) + entry->size, GFP_KERNEL); if (!device) return -ENOMEM; @@ -137,13 +155,13 @@ static int coreboot_table_populate(struct device *dev, void *ptr) break; } + ptr_entry += entry->size; + ret = device_register(&device->dev); if (ret) { + dev_warn(dev, "failed to register coreboot device: %d\n", ret); put_device(&device->dev); - return ret; } - - ptr_entry += entry->size; } return 0; @@ -183,7 +201,7 @@ static int coreboot_table_probe(struct platform_device *pdev) if (!ptr) return -ENOMEM; - ret = coreboot_table_populate(dev, ptr); + ret = coreboot_table_populate(dev, ptr, len); memunmap(ptr); @@ -251,7 +269,7 @@ static void __exit coreboot_table_driver_exit(void) bus_unregister(&coreboot_bus_type); } -module_init(coreboot_table_driver_init); +subsys_initcall(coreboot_table_driver_init); module_exit(coreboot_table_driver_exit); MODULE_AUTHOR("Google, Inc."); |
