Skip to content

Commit

Permalink
zipl: add secure boot switch
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Stefan Haberland authored and hoeppnerj committed Apr 29, 2019
1 parent 7c7e10e commit 58a7462
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 23 deletions.
1 change: 1 addition & 0 deletions zipl/include/job.h
Expand Up @@ -121,6 +121,7 @@ struct job_data {
int add_files;
int dry_run;
int command_line;
int is_secure;
};


Expand Down
1 change: 1 addition & 0 deletions zipl/include/misc.h
Expand Up @@ -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))
Expand Down
3 changes: 2 additions & 1 deletion zipl/include/scan.h
Expand Up @@ -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"

Expand Down Expand Up @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions zipl/include/zipl.h
Expand Up @@ -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;

Expand Down
65 changes: 57 additions & 8 deletions zipl/src/bootmap.c
Expand Up @@ -19,6 +19,7 @@
#include <sys/types.h>

#include "lib/util_part.h"
#include "lib/util_path.h"

#include "boot.h"
#include "bootmap.h"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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));
Expand Down Expand Up @@ -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);

Expand All @@ -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 */
Expand Down Expand Up @@ -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);

Expand All @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}


Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down
42 changes: 41 additions & 1 deletion zipl/src/job.c
Expand Up @@ -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];
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
Expand Down
1 change: 0 additions & 1 deletion zipl/src/misc.c
Expand Up @@ -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 *
Expand Down
34 changes: 22 additions & 12 deletions zipl/src/scan.c
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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= */
Expand Down

0 comments on commit 58a7462

Please sign in to comment.