forked from microsoft/WSL2-Linux-Kernel
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
s390/ipl: read IPL report at early boot
Read the IPL Report block provided by secure-boot, add the entries of the certificate list to the system key ring and print the list of components. PR: Adjust to Vasilys bootdata_preserved patch set. Preserve ipl_cert_list for later use in kexec_file. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Philipp Rudo <prudo@linux.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
- Loading branch information
Martin Schwidefsky
committed
Apr 26, 2019
1 parent
d29af5b
commit 9641b8c
Showing
10 changed files
with
300 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
#include <linux/init.h> | ||
#include <linux/ctype.h> | ||
#include <asm/ebcdic.h> | ||
#include <asm/sclp.h> | ||
#include <asm/sections.h> | ||
#include <asm/boot_data.h> | ||
#include <uapi/asm/ipl.h> | ||
#include "boot.h" | ||
|
||
int __bootdata_preserved(ipl_secure_flag); | ||
|
||
unsigned long __bootdata_preserved(ipl_cert_list_addr); | ||
unsigned long __bootdata_preserved(ipl_cert_list_size); | ||
|
||
unsigned long __bootdata(early_ipl_comp_list_addr); | ||
unsigned long __bootdata(early_ipl_comp_list_size); | ||
|
||
#define for_each_rb_entry(entry, rb) \ | ||
for (entry = rb->entries; \ | ||
(void *) entry + sizeof(*entry) <= (void *) rb + rb->len; \ | ||
entry++) | ||
|
||
static inline bool intersects(unsigned long addr0, unsigned long size0, | ||
unsigned long addr1, unsigned long size1) | ||
{ | ||
return addr0 + size0 > addr1 && addr1 + size1 > addr0; | ||
} | ||
|
||
static unsigned long find_bootdata_space(struct ipl_rb_components *comps, | ||
struct ipl_rb_certificates *certs, | ||
unsigned long safe_addr) | ||
{ | ||
struct ipl_rb_certificate_entry *cert; | ||
struct ipl_rb_component_entry *comp; | ||
size_t size; | ||
|
||
/* | ||
* Find the length for the IPL report boot data | ||
*/ | ||
early_ipl_comp_list_size = 0; | ||
for_each_rb_entry(comp, comps) | ||
early_ipl_comp_list_size += sizeof(*comp); | ||
ipl_cert_list_size = 0; | ||
for_each_rb_entry(cert, certs) | ||
ipl_cert_list_size += sizeof(unsigned int) + cert->len; | ||
size = ipl_cert_list_size + early_ipl_comp_list_size; | ||
|
||
/* | ||
* Start from safe_addr to find a free memory area large | ||
* enough for the IPL report boot data. This area is used | ||
* for ipl_cert_list_addr/ipl_cert_list_size and | ||
* early_ipl_comp_list_addr/early_ipl_comp_list_size. It must | ||
* not overlap with any component or any certificate. | ||
*/ | ||
repeat: | ||
if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && INITRD_START && INITRD_SIZE && | ||
intersects(INITRD_START, INITRD_SIZE, safe_addr, size)) | ||
safe_addr = INITRD_START + INITRD_SIZE; | ||
for_each_rb_entry(comp, comps) | ||
if (intersects(safe_addr, size, comp->addr, comp->len)) { | ||
safe_addr = comp->addr + comp->len; | ||
goto repeat; | ||
} | ||
for_each_rb_entry(cert, certs) | ||
if (intersects(safe_addr, size, cert->addr, cert->len)) { | ||
safe_addr = cert->addr + cert->len; | ||
goto repeat; | ||
} | ||
early_ipl_comp_list_addr = safe_addr; | ||
ipl_cert_list_addr = safe_addr + early_ipl_comp_list_size; | ||
|
||
return safe_addr + size; | ||
} | ||
|
||
static void copy_components_bootdata(struct ipl_rb_components *comps) | ||
{ | ||
struct ipl_rb_component_entry *comp, *ptr; | ||
|
||
ptr = (struct ipl_rb_component_entry *) early_ipl_comp_list_addr; | ||
for_each_rb_entry(comp, comps) | ||
memcpy(ptr++, comp, sizeof(*ptr)); | ||
} | ||
|
||
static void copy_certificates_bootdata(struct ipl_rb_certificates *certs) | ||
{ | ||
struct ipl_rb_certificate_entry *cert; | ||
void *ptr; | ||
|
||
ptr = (void *) ipl_cert_list_addr; | ||
for_each_rb_entry(cert, certs) { | ||
*(unsigned int *) ptr = cert->len; | ||
ptr += sizeof(unsigned int); | ||
memcpy(ptr, (void *) cert->addr, cert->len); | ||
ptr += cert->len; | ||
} | ||
} | ||
|
||
unsigned long read_ipl_report(unsigned long safe_addr) | ||
{ | ||
struct ipl_rb_certificates *certs; | ||
struct ipl_rb_components *comps; | ||
struct ipl_pl_hdr *pl_hdr; | ||
struct ipl_rl_hdr *rl_hdr; | ||
struct ipl_rb_hdr *rb_hdr; | ||
unsigned long tmp; | ||
void *rl_end; | ||
|
||
/* | ||
* Check if there is a IPL report by looking at the copy | ||
* of the IPL parameter information block. | ||
*/ | ||
if (!ipl_block_valid || | ||
!(ipl_block.hdr.flags & IPL_PL_FLAG_IPLSR)) | ||
return safe_addr; | ||
ipl_secure_flag = !!(ipl_block.hdr.flags & IPL_PL_FLAG_SIPL); | ||
/* | ||
* There is an IPL report, to find it load the pointer to the | ||
* IPL parameter information block from lowcore and skip past | ||
* the IPL parameter list, then align the address to a double | ||
* word boundary. | ||
*/ | ||
tmp = (unsigned long) S390_lowcore.ipl_parmblock_ptr; | ||
pl_hdr = (struct ipl_pl_hdr *) tmp; | ||
tmp = (tmp + pl_hdr->len + 7) & -8UL; | ||
rl_hdr = (struct ipl_rl_hdr *) tmp; | ||
/* Walk through the IPL report blocks in the IPL Report list */ | ||
certs = NULL; | ||
comps = NULL; | ||
rl_end = (void *) rl_hdr + rl_hdr->len; | ||
rb_hdr = (void *) rl_hdr + sizeof(*rl_hdr); | ||
while ((void *) rb_hdr + sizeof(*rb_hdr) < rl_end && | ||
(void *) rb_hdr + rb_hdr->len <= rl_end) { | ||
|
||
switch (rb_hdr->rbt) { | ||
case IPL_RBT_CERTIFICATES: | ||
certs = (struct ipl_rb_certificates *) rb_hdr; | ||
break; | ||
case IPL_RBT_COMPONENTS: | ||
comps = (struct ipl_rb_components *) rb_hdr; | ||
break; | ||
default: | ||
break; | ||
} | ||
|
||
rb_hdr = (void *) rb_hdr + rb_hdr->len; | ||
} | ||
|
||
/* | ||
* With either the component list or the certificate list | ||
* missing the kernel will stay ignorant of secure IPL. | ||
*/ | ||
if (!comps || !certs) | ||
return safe_addr; | ||
|
||
/* | ||
* Copy component and certificate list to a safe area | ||
* where the decompressed kernel can find them. | ||
*/ | ||
safe_addr = find_bootdata_space(comps, certs, safe_addr); | ||
copy_components_bootdata(comps); | ||
copy_certificates_bootdata(certs); | ||
|
||
return safe_addr; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.