diff options
author | Stewart Smith <stewart@linux.ibm.com> | 2018-12-17 16:56:06 +1100 |
---|---|---|
committer | Stewart Smith <stewart@linux.ibm.com> | 2019-02-13 17:04:51 +1100 |
commit | 3170270be92ad945600d25ced9352c39fc7f156a (patch) | |
tree | 0606f62a8d19a3bf092de5f0f9b5ef373d8bd2ef | |
parent | abd17b24a5aebe8435e44587c3efb513e2f1e8d1 (diff) | |
download | skiboot-3170270be92ad945600d25ced9352c39fc7f156a.zip skiboot-3170270be92ad945600d25ced9352c39fc7f156a.tar.gz skiboot-3170270be92ad945600d25ced9352c39fc7f156a.tar.bz2 |
firmware-versions: Add test case for parsing VERSION
Also make it possible to use with afl-lop/afl-fuzz just to help make
*sure* we're all good.
Additionally, if we hit a entry in VERSION that is larger than our
buffer size, we skip over it gracefully rather than overwriting the
stack. This is only a problem if VERSION isn't trusted, which as of
4b8cc05a94513816d43fb8bd6178896b430af08f it is verified as part of
Secure Boot.
CC: stable # v5.9+
Fixes: 9727fe384b8685270d344201f7e051475eea3a0b
[stewart: fix up include ordering for building on centos7]
Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
18 files changed, 364 insertions, 147 deletions
diff --git a/core/Makefile.inc b/core/Makefile.inc index 3bdfd09..3b43870 100644 --- a/core/Makefile.inc +++ b/core/Makefile.inc @@ -10,6 +10,7 @@ CORE_OBJS += console-log.o ipmi.o time-utils.o pel.o pool.o errorlog.o CORE_OBJS += timer.o i2c.o rtc.o flash.o sensor.o ipmi-opal.o CORE_OBJS += flash-subpartition.o bitmap.o buddy.o pci-quirk.o powercap.o psr.o CORE_OBJS += pci-dt-slot.o direct-controls.o cpufeatures.o +CORE_OBJS += flash-firmware-versions.o ifeq ($(SKIBOOT_GCOV),1) CORE_OBJS += gcov-profiling.o diff --git a/core/flash-firmware-versions.c b/core/flash-firmware-versions.c new file mode 100644 index 0000000..59294e4 --- /dev/null +++ b/core/flash-firmware-versions.c @@ -0,0 +1,173 @@ +/* Copyright 2013-2018 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <skiboot.h> +#include <device.h> +#include <opal.h> +#include <libstb/secureboot.h> +#include <libstb/trustedboot.h> + +/* ibm,firmware-versions support */ +static char *version_buf; +static size_t version_buf_size = 0x2000; + +static void __flash_dt_add_fw_version(struct dt_node *fw_version, char* data) +{ + static bool first = true; + char *prop; + int version_len, i; + int len = strlen(data); + const char *skiboot_version; + const char * version_str[] = {"open-power", "buildroot", "skiboot", + "hostboot-binaries", "hostboot", "linux", + "petitboot", "occ", "capp-ucode", "sbe", + "machine-xml", "hcode"}; + + if (first) { + first = false; + + /* Increment past "key-" */ + if (memcmp(data, "open-power", strlen("open-power")) == 0) + prop = data + strlen("open-power"); + else + prop = strchr(data, '-'); + if (!prop) { + prlog(PR_DEBUG, + "FLASH: Invalid fw version format (%s)\n", data); + return; + } + prop++; + + dt_add_property_string(fw_version, "version", prop); + return; + } + + /* + * PNOR version strings are not easily consumable. Split them into + * property, value. + * + * Example input from PNOR : + * "open-power-firestone-v1.8" + * "linux-4.4.6-openpower1-8420e0f" + * + * Desired output in device tree: + * open-power = "firestone-v1.8"; + * linux = "4.4.6-openpower1-8420e0f"; + */ + for(i = 0; i < ARRAY_SIZE(version_str); i++) + { + version_len = strlen(version_str[i]); + if (len < version_len) + continue; + + if (memcmp(data, version_str[i], version_len) != 0) + continue; + + /* Found a match, add property */ + if (dt_find_property(fw_version, version_str[i])) + continue; + + /* Increment past "key-" */ + prop = data + version_len + 1; + dt_add_property_string(fw_version, version_str[i], prop); + + /* Sanity check against what Skiboot thinks its version is. */ + if (strncmp(version_str[i], "skiboot", + strlen("skiboot")) == 0) { + /* + * If Skiboot was built with Buildroot its version may + * include a 'skiboot-' prefix; ignore it. + */ + if (strncmp(version, "skiboot-", + strlen("skiboot-")) == 0) + skiboot_version = version + strlen("skiboot-"); + else + skiboot_version = version; + if (strncmp(prop, skiboot_version, + strlen(skiboot_version)) != 0) + prlog(PR_WARNING, "WARNING! Skiboot version does not match VERSION partition!\n"); + } + } +} + +void flash_dt_add_fw_version(void) +{ + uint8_t version_data[80]; + int rc; + int numbytes = 0, i = 0; + struct dt_node *fw_version; + + if (version_buf == NULL) + return; + + rc = wait_for_resource_loaded(RESOURCE_ID_VERSION, RESOURCE_SUBID_NONE); + if (rc != OPAL_SUCCESS) { + prlog(PR_WARNING, "FLASH: Failed to load VERSION data\n"); + free(version_buf); + return; + } + + fw_version = dt_new(dt_root, "ibm,firmware-versions"); + assert(fw_version); + + if (stb_is_container(version_buf, version_buf_size)) + numbytes += SECURE_BOOT_HEADERS_SIZE; + for ( ; (numbytes < version_buf_size) && version_buf[numbytes]; numbytes++) { + if (version_buf[numbytes] == '\n') { + version_data[i] = '\0'; + __flash_dt_add_fw_version(fw_version, version_data); + memset(version_data, 0, sizeof(version_data)); + i = 0; + continue; + } else if (version_buf[numbytes] == '\t') { + continue; /* skip tabs */ + } + + version_data[i++] = version_buf[numbytes]; + if (i == sizeof(version_data)) { + prlog(PR_WARNING, "VERSION item >%lu chars, skipping\n", + sizeof(version_data)); + break; + } + } + + free(version_buf); +} + +void flash_fw_version_preload(void) +{ + int rc; + + if (proc_gen < proc_gen_p9) + return; + + prlog(PR_INFO, "FLASH: Loading VERSION section\n"); + + version_buf = malloc(version_buf_size); + if (!version_buf) { + prlog(PR_WARNING, "FLASH: Failed to allocate memory\n"); + return; + } + + rc = start_preload_resource(RESOURCE_ID_VERSION, RESOURCE_SUBID_NONE, + version_buf, &version_buf_size); + if (rc != OPAL_SUCCESS) { + prlog(PR_WARNING, + "FLASH: Failed to start loading VERSION data\n"); + free(version_buf); + version_buf = NULL; + } +} diff --git a/core/flash.c b/core/flash.c index 08d69ed..5fae0f3 100644 --- a/core/flash.c +++ b/core/flash.c @@ -49,10 +49,6 @@ static struct lock flash_lock; static struct flash *nvram_flash; static u32 nvram_offset, nvram_size; -/* ibm,firmware-versions support */ -static char *version_buf; -static size_t version_buf_size = 0x2000; - bool flash_reserve(void) { bool rc = false; @@ -165,149 +161,6 @@ out: return rc; } -static void __flash_dt_add_fw_version(struct dt_node *fw_version, char* data) -{ - static bool first = true; - char *prop; - int version_len, i; - int len = strlen(data); - const char *skiboot_version; - const char * version_str[] = {"open-power", "buildroot", "skiboot", - "hostboot-binaries", "hostboot", "linux", - "petitboot", "occ", "capp-ucode", "sbe", - "machine-xml", "hcode"}; - - if (first) { - first = false; - - /* Increment past "key-" */ - if (memcmp(data, "open-power", strlen("open-power")) == 0) - prop = data + strlen("open-power"); - else - prop = strchr(data, '-'); - if (!prop) { - prlog(PR_DEBUG, - "FLASH: Invalid fw version format (%s)\n", data); - return; - } - prop++; - - dt_add_property_string(fw_version, "version", prop); - return; - } - - /* - * PNOR version strings are not easily consumable. Split them into - * property, value. - * - * Example input from PNOR : - * "open-power-firestone-v1.8" - * "linux-4.4.6-openpower1-8420e0f" - * - * Desired output in device tree: - * open-power = "firestone-v1.8"; - * linux = "4.4.6-openpower1-8420e0f"; - */ - for(i = 0; i < ARRAY_SIZE(version_str); i++) - { - version_len = strlen(version_str[i]); - if (len < version_len) - continue; - - if (memcmp(data, version_str[i], version_len) != 0) - continue; - - /* Found a match, add property */ - if (dt_find_property(fw_version, version_str[i])) - continue; - - /* Increment past "key-" */ - prop = data + version_len + 1; - dt_add_property_string(fw_version, version_str[i], prop); - - /* Sanity check against what Skiboot thinks its version is. */ - if (strncmp(version_str[i], "skiboot", - strlen("skiboot")) == 0) { - /* - * If Skiboot was built with Buildroot its version may - * include a 'skiboot-' prefix; ignore it. - */ - if (strncmp(version, "skiboot-", - strlen("skiboot-")) == 0) - skiboot_version = version + strlen("skiboot-"); - else - skiboot_version = version; - if (strncmp(prop, skiboot_version, - strlen(skiboot_version)) != 0) - prlog(PR_WARNING, "WARNING! Skiboot version does not match VERSION partition!\n"); - } - } -} - -void flash_dt_add_fw_version(void) -{ - uint8_t version_data[80]; - int rc; - int numbytes = 0, i = 0; - struct dt_node *fw_version; - - if (version_buf == NULL) - return; - - rc = wait_for_resource_loaded(RESOURCE_ID_VERSION, RESOURCE_SUBID_NONE); - if (rc != OPAL_SUCCESS) { - prlog(PR_WARNING, "FLASH: Failed to load VERSION data\n"); - free(version_buf); - return; - } - - fw_version = dt_new(dt_root, "ibm,firmware-versions"); - assert(fw_version); - - if (stb_is_container(version_buf, version_buf_size)) - numbytes += SECURE_BOOT_HEADERS_SIZE; - for ( ; (numbytes < version_buf_size) && version_buf[numbytes]; numbytes++) { - if (version_buf[numbytes] == '\n') { - version_data[i] = '\0'; - __flash_dt_add_fw_version(fw_version, version_data); - memset(version_data, 0, sizeof(version_data)); - i = 0; - continue; - } else if (version_buf[numbytes] == '\t') { - continue; /* skip tabs */ - } - - version_data[i++] = version_buf[numbytes]; - } - - free(version_buf); -} - -void flash_fw_version_preload(void) -{ - int rc; - - if (proc_gen < proc_gen_p9) - return; - - prlog(PR_INFO, "FLASH: Loading VERSION section\n"); - - version_buf = malloc(version_buf_size); - if (!version_buf) { - prlog(PR_WARNING, "FLASH: Failed to allocate memory\n"); - return; - } - - rc = start_preload_resource(RESOURCE_ID_VERSION, RESOURCE_SUBID_NONE, - version_buf, &version_buf_size); - if (rc != OPAL_SUCCESS) { - prlog(PR_WARNING, - "FLASH: Failed to start loading VERSION data\n"); - free(version_buf); - version_buf = NULL; - } -} - static int flash_nvram_probe(struct flash *flash, struct ffs_handle *ffs) { uint32_t start, size, part; diff --git a/core/test/Makefile.check b/core/test/Makefile.check index a5226a8..0fb585e 100644 --- a/core/test/Makefile.check +++ b/core/test/Makefile.check @@ -3,6 +3,7 @@ CORE_TEST := \ core/test/run-bitmap \ core/test/run-device \ core/test/run-flash-subpartition \ + core/test/run-flash-firmware-versions \ core/test/run-mem_region \ core/test/run-malloc \ core/test/run-malloc-speed \ @@ -72,6 +73,23 @@ $(CORE_TEST:%=%-gcov): %-gcov : %.c % $(CORE_TEST_NOSTUB:%=%-gcov) : %-gcov : %.c % $(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) $(HOSTGCOVCFLAGS) -I include -I . -I libfdt -lgcov -o $@ $< , $<) +core/test/run-flash-firmware-versions-gcov-run: core/test/run-flash-firmware-versions-inputs-gcov-run + +core/test/run-flash-firmware-versions-inputs-gcov-run: core/test/run-flash-firmware-versions-gcov + $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-0 > /dev/null, $< version-0) + $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-1 > /dev/null, $< version-1) + $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-2 > /dev/null, $< version-2) + $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-10 > /dev/null, $< version-10) + $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-11 > /dev/null, $< version-11) + $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-16 > /dev/null, $< version-16) + $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-26 > /dev/null, $< version-26) + $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-27 > /dev/null, $< version-27) + $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-29 > /dev/null, $< version-29) + $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-trunc > /dev/null, $< version-trunc) + $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-long > /dev/null, $< version-long) + $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-nodash > /dev/null, $< version-nodash) + + -include $(wildcard core/test/*.d) clean: core-test-clean diff --git a/core/test/firmware-versions-input/version-0 b/core/test/firmware-versions-input/version-0 Binary files differnew file mode 100644 index 0000000..2ab241a --- /dev/null +++ b/core/test/firmware-versions-input/version-0 diff --git a/core/test/firmware-versions-input/version-1 b/core/test/firmware-versions-input/version-1 Binary files differnew file mode 100644 index 0000000..746327a --- /dev/null +++ b/core/test/firmware-versions-input/version-1 diff --git a/core/test/firmware-versions-input/version-10 b/core/test/firmware-versions-input/version-10 Binary files differnew file mode 100644 index 0000000..013af60 --- /dev/null +++ b/core/test/firmware-versions-input/version-10 diff --git a/core/test/firmware-versions-input/version-11 b/core/test/firmware-versions-input/version-11 Binary files differnew file mode 100644 index 0000000..55e8353 --- /dev/null +++ b/core/test/firmware-versions-input/version-11 diff --git a/core/test/firmware-versions-input/version-16 b/core/test/firmware-versions-input/version-16 Binary files differnew file mode 100644 index 0000000..8906af4 --- /dev/null +++ b/core/test/firmware-versions-input/version-16 diff --git a/core/test/firmware-versions-input/version-2 b/core/test/firmware-versions-input/version-2 Binary files differnew file mode 100644 index 0000000..f012ffd --- /dev/null +++ b/core/test/firmware-versions-input/version-2 diff --git a/core/test/firmware-versions-input/version-26 b/core/test/firmware-versions-input/version-26 Binary files differnew file mode 100644 index 0000000..adfd5bb --- /dev/null +++ b/core/test/firmware-versions-input/version-26 diff --git a/core/test/firmware-versions-input/version-27 b/core/test/firmware-versions-input/version-27 Binary files differnew file mode 100644 index 0000000..d7ade98 --- /dev/null +++ b/core/test/firmware-versions-input/version-27 diff --git a/core/test/firmware-versions-input/version-29 b/core/test/firmware-versions-input/version-29 Binary files differnew file mode 100644 index 0000000..b1476a3 --- /dev/null +++ b/core/test/firmware-versions-input/version-29 diff --git a/core/test/firmware-versions-input/version-long b/core/test/firmware-versions-input/version-long new file mode 100644 index 0000000..f814fa6 --- /dev/null +++ b/core/test/firmware-versions-input/version-long @@ -0,0 +1,2 @@ +open-power-whatever-v2.0-10-g1cec21d-dirty + Well, I wonder what a short essay here will mean for parsing everything. I hope it is all okay, but we want to get greater than 80 chars. diff --git a/core/test/firmware-versions-input/version-nodash b/core/test/firmware-versions-input/version-nodash new file mode 100644 index 0000000..139aa93 --- /dev/null +++ b/core/test/firmware-versions-input/version-nodash @@ -0,0 +1,2 @@ +no_dashes_in_version + this_is_wrong diff --git a/core/test/firmware-versions-input/version-trunc b/core/test/firmware-versions-input/version-trunc new file mode 100644 index 0000000..c9c92a0 --- /dev/null +++ b/core/test/firmware-versions-input/version-trunc @@ -0,0 +1,2 @@ +open-power-SUPERMICRO-P8DTU-V2.00.GA2-20161028 + op diff --git a/core/test/run-flash-firmware-versions.c b/core/test/run-flash-firmware-versions.c new file mode 100644 index 0000000..924f3e9 --- /dev/null +++ b/core/test/run-flash-firmware-versions.c @@ -0,0 +1,165 @@ +/* Copyright 2018 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <malloc.h> +#include <stdint.h> + + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <assert.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> + + +#include <interrupts.h> +#include <bitutils.h> + +#include <compiler.h> + +/* + * Skiboot malloc stubs + * + * The actual prototypes for these are defined in mem_region-malloc.h, + * but that file also #defines malloc, and friends so we don't pull that in + * directly. + */ + +#define DEFAULT_ALIGN __alignof__(long) + +void *__memalign(size_t blocksize, size_t bytes, const char *location __unused); +void *__memalign(size_t blocksize, size_t bytes, const char *location __unused) +{ + return memalign(blocksize, bytes); +} + +void *__malloc(size_t bytes, const char *location); +void *__malloc(size_t bytes, const char *location) +{ + return __memalign(DEFAULT_ALIGN, bytes, location); +} + +void __free(void *p, const char *location __unused); +void __free(void *p, const char *location __unused) +{ + free(p); +} + +void *__realloc(void *ptr, size_t size, const char *location __unused); +void *__realloc(void *ptr, size_t size, const char *location __unused) +{ + return realloc(ptr, size); +} + +void *__zalloc(size_t bytes, const char *location); +void *__zalloc(size_t bytes, const char *location) +{ + void *p = __malloc(bytes, location); + + if (p) + memset(p, 0, bytes); + return p; +} + +#include <mem_region-malloc.h> + +#include <opal-api.h> + +#include "../../libfdt/fdt.c" +#include "../../libfdt/fdt_ro.c" +#include "../../libfdt/fdt_sw.c" +#include "../../libfdt/fdt_strerror.c" + +#include "../../core/device.c" + +#include "../../libstb/container-utils.h" +#include "../../libstb/container.h" +#include "../../libstb/container.c" + +#include "../flash-firmware-versions.c" +#include <assert.h> + +char __rodata_start[1], __rodata_end[1]; + +const char version[]="Hello world!"; + +enum proc_gen proc_gen = proc_gen_p7; + +static char *loaded_version_buf; +static size_t loaded_version_buf_size; + +#define min(x,y) ((x) < (y) ? x : y) + +int start_preload_resource(enum resource_id id, uint32_t subid, + void *buf, size_t *len) +{ + (void)id; + (void)subid; + (void)buf; + if (loaded_version_buf) { + *len = min(*len, loaded_version_buf_size); + memcpy(buf, loaded_version_buf, *len); + } else { + *len = 0; + } + + return 0; +} + +int wait_for_resource_loaded(enum resource_id id, uint32_t idx) +{ + (void)id; + (void)idx; + return 0; +} + +int main(int argc, char *argv[]) +{ + int fd; + struct stat ver_st; + int r; + + dt_root = dt_new_root(""); + + if (argc > 1) { + fd = open(argv[1], O_RDONLY); + + assert(fd > 0); + r = fstat(fd, &ver_st); + assert(r == 0); + + loaded_version_buf = mmap(NULL, ver_st.st_size, + PROT_READ, MAP_PRIVATE, fd, 0); + assert(loaded_version_buf != (char*)-1); + loaded_version_buf_size = ver_st.st_size; + } + + flash_fw_version_preload(); + + proc_gen = proc_gen_p9; + flash_fw_version_preload(); + flash_dt_add_fw_version(); + + return 0; +} + diff --git a/core/test/stubs.c b/core/test/stubs.c index 66252f8..3aa1b86 100644 --- a/core/test/stubs.c +++ b/core/test/stubs.c @@ -16,6 +16,7 @@ #include <stdlib.h> #include <stdio.h> #include <stdarg.h> +#include <string.h> #include <stdint.h> #include <compiler.h> |