Skip to content

Commit

Permalink
GRUB: predict cmdline, linux and initrd lines
Browse files Browse the repository at this point in the history
Signed-off-by: Alberto Planas <[email protected]>
  • Loading branch information
aplanas committed Mar 25, 2024
1 parent b0c4c5f commit 4ec6b60
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 24 deletions.
131 changes: 115 additions & 16 deletions src/eventlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -613,11 +613,11 @@ __tpm_event_grub_file_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *pa
* omitted (eg for kernel and initrd).
*/
static bool
__tpm_event_grub_file_event_parse(tpm_event_t *ev, tpm_parsed_event_t *parsed, const char *value)
__grub_path_parse(grub_path_t *grub_path, const char *value)
{
if (value[0] == '/') {
parsed->grub_file.device = NULL;
parsed->grub_file.path = strdup(value);
grub_path->device = NULL;
grub_path->path = strdup(value);
} else if (value[0] == '(') {
char *copy = strdup(value);
char *path;
Expand All @@ -629,13 +629,35 @@ __tpm_event_grub_file_event_parse(tpm_event_t *ev, tpm_parsed_event_t *parsed, c

*path++ = '\0';

parsed->grub_file.device = strdup(copy + 1);
parsed->grub_file.path = strdup(path);
grub_path->device = strdup(copy + 1);
grub_path->path = strdup(path);
free(copy);
} else {
return false;
}

return true;
}

static char *
__grub_path_join(grub_path_t grub_path)
{
char path[PATH_MAX];

if (grub_path.device)
snprintf(path, sizeof(path), "(%s)%s", grub_path.device, grub_path.path);
else
snprintf(path, sizeof(path), "%s", grub_path.path);

return path;
}

static bool
__tpm_event_grub_file_event_parse(tpm_event_t *ev, tpm_parsed_event_t *parsed, const char *value)
{
if (!__grub_path_parse(&parsed->grub_path, value))
return false;

parsed->event_subtype = GRUB_EVENT_FILE;
parsed->destroy = __tpm_event_grub_file_destroy;
parsed->rehash = __tpm_event_grub_file_rehash;
Expand All @@ -658,21 +680,84 @@ static const char *
__tpm_event_grub_command_describe(const tpm_parsed_event_t *parsed)
{
static char buffer[128];
static char *topic = NULL;

switch (parsed->event_subtype) {
case GRUB_EVENT_COMMAND:
topic = "grub2 command";
break;
case GRUB_EVENT_COMMAND_LINUX:
topic = "grub2 linux command";
break;
case GRUB_EVENT_COMMAND_INITRD:
topic = "grub2 initrd command";
break;
case GRUB_EVENT_KERNEL_CMDLINE:
topic = "grub2 kernel cmdline";
break;
}

snprintf(buffer, sizeof(buffer), "%s \"%s\"", topic, parsed->grub_command.string);

if (parsed->event_subtype == GRUB_EVENT_COMMAND)
snprintf(buffer, sizeof(buffer), "grub2 command \"%s\"", parsed->grub_command.string);
else
snprintf(buffer, sizeof(buffer), "grub2 kernel cmdline \"%s\"", parsed->grub_command.string);
return buffer;
}

static const tpm_evdigest_t *
__tpm_event_grub_command_rehash(const tpm_event_t *ev, const tpm_parsed_event_t *parsed, tpm_event_log_rehash_ctx_t *ctx)
{
if (parsed->grub_command.string == NULL)
return NULL;
char *str = NULL;
size_t sz = 0;
const tpm_evdigest_t *digest = NULL;
grub_path_t grub_path;

switch (parsed->event_subtype) {
case GRUB_EVENT_COMMAND:
str = strdup(parsed->grub_command.string);
break;
case GRUB_EVENT_COMMAND_LINUX:
if (ctx->boot_entry && parser->grub_command.grub_path.path) {
grub_path = (grub_path_t) {
.device = parsed->grub_command.grub_path.device;
.path = ctx->boot_entry->image_path;
};
sz = snprintf(NULL, 0, "linux %s", __grub_path_join(grub_path));
str = malloc(sz + 1);
snprintf(str, sz + 1, "linux %s", __grub_path_join(grub_path));
} else
str = strdup(parsed->grub_command.string);
break;
case GRUB_EVENT_COMMAND_INITRD:
if (ctx->boot_entry && parser->grub_command.grub_path.path) {
grub_path = (grub_path_t) {
.device = parsed->grub_command.grub_path.device;
.path = ctx->boot_entry->initrd_path;
};
sz = snprintf(NULL, 0, "initrd %s", __grub_path_join(grub_path));
str = malloc(sz + 1);
snprintf(str, sz + 1, "initrd %s", __grub_path_join(grub_path));
} else
str = strdup(parsed->grub_command.string);
break;
case GRUB_EVENT_KERNEL_CMDLINE:
if (ctx->boot_entry && parser->grub_command.grub_path.path) {
grub_path = (grub_path_t) {
.device = parsed->grub_command.grub_path.device;
.path = ctx->boot_entry->image_path;
};
sz = snprintf(NULL, 0, "%s %s", __grub_path_join(grub_path), ctx->boot_entry->options);
str = malloc(sz + 1);
snprintf(str, sz + 1, "%s %s", __grub_path_join(grub_path), ctx->boot_entry->options);
} else
str = strdup(parsed->grub_command.string);
break;
}

return digest_compute(ctx->algo, parsed->grub_command.string, strlen(parsed->grub_command.string));
if (str) {
digest = digest_compute(ctx->algo, str, strlen(str));
free(str);
}

return digest;
}

/*
Expand Down Expand Up @@ -703,15 +788,25 @@ __tpm_event_grub_command_event_parse(tpm_event_t *ev, tpm_parsed_event_t *parsed
keyword = copy;
arg = copy + wordlen;

if (!strcmp(keyword, "grub_cmd: linux")) {
if (!__grub_path_parse(&parsed->grub_path, arg))
goto failed;
parsed->event_subtype = GRUB_EVENT_COMMAND_LINUX;
} else
if (!strcmp(keyword, "grub_cmd: initrd")) {
if (!__grub_path_parse(&parsed->grub_path, arg))
goto failed;
parsed->event_subtype = GRUB_EVENT_COMMAND_INITRD;
} else
if (!strcmp(keyword, "grub_cmd")) {
parsed->event_subtype = GRUB_EVENT_COMMAND;
} else
if (!strcmp(keyword, "kernel_cmdline")) {
if (!__grub_path_parse(&parsed->grub_path, arg))
goto failed;
parsed->event_subtype = GRUB_EVENT_KERNEL_CMDLINE;
} else {
free(copy);
return false;
}
} else
goto failed;

parsed->grub_command.string = strdup(arg);
for (argc = 0, s = strtok(arg, " \t"); s && argc < GRUB_COMMAND_ARGV_MAX - 1; s = strtok(NULL, " \t")) {
Expand All @@ -725,6 +820,10 @@ __tpm_event_grub_command_event_parse(tpm_event_t *ev, tpm_parsed_event_t *parsed

free(copy);
return true;

failed:
free(copy);
return false;
}

static void
Expand Down
21 changes: 14 additions & 7 deletions src/eventlog.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,12 @@ enum {
enum {
/* IPL subtypes for grub */
GRUB_EVENT_COMMAND = 0x0001,
GRUB_EVENT_FILE = 0x0002,
GRUB_EVENT_KERNEL_CMDLINE = 0x0003,
SHIM_EVENT_VARIABLE = 0x0004,
SYSTEMD_EVENT_VARIABLE = 0x0005,
GRUB_EVENT_COMMAND_LINUX = 0x0002,
GRUB_EVENT_COMMAND_INITRD = 0x0003,
GRUB_EVENT_FILE = 0x0004,
GRUB_EVENT_KERNEL_CMDLINE = 0x0005,
SHIM_EVENT_VARIABLE = 0x0006,
SYSTEMD_EVENT_VARIABLE = 0x0007,
};

enum {
Expand Down Expand Up @@ -208,6 +210,11 @@ typedef struct tpm_event_log_rehash_ctx {

#define GRUB_COMMAND_ARGV_MAX 32

typedef struct grub_path {
char * device;
char * path;
} grub_path_t;

/*
* Parsed event types
*/
Expand Down Expand Up @@ -247,12 +254,12 @@ typedef struct tpm_parsed_event {
/* for GRUB_COMMAND, GRUB_KERNEL_CMDLINE */
struct grub_command_event {
char * string;
char * argv[GRUB_COMMAND_ARGV_MAX];
char * argv[GRUB_COMMAND_ARGV_MAX];
grub_path_t grub_path;
} grub_command;

struct grub_file_event {
char * device;
char * path;
grub_path_t grub_path;
} grub_file;

struct shim_event {
Expand Down
2 changes: 1 addition & 1 deletion src/oracle.c
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ __check_stop_event(tpm_event_t *ev, int type, const char *value, tpm_event_log_s
if (parsed->event_subtype != GRUB_EVENT_FILE)
return false;

if (!(grub_arg = parsed->grub_file.path)) {
if (!(grub_arg = parsed->grub_file.grub_path.path)) {
return false;
} else {
unsigned int match_len = strlen(value);
Expand Down

0 comments on commit 4ec6b60

Please sign in to comment.