summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2019-02-21 08:23:04 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2019-04-26 06:34:05 -0400
commit9641b8cc733f70a5400aa7e6831de4542c46a94c (patch)
tree446b0fc5c9e6875da888017debb971eff4d4d4b0 /arch
parentd29af5b7a886033e6a4eb5f0a9a25cd00da63ae8 (diff)
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>
Diffstat (limited to 'arch')
-rw-r--r--arch/s390/boot/Makefile5
-rw-r--r--arch/s390/boot/boot.h2
-rw-r--r--arch/s390/boot/ipl_report.c165
-rw-r--r--arch/s390/boot/startup.c18
-rw-r--r--arch/s390/include/asm/boot_data.h7
-rw-r--r--arch/s390/kernel/ipl.c19
-rw-r--r--arch/s390/kernel/setup.c45
7 files changed, 250 insertions, 11 deletions
diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile
index a5ae68b2aa84..1f8fd68beae3 100644
--- a/arch/s390/boot/Makefile
+++ b/arch/s390/boot/Makefile
@@ -28,8 +28,9 @@ endif
28 28
29CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char 29CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char
30 30
31obj-y := head.o als.o startup.o mem_detect.o ipl_parm.o string.o ebcdic.o 31obj-y := head.o als.o startup.o mem_detect.o ipl_parm.o ipl_report.o
32obj-y += sclp_early_core.o mem.o ipl_vmparm.o cmdline.o ctype.o 32obj-y += string.o ebcdic.o sclp_early_core.o mem.o ipl_vmparm.o cmdline.o
33obj-y += ctype.o
33obj-$(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) += uv.o 34obj-$(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) += uv.o
34targets := bzImage startup.a section_cmp.boot.data section_cmp.boot.preserved.data $(obj-y) 35targets := bzImage startup.a section_cmp.boot.data section_cmp.boot.preserved.data $(obj-y)
35subdir- := compressed 36subdir- := compressed
diff --git a/arch/s390/boot/boot.h b/arch/s390/boot/boot.h
index 82bc06346e05..ca395fcff15e 100644
--- a/arch/s390/boot/boot.h
+++ b/arch/s390/boot/boot.h
@@ -10,4 +10,6 @@ void parse_boot_command_line(void);
10void setup_memory_end(void); 10void setup_memory_end(void);
11void print_missing_facilities(void); 11void print_missing_facilities(void);
12 12
13unsigned long read_ipl_report(unsigned long safe_offset);
14
13#endif /* BOOT_BOOT_H */ 15#endif /* BOOT_BOOT_H */
diff --git a/arch/s390/boot/ipl_report.c b/arch/s390/boot/ipl_report.c
new file mode 100644
index 000000000000..0b4965573656
--- /dev/null
+++ b/arch/s390/boot/ipl_report.c
@@ -0,0 +1,165 @@
1// SPDX-License-Identifier: GPL-2.0
2#include <linux/init.h>
3#include <linux/ctype.h>
4#include <asm/ebcdic.h>
5#include <asm/sclp.h>
6#include <asm/sections.h>
7#include <asm/boot_data.h>
8#include <uapi/asm/ipl.h>
9#include "boot.h"
10
11int __bootdata_preserved(ipl_secure_flag);
12
13unsigned long __bootdata_preserved(ipl_cert_list_addr);
14unsigned long __bootdata_preserved(ipl_cert_list_size);
15
16unsigned long __bootdata(early_ipl_comp_list_addr);
17unsigned long __bootdata(early_ipl_comp_list_size);
18
19#define for_each_rb_entry(entry, rb) \
20 for (entry = rb->entries; \
21 (void *) entry + sizeof(*entry) <= (void *) rb + rb->len; \
22 entry++)
23
24static inline bool intersects(unsigned long addr0, unsigned long size0,
25 unsigned long addr1, unsigned long size1)
26{
27 return addr0 + size0 > addr1 && addr1 + size1 > addr0;
28}
29
30static unsigned long find_bootdata_space(struct ipl_rb_components *comps,
31 struct ipl_rb_certificates *certs,
32 unsigned long safe_addr)
33{
34 struct ipl_rb_certificate_entry *cert;
35 struct ipl_rb_component_entry *comp;
36 size_t size;
37
38 /*
39 * Find the length for the IPL report boot data
40 */
41 early_ipl_comp_list_size = 0;
42 for_each_rb_entry(comp, comps)
43 early_ipl_comp_list_size += sizeof(*comp);
44 ipl_cert_list_size = 0;
45 for_each_rb_entry(cert, certs)
46 ipl_cert_list_size += sizeof(unsigned int) + cert->len;
47 size = ipl_cert_list_size + early_ipl_comp_list_size;
48
49 /*
50 * Start from safe_addr to find a free memory area large
51 * enough for the IPL report boot data. This area is used
52 * for ipl_cert_list_addr/ipl_cert_list_size and
53 * early_ipl_comp_list_addr/early_ipl_comp_list_size. It must
54 * not overlap with any component or any certificate.
55 */
56repeat:
57 if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && INITRD_START && INITRD_SIZE &&
58 intersects(INITRD_START, INITRD_SIZE, safe_addr, size))
59 safe_addr = INITRD_START + INITRD_SIZE;
60 for_each_rb_entry(comp, comps)
61 if (intersects(safe_addr, size, comp->addr, comp->len)) {
62 safe_addr = comp->addr + comp->len;
63 goto repeat;
64 }
65 for_each_rb_entry(cert, certs)
66 if (intersects(safe_addr, size, cert->addr, cert->len)) {
67 safe_addr = cert->addr + cert->len;
68 goto repeat;
69 }
70 early_ipl_comp_list_addr = safe_addr;
71 ipl_cert_list_addr = safe_addr + early_ipl_comp_list_size;
72
73 return safe_addr + size;
74}
75
76static void copy_components_bootdata(struct ipl_rb_components *comps)
77{
78 struct ipl_rb_component_entry *comp, *ptr;
79
80 ptr = (struct ipl_rb_component_entry *) early_ipl_comp_list_addr;
81 for_each_rb_entry(comp, comps)
82 memcpy(ptr++, comp, sizeof(*ptr));
83}
84
85static void copy_certificates_bootdata(struct ipl_rb_certificates *certs)
86{
87 struct ipl_rb_certificate_entry *cert;
88 void *ptr;
89
90 ptr = (void *) ipl_cert_list_addr;
91 for_each_rb_entry(cert, certs) {
92 *(unsigned int *) ptr = cert->len;
93 ptr += sizeof(unsigned int);
94 memcpy(ptr, (void *) cert->addr, cert->len);
95 ptr += cert->len;
96 }
97}
98
99unsigned long read_ipl_report(unsigned long safe_addr)
100{
101 struct ipl_rb_certificates *certs;
102 struct ipl_rb_components *comps;
103 struct ipl_pl_hdr *pl_hdr;
104 struct ipl_rl_hdr *rl_hdr;
105 struct ipl_rb_hdr *rb_hdr;
106 unsigned long tmp;
107 void *rl_end;
108
109 /*
110 * Check if there is a IPL report by looking at the copy
111 * of the IPL parameter information block.
112 */
113 if (!ipl_block_valid ||
114 !(ipl_block.hdr.flags & IPL_PL_FLAG_IPLSR))
115 return safe_addr;
116 ipl_secure_flag = !!(ipl_block.hdr.flags & IPL_PL_FLAG_SIPL);
117 /*
118 * There is an IPL report, to find it load the pointer to the
119 * IPL parameter information block from lowcore and skip past
120 * the IPL parameter list, then align the address to a double
121 * word boundary.
122 */
123 tmp = (unsigned long) S390_lowcore.ipl_parmblock_ptr;
124 pl_hdr = (struct ipl_pl_hdr *) tmp;
125 tmp = (tmp + pl_hdr->len + 7) & -8UL;
126 rl_hdr = (struct ipl_rl_hdr *) tmp;
127 /* Walk through the IPL report blocks in the IPL Report list */
128 certs = NULL;
129 comps = NULL;
130 rl_end = (void *) rl_hdr + rl_hdr->len;
131 rb_hdr = (void *) rl_hdr + sizeof(*rl_hdr);
132 while ((void *) rb_hdr + sizeof(*rb_hdr) < rl_end &&
133 (void *) rb_hdr + rb_hdr->len <= rl_end) {
134
135 switch (rb_hdr->rbt) {
136 case IPL_RBT_CERTIFICATES:
137 certs = (struct ipl_rb_certificates *) rb_hdr;
138 break;
139 case IPL_RBT_COMPONENTS:
140 comps = (struct ipl_rb_components *) rb_hdr;
141 break;
142 default:
143 break;
144 }
145
146 rb_hdr = (void *) rb_hdr + rb_hdr->len;
147 }
148
149 /*
150 * With either the component list or the certificate list
151 * missing the kernel will stay ignorant of secure IPL.
152 */
153 if (!comps || !certs)
154 return safe_addr;
155
156 /*
157 * Copy component and certificate list to a safe area
158 * where the decompressed kernel can find them.
159 */
160 safe_addr = find_bootdata_space(comps, certs, safe_addr);
161 copy_components_bootdata(comps);
162 copy_certificates_bootdata(certs);
163
164 return safe_addr;
165}
diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c
index 2bd4a62d436c..90898976a941 100644
--- a/arch/s390/boot/startup.c
+++ b/arch/s390/boot/startup.c
@@ -25,19 +25,16 @@ unsigned long mem_safe_offset(void)
25} 25}
26#endif 26#endif
27 27
28static void rescue_initrd(void) 28static void rescue_initrd(unsigned long addr)
29{ 29{
30 unsigned long min_initrd_addr;
31
32 if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD)) 30 if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD))
33 return; 31 return;
34 if (!INITRD_START || !INITRD_SIZE) 32 if (!INITRD_START || !INITRD_SIZE)
35 return; 33 return;
36 min_initrd_addr = mem_safe_offset(); 34 if (addr <= INITRD_START)
37 if (min_initrd_addr <= INITRD_START)
38 return; 35 return;
39 memmove((void *)min_initrd_addr, (void *)INITRD_START, INITRD_SIZE); 36 memmove((void *)addr, (void *)INITRD_START, INITRD_SIZE);
40 INITRD_START = min_initrd_addr; 37 INITRD_START = addr;
41} 38}
42 39
43static void copy_bootdata(void) 40static void copy_bootdata(void)
@@ -52,12 +49,15 @@ static void copy_bootdata(void)
52 49
53void startup_kernel(void) 50void startup_kernel(void)
54{ 51{
52 unsigned long safe_addr;
55 void *img; 53 void *img;
56 54
55 store_ipl_parmblock();
56 safe_addr = mem_safe_offset();
57 safe_addr = read_ipl_report(safe_addr);
57 uv_query_info(); 58 uv_query_info();
58 rescue_initrd(); 59 rescue_initrd(safe_addr);
59 sclp_early_read_info(); 60 sclp_early_read_info();
60 store_ipl_parmblock();
61 setup_boot_command_line(); 61 setup_boot_command_line();
62 parse_boot_command_line(); 62 parse_boot_command_line();
63 setup_memory_end(); 63 setup_memory_end();
diff --git a/arch/s390/include/asm/boot_data.h b/arch/s390/include/asm/boot_data.h
index d794802a2291..f7eed27b3220 100644
--- a/arch/s390/include/asm/boot_data.h
+++ b/arch/s390/include/asm/boot_data.h
@@ -7,5 +7,12 @@
7extern char early_command_line[COMMAND_LINE_SIZE]; 7extern char early_command_line[COMMAND_LINE_SIZE];
8extern struct ipl_parameter_block ipl_block; 8extern struct ipl_parameter_block ipl_block;
9extern int ipl_block_valid; 9extern int ipl_block_valid;
10extern int ipl_secure_flag;
11
12extern unsigned long ipl_cert_list_addr;
13extern unsigned long ipl_cert_list_size;
14
15extern unsigned long early_ipl_comp_list_addr;
16extern unsigned long early_ipl_comp_list_size;
10 17
11#endif /* _ASM_S390_BOOT_DATA_H */ 18#endif /* _ASM_S390_BOOT_DATA_H */
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index f9718bc67cd4..0567de4005b4 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -122,6 +122,13 @@ static char *dump_type_str(enum dump_type type)
122 122
123int __bootdata_preserved(ipl_block_valid); 123int __bootdata_preserved(ipl_block_valid);
124struct ipl_parameter_block __bootdata_preserved(ipl_block); 124struct ipl_parameter_block __bootdata_preserved(ipl_block);
125int __bootdata_preserved(ipl_secure_flag);
126
127unsigned long __bootdata_preserved(ipl_cert_list_addr);
128unsigned long __bootdata_preserved(ipl_cert_list_size);
129
130unsigned long __bootdata(early_ipl_comp_list_addr);
131unsigned long __bootdata(early_ipl_comp_list_size);
125 132
126static int reipl_capabilities = IPL_TYPE_UNKNOWN; 133static int reipl_capabilities = IPL_TYPE_UNKNOWN;
127 134
@@ -267,6 +274,15 @@ static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr,
267 274
268static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); 275static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
269 276
277static ssize_t ipl_secure_show(struct kobject *kobj,
278 struct kobj_attribute *attr, char *page)
279{
280 return sprintf(page, "%i\n", !!ipl_secure_flag);
281}
282
283static struct kobj_attribute sys_ipl_secure_attr =
284 __ATTR(secure, 0444, ipl_secure_show, NULL);
285
270static ssize_t ipl_vm_parm_show(struct kobject *kobj, 286static ssize_t ipl_vm_parm_show(struct kobject *kobj,
271 struct kobj_attribute *attr, char *page) 287 struct kobj_attribute *attr, char *page)
272{ 288{
@@ -362,6 +378,7 @@ static struct attribute *ipl_fcp_attrs[] = {
362 &sys_ipl_fcp_bootprog_attr.attr, 378 &sys_ipl_fcp_bootprog_attr.attr,
363 &sys_ipl_fcp_br_lba_attr.attr, 379 &sys_ipl_fcp_br_lba_attr.attr,
364 &sys_ipl_ccw_loadparm_attr.attr, 380 &sys_ipl_ccw_loadparm_attr.attr,
381 &sys_ipl_secure_attr.attr,
365 NULL, 382 NULL,
366}; 383};
367 384
@@ -377,6 +394,7 @@ static struct attribute *ipl_ccw_attrs_vm[] = {
377 &sys_ipl_device_attr.attr, 394 &sys_ipl_device_attr.attr,
378 &sys_ipl_ccw_loadparm_attr.attr, 395 &sys_ipl_ccw_loadparm_attr.attr,
379 &sys_ipl_vm_parm_attr.attr, 396 &sys_ipl_vm_parm_attr.attr,
397 &sys_ipl_secure_attr.attr,
380 NULL, 398 NULL,
381}; 399};
382 400
@@ -384,6 +402,7 @@ static struct attribute *ipl_ccw_attrs_lpar[] = {
384 &sys_ipl_type_attr.attr, 402 &sys_ipl_type_attr.attr,
385 &sys_ipl_device_attr.attr, 403 &sys_ipl_device_attr.attr,
386 &sys_ipl_ccw_loadparm_attr.attr, 404 &sys_ipl_ccw_loadparm_attr.attr,
405 &sys_ipl_secure_attr.attr,
387 NULL, 406 NULL,
388}; 407};
389 408
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 12d136e567c4..ffc87520aca9 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -50,6 +50,7 @@
50#include <linux/compat.h> 50#include <linux/compat.h>
51#include <linux/start_kernel.h> 51#include <linux/start_kernel.h>
52 52
53#include <asm/boot_data.h>
53#include <asm/ipl.h> 54#include <asm/ipl.h>
54#include <asm/facility.h> 55#include <asm/facility.h>
55#include <asm/smp.h> 56#include <asm/smp.h>
@@ -741,6 +742,15 @@ static void __init reserve_initrd(void)
741#endif 742#endif
742} 743}
743 744
745/*
746 * Reserve the memory area used to pass the certificate lists
747 */
748static void __init reserve_certificate_list(void)
749{
750 if (ipl_cert_list_addr)
751 memblock_reserve(ipl_cert_list_addr, ipl_cert_list_size);
752}
753
744static void __init reserve_mem_detect_info(void) 754static void __init reserve_mem_detect_info(void)
745{ 755{
746 unsigned long start, size; 756 unsigned long start, size;
@@ -1036,6 +1046,38 @@ static void __init setup_control_program_code(void)
1036} 1046}
1037 1047
1038/* 1048/*
1049 * Print the component list from the IPL report
1050 */
1051static void __init log_component_list(void)
1052{
1053 struct ipl_rb_component_entry *ptr, *end;
1054 char *str;
1055
1056 if (!early_ipl_comp_list_addr)
1057 return;
1058 if (ipl_block.hdr.flags & IPL_PL_FLAG_IPLSR)
1059 pr_info("Linux is running with Secure-IPL enabled\n");
1060 else
1061 pr_info("Linux is running with Secure-IPL disabled\n");
1062 ptr = (void *) early_ipl_comp_list_addr;
1063 end = (void *) ptr + early_ipl_comp_list_size;
1064 pr_info("The IPL report contains the following components:\n");
1065 while (ptr < end) {
1066 if (ptr->flags & IPL_RB_COMPONENT_FLAG_SIGNED) {
1067 if (ptr->flags & IPL_RB_COMPONENT_FLAG_VERIFIED)
1068 str = "signed, verified";
1069 else
1070 str = "signed, verification failed";
1071 } else {
1072 str = "not signed";
1073 }
1074 pr_info("%016llx - %016llx (%s)\n",
1075 ptr->addr, ptr->addr + ptr->len, str);
1076 ptr++;
1077 }
1078}
1079
1080/*
1039 * Setup function called from init/main.c just after the banner 1081 * Setup function called from init/main.c just after the banner
1040 * was printed. 1082 * was printed.
1041 */ 1083 */
@@ -1055,6 +1097,8 @@ void __init setup_arch(char **cmdline_p)
1055 else 1097 else
1056 pr_info("Linux is running as a guest in 64-bit mode\n"); 1098 pr_info("Linux is running as a guest in 64-bit mode\n");
1057 1099
1100 log_component_list();
1101
1058 /* Have one command line that is parsed and saved in /proc/cmdline */ 1102 /* Have one command line that is parsed and saved in /proc/cmdline */
1059 /* boot_command_line has been already set up in early.c */ 1103 /* boot_command_line has been already set up in early.c */
1060 *cmdline_p = boot_command_line; 1104 *cmdline_p = boot_command_line;
@@ -1086,6 +1130,7 @@ void __init setup_arch(char **cmdline_p)
1086 reserve_oldmem(); 1130 reserve_oldmem();
1087 reserve_kernel(); 1131 reserve_kernel();
1088 reserve_initrd(); 1132 reserve_initrd();
1133 reserve_certificate_list();
1089 reserve_mem_detect_info(); 1134 reserve_mem_detect_info();
1090 memblock_allow_resize(); 1135 memblock_allow_resize();
1091 1136