mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
zipl: add secure boot switch
Add a command line option and configuration section keyword to control
the zIPL secure boot support. This option is named "secure" and can take
one of three values:
auto (default)
Write signatures if available and supported by the system.
1
Signatures are written independent of support indicated by the local
system. Also missing signatures for stage 3 and kernel IPL files
will result in an error.
0
No signatures will be written.
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
7c7e10ed8f
commit
58a7462f65
@@ -121,6 +121,7 @@ struct job_data {
|
||||
int add_files;
|
||||
int dry_run;
|
||||
int command_line;
|
||||
int is_secure;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ int misc_check_readable_file(const char* filename);
|
||||
int misc_check_writable_device(const char* devno, int blockdev, int chardev);
|
||||
void misc_ebcdic_to_ascii(unsigned char *from, unsigned char *to);
|
||||
void misc_ascii_to_ebcdic(unsigned char *from, unsigned char *to);
|
||||
unsigned int misc_check_secure_boot(void);
|
||||
|
||||
#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
|
||||
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
|
||||
|
||||
+2
-1
@@ -16,7 +16,7 @@
|
||||
|
||||
|
||||
#define SCAN_SECTION_NUM 9
|
||||
#define SCAN_KEYWORD_NUM 21
|
||||
#define SCAN_KEYWORD_NUM 22
|
||||
#define SCAN_KEYWORD_ONLY_NUM 1
|
||||
#define SCAN_AUTOMENU_NAME "zipl-automatic-menu"
|
||||
|
||||
@@ -51,6 +51,7 @@ enum scan_keyword_id {
|
||||
scan_keyword_targetoffset = 18,
|
||||
scan_keyword_defaultauto = 19,
|
||||
scan_keyword_kdump = 20,
|
||||
scan_keyword_secure = 21,
|
||||
};
|
||||
|
||||
enum scan_section_type {
|
||||
|
||||
@@ -45,12 +45,17 @@
|
||||
#define ZIPL_DEFAULT_CONF "/etc/zipl.conf"
|
||||
#define ZIPL_DEFAULT_BLSDIR "/boot/loader/entries"
|
||||
#define ZIPL_STAGE3_PATH TOOLS_LIBDIR "/stage3.bin"
|
||||
#define ZIPL_SIPL_PATH "/sys/firmware/ipl/has_secure"
|
||||
|
||||
#define MENU_DEFAULT_PROMPT 0
|
||||
#define MENU_DEFAULT_TIMEOUT 0
|
||||
|
||||
#define MAX_DUMP_VOLUMES 32
|
||||
|
||||
#define SECURE_BOOT_DISABLED 0
|
||||
#define SECURE_BOOT_ENABLED 1
|
||||
#define SECURE_BOOT_AUTO 2
|
||||
|
||||
/* Internal component load address type */
|
||||
typedef uint64_t address_t;
|
||||
|
||||
|
||||
+57
-8
@@ -19,6 +19,7 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "lib/util_part.h"
|
||||
#include "lib/util_path.h"
|
||||
|
||||
#include "boot.h"
|
||||
#include "bootmap.h"
|
||||
@@ -117,6 +118,22 @@ check_menu_positions(struct job_menu_data* menu, char* name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
check_secure_boot_support(void)
|
||||
{
|
||||
unsigned int val;
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(ZIPL_SIPL_PATH, "r");
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
fscanf(fp, "%d", &val);
|
||||
fclose(fp);
|
||||
|
||||
return val ? true : false;
|
||||
}
|
||||
|
||||
|
||||
/* Write COUNT elements of the blocklist specified by LIST as a linked list
|
||||
* of segment table blocks to the file identified by file descriptor FD. Upon
|
||||
@@ -452,7 +469,8 @@ check_remaining_filesize(size_t filesize, size_t signature_size,
|
||||
static int
|
||||
add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program,
|
||||
int verbose, int add_files, component_header_type type,
|
||||
struct disk_info* info, struct job_target_data* target)
|
||||
struct disk_info* info, struct job_target_data* target,
|
||||
int is_secure)
|
||||
{
|
||||
struct stat stats;
|
||||
void* table;
|
||||
@@ -467,6 +485,7 @@ add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program,
|
||||
size_t signature_size;
|
||||
struct signature_header sig_head;
|
||||
int comp_nr = 0;
|
||||
bool secure_boot_supported;
|
||||
|
||||
memset(comp_loc, 0, sizeof(comp_loc));
|
||||
memset(&sig_head, 0, sizeof(sig_head));
|
||||
@@ -515,10 +534,12 @@ add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program,
|
||||
return -1;
|
||||
}
|
||||
image_size = stats.st_size;
|
||||
|
||||
secure_boot_supported = check_secure_boot_support();
|
||||
signature_size = extract_signature(ZIPL_STAGE3_PATH, &signature,
|
||||
&sig_head);
|
||||
if (signature_size) {
|
||||
if (signature_size &&
|
||||
(is_secure == SECURE_BOOT_ENABLED ||
|
||||
(is_secure == SECURE_BOOT_AUTO && secure_boot_supported))) {
|
||||
if (verbose)
|
||||
printf(" signature for.....: %s\n", ZIPL_STAGE3_PATH);
|
||||
|
||||
@@ -536,6 +557,17 @@ add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program,
|
||||
offset += sizeof(struct component_entry);
|
||||
comp_nr++;
|
||||
free(signature);
|
||||
} else if (is_secure == SECURE_BOOT_ENABLED) {
|
||||
/*
|
||||
* If secure boot is forced and we have failed to extract a
|
||||
* signature for the stage 3 loader zipl will abort with an
|
||||
* error message
|
||||
*/
|
||||
error_text("Could not install Secure Boot IPL records");
|
||||
error_reason("Missing signature in internal loader file %s",
|
||||
ZIPL_STAGE3_PATH);
|
||||
free(table);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add stage 3 loader to bootmap */
|
||||
@@ -584,7 +616,9 @@ add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program,
|
||||
printf(" kernel image......: %s\n", ipl->image);
|
||||
}
|
||||
signature_size = extract_signature(ipl->image, &signature, &sig_head);
|
||||
if (signature_size) {
|
||||
if (signature_size &&
|
||||
(is_secure == SECURE_BOOT_ENABLED ||
|
||||
(is_secure == SECURE_BOOT_AUTO && secure_boot_supported))) {
|
||||
if (verbose)
|
||||
printf(" signature for.....: %s\n", ipl->image);
|
||||
|
||||
@@ -604,6 +638,17 @@ add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program,
|
||||
free(signature);
|
||||
check_remaining_filesize(image_size, signature_size, info,
|
||||
ipl->image);
|
||||
} else if (is_secure == SECURE_BOOT_ENABLED) {
|
||||
/*
|
||||
* If secure boot is forced and we have failed to extract a
|
||||
* signature for the kernel image zipl will abort with an
|
||||
* error message
|
||||
*/
|
||||
error_text("Could not install Secure Boot IPL records");
|
||||
error_reason("Missing signature in image file %s",
|
||||
ipl->image);
|
||||
free(table);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = add_component_file(fd, ipl->image, ipl->image_addr,
|
||||
@@ -644,7 +689,10 @@ add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program,
|
||||
if (ipl->ramdisk != NULL) {
|
||||
signature_size = extract_signature(ipl->ramdisk, &signature,
|
||||
&sig_head);
|
||||
if (signature_size) {
|
||||
if (signature_size &&
|
||||
(is_secure == SECURE_BOOT_ENABLED ||
|
||||
(is_secure == SECURE_BOOT_AUTO &&
|
||||
secure_boot_supported))) {
|
||||
if (verbose) {
|
||||
printf(" signature for.....: %s\n",
|
||||
ipl->ramdisk);
|
||||
@@ -830,7 +878,7 @@ add_dump_program(int fd, struct job_dump_data* dump,
|
||||
return rc;
|
||||
ipl.parm_addr = dump->parm_addr;
|
||||
return add_ipl_program(fd, &ipl, program, verbose, 1,
|
||||
type, info, target);
|
||||
type, info, target, SECURE_BOOT_DISABLED);
|
||||
}
|
||||
|
||||
|
||||
@@ -867,7 +915,7 @@ build_program_table(int fd, struct job_data* job, disk_blockptr_t* pointer,
|
||||
rc = add_ipl_program(fd, &job->data.ipl, &table[0],
|
||||
verbose || job->command_line,
|
||||
job->add_files, component_header,
|
||||
info, &job->target);
|
||||
info, &job->target, job->is_secure);
|
||||
break;
|
||||
case job_segment:
|
||||
if (job->command_line)
|
||||
@@ -918,7 +966,8 @@ build_program_table(int fd, struct job_data* job, disk_blockptr_t* pointer,
|
||||
&table[job->data.menu.entry[i].pos],
|
||||
verbose || job->command_line,
|
||||
job->add_files, component_header,
|
||||
info, &job->target);
|
||||
info, &job->target,
|
||||
job->is_secure);
|
||||
break;
|
||||
case job_print_usage:
|
||||
case job_print_version:
|
||||
|
||||
+41
-1
@@ -52,11 +52,12 @@ static struct option options[] = {
|
||||
{ "dry-run", no_argument, NULL, '0'},
|
||||
{ "force", no_argument, NULL, 'f'},
|
||||
{ "kdump", required_argument, NULL, 'k'},
|
||||
{ "secure", required_argument, NULL, 'S'},
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
/* Command line option abbreviations */
|
||||
static const char option_string[] = "-c:b:t:i:r:p:P:d:D:M:s:m:hHnVvaT:fk:";
|
||||
static const char option_string[] = "-c:b:t:i:r:p:P:d:D:M:s:S:m:hHnVvaT:fk:";
|
||||
|
||||
struct command_line {
|
||||
char* data[SCAN_KEYWORD_NUM];
|
||||
@@ -215,6 +216,11 @@ get_command_line(int argc, char* argv[], struct command_line* line)
|
||||
} else
|
||||
cmdline.menu = optarg;
|
||||
break;
|
||||
case 'S':
|
||||
is_keyword = 1;
|
||||
rc = store_option(&cmdline, scan_keyword_secure,
|
||||
optarg);
|
||||
break;
|
||||
case 'h':
|
||||
cmdline.help = 1;
|
||||
break;
|
||||
@@ -1263,6 +1269,26 @@ type_from_target(char *target, disk_type_t *type)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
set_secure_ipl(char *keyword, struct job_data *job)
|
||||
{
|
||||
if (strcmp(keyword, "auto") == 0) {
|
||||
job->is_secure = SECURE_BOOT_AUTO;
|
||||
} else if (strcmp(keyword, "0") == 0) {
|
||||
job->is_secure = SECURE_BOOT_DISABLED;
|
||||
} else if (strcmp(keyword, "1") == 0) {
|
||||
if (job->target.targettype != disk_type_scsi) {
|
||||
error_reason("Secure boot forced for non-SCSI disk type");
|
||||
return -1;
|
||||
}
|
||||
job->is_secure = SECURE_BOOT_ENABLED;
|
||||
} else {
|
||||
error_reason("Invalid secure boot setting '%s'",
|
||||
keyword);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
get_job_from_section_data(char* data[], struct job_data* job, char* section)
|
||||
@@ -1345,6 +1371,13 @@ get_job_from_section_data(char* data[], struct job_data* job, char* section)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* Fill in secure boot */
|
||||
if (data[(int) scan_keyword_secure] != NULL) {
|
||||
rc = set_secure_ipl(data[(int) scan_keyword_secure],
|
||||
job);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
break;
|
||||
case section_ipl_tape:
|
||||
/* Tape IPL job */
|
||||
@@ -1502,6 +1535,13 @@ get_menu_job(struct scan_token* scan, char* menu, struct job_data* job)
|
||||
job->data.menu.timeout =
|
||||
atol(scan[i].content.keyword.value);
|
||||
break;
|
||||
case scan_keyword_secure:
|
||||
rc = set_secure_ipl(
|
||||
scan[i].content.keyword.value,
|
||||
job);
|
||||
if (rc)
|
||||
return rc;
|
||||
break;
|
||||
case scan_keyword_target:
|
||||
job->target.bootmap_dir = misc_strdup(
|
||||
scan[i].content.keyword.value);
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "error.h"
|
||||
#include "misc.h"
|
||||
|
||||
|
||||
/* Allocate SIZE bytes of memory. Upon success, return pointer to memory.
|
||||
* Return NULL otherwise. */
|
||||
void *
|
||||
|
||||
+22
-12
@@ -45,45 +45,45 @@ enum scan_key_state scan_key_table[SCAN_SECTION_NUM][SCAN_KEYWORD_NUM] = {
|
||||
* ult to tofs e mete file isk ent et pt out ultm dump
|
||||
* rs enu
|
||||
*
|
||||
* targ targ targ targ targ defa kdum
|
||||
* etba etty etge etbl etof ulta p
|
||||
* targ targ targ targ targ defa kdum secu
|
||||
* etba etty etge etbl etof ulta p re
|
||||
* se pe omet ocks fset uto
|
||||
* ry ize
|
||||
*/
|
||||
/* default auto */
|
||||
{opt, inv, inv, inv, inv, inv, inv, inv, req, opt, opt, inv, inv, inv,
|
||||
opt, opt, opt, opt, opt, opt, inv},
|
||||
opt, opt, opt, opt, opt, opt, inv, opt},
|
||||
/* default menu */
|
||||
{inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv,
|
||||
inv, inv, inv, inv, inv, inv, inv},
|
||||
inv, inv, inv, inv, inv, inv, inv, opt},
|
||||
/* default section */
|
||||
{req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv,
|
||||
inv, inv, inv, inv, inv, inv, inv},
|
||||
inv, inv, inv, inv, inv, inv, inv, opt},
|
||||
/* ipl */
|
||||
{inv, inv, inv, req, opt, opt, opt, inv, req, inv, inv, inv, inv, inv,
|
||||
opt, opt, opt, opt, opt, inv, opt},
|
||||
opt, opt, opt, opt, opt, inv, opt, opt},
|
||||
/* segment load */
|
||||
{inv, inv, inv, inv, inv, inv, inv, req, req, inv, inv, inv, inv, inv,
|
||||
inv, inv, inv, inv, inv, inv, inv},
|
||||
inv, inv, inv, inv, inv, inv, inv, inv},
|
||||
/* part dump */
|
||||
{inv, req, inv, inv, inv, inv, inv, inv, opt, inv, inv, inv, inv, inv,
|
||||
inv, inv, inv, inv, inv, inv, inv},
|
||||
inv, inv, inv, inv, inv, inv, inv, inv},
|
||||
/* fs dump */
|
||||
{inv, inv, req, inv, opt, opt, inv, inv, req, inv, inv, inv, inv, inv,
|
||||
inv, inv, inv, inv, inv, inv, inv},
|
||||
inv, inv, inv, inv, inv, inv, inv, inv},
|
||||
/* ipl tape */
|
||||
{inv, inv, inv, req, opt, opt, opt, inv, inv, inv, inv, inv, req, inv,
|
||||
inv, inv, inv, inv, inv, inv, inv},
|
||||
inv, inv, inv, inv, inv, inv, inv, inv},
|
||||
/* multi volume dump */
|
||||
{inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req,
|
||||
inv, inv, inv, inv, inv, inv, inv}
|
||||
inv, inv, inv, inv, inv, inv, inv, inv}
|
||||
};
|
||||
|
||||
/* Determines which keyword may be present in a menu section */
|
||||
enum scan_key_state scan_menu_key_table[SCAN_KEYWORD_NUM] = {
|
||||
/* menu section */
|
||||
opt, inv, inv, inv, inv, inv, inv, inv, req, opt, opt, inv, inv, inv,
|
||||
opt, opt, opt, opt, opt, inv, inv
|
||||
opt, opt, opt, opt, opt, inv, inv, opt
|
||||
};
|
||||
|
||||
/* Mapping of keyword IDs to strings */
|
||||
@@ -111,6 +111,7 @@ static const struct {
|
||||
{ "timeout", scan_keyword_timeout},
|
||||
{ "tape", scan_keyword_tape},
|
||||
{ "kdump", scan_keyword_kdump},
|
||||
{ "secure", scan_keyword_secure},
|
||||
};
|
||||
|
||||
/* List of keywords that are used without an assignment */
|
||||
@@ -1863,6 +1864,7 @@ scan_build_automenu(struct scan_token* scan)
|
||||
/* defaultmenu */ 1 +
|
||||
/* menu heading */ 1 +
|
||||
/* keyword default,prompt,timeout */ 3 +
|
||||
/* keyword secure */ 1 +
|
||||
/* target keywords*/ num_targets +
|
||||
/* missing target definitions */ num_sections * num_targets +
|
||||
/* number assigment */ num_sections;
|
||||
@@ -1978,6 +1980,14 @@ scan_build_automenu(struct scan_token* scan)
|
||||
db_keyword[i]))
|
||||
goto err;
|
||||
}
|
||||
/* secure= */
|
||||
i = (int) scan_keyword_secure;
|
||||
if (db_keyword[i]) {
|
||||
if (scan_append_keyword_assignment(new_scan, &i_new,
|
||||
scan_keyword_secure,
|
||||
db_keyword[i]))
|
||||
goto err;
|
||||
}
|
||||
/* target= */
|
||||
/* targetbase= */
|
||||
/* targetgeometry= */
|
||||
|
||||
Reference in New Issue
Block a user