Message ID | 20180801234042.6740-3-erichte@linux.ibm.com |
---|---|
State | RFC |
Headers | show |
Series | Initial Implementation of Secure Boot Key Management support | expand |
Context | Check | Description |
---|---|---|
snowpatch_ozlabs/apply_patch | success | master/apply_patch Successfully applied |
Eric Richter <erichte@linux.ibm.com> writes: > From: Claudio Carvalho <cclaudio@linux.ibm.com> > > The SECBOOT partition is used to store secure boot variables and variable > updates. A variable/update can store several data types, including a x509 > certificate, but for skiboot the variable/update data is a blob that can be > handled by the linux kernel via secure boot runtime services (added by > other patches in this series). It would be good to detail here why it's different to NVRAM and what the semantic differences are. > > This implements the SECBOOT API required to provide the aforementioned > runtime services. This implementation is based on the NVRAM API > implementation. What are things going to look like for FSP based systems? Are we going to get similar calls to the NVRAM ones? > NOTE: There are other ways to implement the SECBOOT API, for example > extending the current resource load framework (flash API). Issues: > (1) Looking at the NVRAM code, it seems that the flash API should be used > only for boot services. (2) The flash API spend some space with partition > and subpartition headers, but the SECBOOT space is very limited for the > purpose. (3) The flash API doesn't support partial writes to a partition or > subpartition. The SECBOOT API can also be implemented extending the NVRAM > API. The same platform hooks could be used if a new parameter is added to > determine the partition. The resource framework is only for boot time, yes. It's designed to only be used when OPAL has control, as it fundamentally does things asynchronously in a way that only works when skiboot has complete control. > CC: Jeremy Kerr <jk@ozlabs.org> > Signed-off-by: Claudio Carvalho <cclaudio@linux.ibm.com> > --- > core/flash.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > include/platform.h | 4 ++ > 2 files changed, 122 insertions(+) > > diff --git a/core/flash.c b/core/flash.c > index 8f00d85e..4e952cb0 100644 > --- a/core/flash.c > +++ b/core/flash.c > @@ -49,6 +49,10 @@ static struct lock flash_lock; > static struct flash *nvram_flash; > static u32 nvram_offset, nvram_size; > > +/* secboot-on-flash support */ > +static struct flash *secboot_flash; > +static u32 secboot_offset, secboot_size; > + > /* ibm,firmware-versions support */ > static char *version_buf; > static size_t version_buf_size = 0x2000; > @@ -76,6 +80,80 @@ void flash_release(void) > unlock(&flash_lock); > } > > +static int flash_secboot_info(uint32_t *total_size) > +{ > + int rc; > + > + lock(&flash_lock); > + if (!secboot_flash) { > + rc = OPAL_HARDWARE; > + } else if (secboot_flash->busy) { > + rc = OPAL_BUSY; > + } else { > + *total_size = secboot_size; > + rc = OPAL_SUCCESS; > + } > + unlock(&flash_lock); > + > + return rc; > +} > + > +static int flash_secboot_read(void *dst, uint32_t src, uint32_t len) > +{ > + int rc; > + > + if (!try_lock(&flash_lock)) > + return OPAL_BUSY; > + > + if (!secboot_flash) { > + rc = OPAL_HARDWARE; > + goto out; > + } > + > + if (secboot_flash->busy) { > + rc = OPAL_BUSY; > + goto out; > + } > + > + if ((src + len) > secboot_size) { > + prerror("FLASH_SECBOOT: read out of bound (0x%x,0x%x)\n", > + src, len); > + rc = OPAL_PARAMETER; > + goto out; > + } > + > + rc = blocklevel_read(secboot_flash->bl, secboot_offset + src, dst, len); > + > +out: > + unlock(&flash_lock); > + return rc; > +} > + > +static int flash_secboot_write(uint32_t dst, void *src, uint32_t len) > +{ > + int rc; > + > + if (!try_lock(&flash_lock)) > + return OPAL_BUSY; > + > + if (secboot_flash->busy) { > + rc = OPAL_BUSY; > + goto out; > + } > + > + if ((dst + len) > secboot_size) { > + prerror("FLASH_SECBOOT: write out of bound (0x%x,0x%x)\n", > + dst, len); > + rc = OPAL_PARAMETER; > + goto out; > + } > + rc = blocklevel_write(secboot_flash->bl, secboot_offset + dst, src, len); > + > +out: > + unlock(&flash_lock); > + return rc; > +} > + > static int flash_nvram_info(uint32_t *total_size) > { > int rc; > @@ -283,6 +361,45 @@ void flash_fw_version_preload(void) > } > } > > +static int flash_secboot_probe(struct flash *flash, struct ffs_handle *ffs) > +{ > + uint32_t start, size, part; > + bool ecc; > + int rc; > + > + prlog(PR_INFO, "FLASH: probing for SECBOOT\n"); PR_DEBUG or PR_TRACE, we probably don't need this printed to the console. > + > + rc = ffs_lookup_part(ffs, "SECBOOT", &part); > + if (rc) { > + prlog(PR_WARNING, "FLASH: no SECBOOT partition found\n"); > + return OPAL_HARDWARE; > + } > + > + rc = ffs_part_info(ffs, part, NULL, > + &start, &size, NULL, &ecc); > + if (rc) { > + /** > + * @fwts-label SECBOOTNoPartition > + * @fwts-advice OPAL could not find an SECBOOT partition > + * on the system flash. Check that the system flash > + * has a valid partition table, and that the firmware > + * build process has added a SECBOOT partition. > + */ > + prlog(PR_ERR, "FLASH: Can't parse ffs info for SECBOOT\n"); > + return OPAL_HARDWARE; > + } Should we enforce secure boot here? As in, if booting securely, do we erase everything? What is the behaviour of the system in the event of corruption? Should there be a golden image that's signed and immutable? > + secboot_flash = flash; > + secboot_offset = start; > + secboot_size = ecc ? ecc_buffer_size_minus_ecc(size) : size; > + > + platform.secboot_info = flash_secboot_info; > + platform.secboot_read = flash_secboot_read; > + platform.secboot_write = flash_secboot_write; > + > + return 0; > +} > + > static int flash_nvram_probe(struct flash *flash, struct ffs_handle *ffs) > { > uint32_t start, size, part; > @@ -376,6 +493,7 @@ static void setup_system_flash(struct flash *flash, struct dt_node *node, > prlog(PR_INFO, "FLASH: registered system flash device %s\n", name); > > flash_nvram_probe(flash, ffs); > + flash_secboot_probe(flash, ffs); > } > > static int num_flashes(void) > diff --git a/include/platform.h b/include/platform.h > index 1a35a86a..1ecafe74 100644 > --- a/include/platform.h > +++ b/include/platform.h > @@ -161,6 +161,10 @@ struct platform { > uint32_t len); > int (*nvram_write)(uint32_t dst, void *src, uint32_t len); > > + int (*secboot_info)(uint32_t *total_size); > + int (*secboot_read)(void *dst, uint32_t src, uint32_t len); > + int (*secboot_write)(uint32_t dst, void *src, uint32_t len); > + > /* > * OCC timeout. This return how long we should wait for the OCC > * before timing out. This lets us use a high value on larger FSP > -- > 2.14.4 > > _______________________________________________ > Skiboot mailing list > Skiboot@lists.ozlabs.org > https://lists.ozlabs.org/listinfo/skiboot >
diff --git a/core/flash.c b/core/flash.c index 8f00d85e..4e952cb0 100644 --- a/core/flash.c +++ b/core/flash.c @@ -49,6 +49,10 @@ static struct lock flash_lock; static struct flash *nvram_flash; static u32 nvram_offset, nvram_size; +/* secboot-on-flash support */ +static struct flash *secboot_flash; +static u32 secboot_offset, secboot_size; + /* ibm,firmware-versions support */ static char *version_buf; static size_t version_buf_size = 0x2000; @@ -76,6 +80,80 @@ void flash_release(void) unlock(&flash_lock); } +static int flash_secboot_info(uint32_t *total_size) +{ + int rc; + + lock(&flash_lock); + if (!secboot_flash) { + rc = OPAL_HARDWARE; + } else if (secboot_flash->busy) { + rc = OPAL_BUSY; + } else { + *total_size = secboot_size; + rc = OPAL_SUCCESS; + } + unlock(&flash_lock); + + return rc; +} + +static int flash_secboot_read(void *dst, uint32_t src, uint32_t len) +{ + int rc; + + if (!try_lock(&flash_lock)) + return OPAL_BUSY; + + if (!secboot_flash) { + rc = OPAL_HARDWARE; + goto out; + } + + if (secboot_flash->busy) { + rc = OPAL_BUSY; + goto out; + } + + if ((src + len) > secboot_size) { + prerror("FLASH_SECBOOT: read out of bound (0x%x,0x%x)\n", + src, len); + rc = OPAL_PARAMETER; + goto out; + } + + rc = blocklevel_read(secboot_flash->bl, secboot_offset + src, dst, len); + +out: + unlock(&flash_lock); + return rc; +} + +static int flash_secboot_write(uint32_t dst, void *src, uint32_t len) +{ + int rc; + + if (!try_lock(&flash_lock)) + return OPAL_BUSY; + + if (secboot_flash->busy) { + rc = OPAL_BUSY; + goto out; + } + + if ((dst + len) > secboot_size) { + prerror("FLASH_SECBOOT: write out of bound (0x%x,0x%x)\n", + dst, len); + rc = OPAL_PARAMETER; + goto out; + } + rc = blocklevel_write(secboot_flash->bl, secboot_offset + dst, src, len); + +out: + unlock(&flash_lock); + return rc; +} + static int flash_nvram_info(uint32_t *total_size) { int rc; @@ -283,6 +361,45 @@ void flash_fw_version_preload(void) } } +static int flash_secboot_probe(struct flash *flash, struct ffs_handle *ffs) +{ + uint32_t start, size, part; + bool ecc; + int rc; + + prlog(PR_INFO, "FLASH: probing for SECBOOT\n"); + + rc = ffs_lookup_part(ffs, "SECBOOT", &part); + if (rc) { + prlog(PR_WARNING, "FLASH: no SECBOOT partition found\n"); + return OPAL_HARDWARE; + } + + rc = ffs_part_info(ffs, part, NULL, + &start, &size, NULL, &ecc); + if (rc) { + /** + * @fwts-label SECBOOTNoPartition + * @fwts-advice OPAL could not find an SECBOOT partition + * on the system flash. Check that the system flash + * has a valid partition table, and that the firmware + * build process has added a SECBOOT partition. + */ + prlog(PR_ERR, "FLASH: Can't parse ffs info for SECBOOT\n"); + return OPAL_HARDWARE; + } + + secboot_flash = flash; + secboot_offset = start; + secboot_size = ecc ? ecc_buffer_size_minus_ecc(size) : size; + + platform.secboot_info = flash_secboot_info; + platform.secboot_read = flash_secboot_read; + platform.secboot_write = flash_secboot_write; + + return 0; +} + static int flash_nvram_probe(struct flash *flash, struct ffs_handle *ffs) { uint32_t start, size, part; @@ -376,6 +493,7 @@ static void setup_system_flash(struct flash *flash, struct dt_node *node, prlog(PR_INFO, "FLASH: registered system flash device %s\n", name); flash_nvram_probe(flash, ffs); + flash_secboot_probe(flash, ffs); } static int num_flashes(void) diff --git a/include/platform.h b/include/platform.h index 1a35a86a..1ecafe74 100644 --- a/include/platform.h +++ b/include/platform.h @@ -161,6 +161,10 @@ struct platform { uint32_t len); int (*nvram_write)(uint32_t dst, void *src, uint32_t len); + int (*secboot_info)(uint32_t *total_size); + int (*secboot_read)(void *dst, uint32_t src, uint32_t len); + int (*secboot_write)(uint32_t dst, void *src, uint32_t len); + /* * OCC timeout. This return how long we should wait for the OCC * before timing out. This lets us use a high value on larger FSP