* [PATCH V7 2/4] tpm: Reserve the TPM final events table
From: Matthew Garrett @ 2019-05-20 20:54 UTC (permalink / raw)
To: linux-integrity
Cc: peterhuewe, jarkko.sakkinen, jgg, roberto.sassu, linux-efi,
linux-security-module, linux-kernel, tweek, bsz, Matthew Garrett
In-Reply-To: <20190520205501.177637-1-matthewgarrett@google.com>
From: Matthew Garrett <mjg59@google.com>
UEFI systems provide a boot services protocol for obtaining the TPM
event log, but this is unusable after ExitBootServices() is called.
Unfortunately ExitBootServices() itself triggers additional TPM events
that then can't be obtained using this protocol. The platform provides a
mechanism for the OS to obtain these events by recording them to a
separate UEFI configuration table which the OS can then map.
Unfortunately this table isn't self describing in terms of providing its
length, so we need to parse the events inside it to figure out how long
it is. Since the table isn't mapped at this point, we need to extend the
length calculation function to be able to map the event as it goes
along.
(Fixes by Bartosz Szczepanek <bsz@semihalf.com>)
Signed-off-by: Matthew Garrett <mjg59@google.com>
---
drivers/char/tpm/eventlog/tpm2.c | 2 +-
drivers/firmware/efi/efi.c | 2 +
drivers/firmware/efi/tpm.c | 62 ++++++++++++++++++-
include/linux/efi.h | 9 +++
include/linux/tpm_eventlog.h | 102 ++++++++++++++++++++++++++++---
5 files changed, 164 insertions(+), 13 deletions(-)
diff --git a/drivers/char/tpm/eventlog/tpm2.c b/drivers/char/tpm/eventlog/tpm2.c
index 1a977bdd3bd2..de1d9f7e5a92 100644
--- a/drivers/char/tpm/eventlog/tpm2.c
+++ b/drivers/char/tpm/eventlog/tpm2.c
@@ -40,7 +40,7 @@
static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
struct tcg_pcr_event *event_header)
{
- return __calc_tpm2_event_size(event, event_header);
+ return __calc_tpm2_event_size(event, event_header, false);
}
static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 55b77c576c42..6b11c41e0575 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -53,6 +53,7 @@ struct efi __read_mostly efi = {
.mem_attr_table = EFI_INVALID_TABLE_ADDR,
.rng_seed = EFI_INVALID_TABLE_ADDR,
.tpm_log = EFI_INVALID_TABLE_ADDR,
+ .tpm_final_log = EFI_INVALID_TABLE_ADDR,
.mem_reserve = EFI_INVALID_TABLE_ADDR,
};
EXPORT_SYMBOL(efi);
@@ -485,6 +486,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
{EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
{LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
{LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
+ {LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log},
{LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve},
{NULL_GUID, NULL, NULL},
};
diff --git a/drivers/firmware/efi/tpm.c b/drivers/firmware/efi/tpm.c
index 3a689b40ccc0..2c912ea08166 100644
--- a/drivers/firmware/efi/tpm.c
+++ b/drivers/firmware/efi/tpm.c
@@ -4,34 +4,90 @@
* Thiebaud Weksteen <tweek@google.com>
*/
+#define TPM_MEMREMAP(start, size) early_memremap(start, size)
+#define TPM_MEMUNMAP(start, size) early_memunmap(start, size)
+
#include <linux/efi.h>
#include <linux/init.h>
#include <linux/memblock.h>
+#include <linux/tpm_eventlog.h>
#include <asm/early_ioremap.h>
+int efi_tpm_final_log_size;
+EXPORT_SYMBOL(efi_tpm_final_log_size);
+
+static int tpm2_calc_event_log_size(void *data, int count, void *size_info)
+{
+ struct tcg_pcr_event2_head *header;
+ int event_size, size = 0;
+
+ while (count > 0) {
+ header = data + size;
+ event_size = __calc_tpm2_event_size(header, size_info, true);
+ if (event_size == 0)
+ return -1;
+ size += event_size;
+ count--;
+ }
+
+ return size;
+}
+
/*
* Reserve the memory associated with the TPM Event Log configuration table.
*/
int __init efi_tpm_eventlog_init(void)
{
struct linux_efi_tpm_eventlog *log_tbl;
+ struct efi_tcg2_final_events_table *final_tbl;
unsigned int tbl_size;
+ int ret = 0;
- if (efi.tpm_log == EFI_INVALID_TABLE_ADDR)
+ if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) {
+ /*
+ * We can't calculate the size of the final events without the
+ * first entry in the TPM log, so bail here.
+ */
return 0;
+ }
log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl));
if (!log_tbl) {
pr_err("Failed to map TPM Event Log table @ 0x%lx\n",
- efi.tpm_log);
+ efi.tpm_log);
efi.tpm_log = EFI_INVALID_TABLE_ADDR;
return -ENOMEM;
}
tbl_size = sizeof(*log_tbl) + log_tbl->size;
memblock_reserve(efi.tpm_log, tbl_size);
+
+ if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR)
+ goto out;
+
+ final_tbl = early_memremap(efi.tpm_final_log, sizeof(*final_tbl));
+
+ if (!final_tbl) {
+ pr_err("Failed to map TPM Final Event Log table @ 0x%lx\n",
+ efi.tpm_final_log);
+ efi.tpm_final_log = EFI_INVALID_TABLE_ADDR;
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ tbl_size = tpm2_calc_event_log_size(efi.tpm_final_log
+ + sizeof(final_tbl->version)
+ + sizeof(final_tbl->nr_events),
+ final_tbl->nr_events,
+ log_tbl->log);
+ memblock_reserve((unsigned long)final_tbl,
+ tbl_size + sizeof(*final_tbl));
+ early_memunmap(final_tbl, sizeof(*final_tbl));
+ efi_tpm_final_log_size = tbl_size;
+
+out:
early_memunmap(log_tbl, sizeof(*log_tbl));
- return 0;
+ return ret;
}
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 54357a258b35..e33c70a52a9d 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -689,6 +689,7 @@ void efi_native_runtime_setup(void);
#define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
#define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
#define LINUX_EFI_TPM_EVENT_LOG_GUID EFI_GUID(0xb7799cb0, 0xeca2, 0x4943, 0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa)
+#define LINUX_EFI_TPM_FINAL_LOG_GUID EFI_GUID(0x1e2ed096, 0x30e2, 0x4254, 0xbd, 0x89, 0x86, 0x3b, 0xbe, 0xf8, 0x23, 0x25)
#define LINUX_EFI_MEMRESERVE_TABLE_GUID EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5, 0xa8, 0xf0, 0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2)
typedef struct {
@@ -996,6 +997,7 @@ extern struct efi {
unsigned long mem_attr_table; /* memory attributes table */
unsigned long rng_seed; /* UEFI firmware random seed */
unsigned long tpm_log; /* TPM2 Event Log table */
+ unsigned long tpm_final_log; /* TPM2 Final Events Log table */
unsigned long mem_reserve; /* Linux EFI memreserve table */
efi_get_time_t *get_time;
efi_set_time_t *set_time;
@@ -1707,6 +1709,13 @@ struct linux_efi_tpm_eventlog {
extern int efi_tpm_eventlog_init(void);
+struct efi_tcg2_final_events_table {
+ u64 version;
+ u64 nr_events;
+ u8 events[];
+};
+extern int efi_tpm_final_log_size;
+
/*
* efi_runtime_service() function identifiers.
* "NONE" is used by efi_recover_from_page_fault() to check if the page
diff --git a/include/linux/tpm_eventlog.h b/include/linux/tpm_eventlog.h
index 6a86144e13f1..63238c84dc0b 100644
--- a/include/linux/tpm_eventlog.h
+++ b/include/linux/tpm_eventlog.h
@@ -112,10 +112,35 @@ struct tcg_pcr_event2_head {
struct tpm_digest digests[];
} __packed;
+struct tcg_algorithm_size {
+ u16 algorithm_id;
+ u16 algorithm_size;
+};
+
+struct tcg_algorithm_info {
+ u8 signature[16];
+ u32 platform_class;
+ u8 spec_version_minor;
+ u8 spec_version_major;
+ u8 spec_errata;
+ u8 uintn_size;
+ u32 number_of_algorithms;
+ struct tcg_algorithm_size digest_sizes[];
+};
+
+#ifndef TPM_MEMREMAP
+#define TPM_MEMREMAP(start, size) NULL
+#endif
+
+#ifndef TPM_MEMUNMAP
+#define TPM_MEMUNMAP(start, size) do{} while(0)
+#endif
+
/**
* __calc_tpm2_event_size - calculate the size of a TPM2 event log entry
* @event: Pointer to the event whose size should be calculated
* @event_header: Pointer to the initial event containing the digest lengths
+ * @do_mapping: Whether or not the event needs to be mapped
*
* The TPM2 event log format can contain multiple digests corresponding to
* separate PCR banks, and also contains a variable length of the data that
@@ -131,10 +156,13 @@ struct tcg_pcr_event2_head {
*/
static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
- struct tcg_pcr_event *event_header)
+ struct tcg_pcr_event *event_header,
+ bool do_mapping)
{
struct tcg_efi_specid_event_head *efispecid;
struct tcg_event_field *event_field;
+ void *mapping = NULL;
+ int mapping_size;
void *marker;
void *marker_start;
u32 halg_size;
@@ -148,16 +176,49 @@ static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
+ sizeof(event->count);
+ /* Map the event header */
+ if (do_mapping) {
+ mapping_size = marker - marker_start;
+ mapping = TPM_MEMREMAP((unsigned long)marker_start,
+ mapping_size);
+ if (!mapping) {
+ size = 0;
+ goto out;
+ }
+ } else {
+ mapping = marker_start;
+ }
+
+ event = (struct tcg_pcr_event2_head *)mapping;
+
efispecid = (struct tcg_efi_specid_event_head *)event_header->event;
/* Check if event is malformed. */
- if (event->count > efispecid->num_algs)
- return 0;
+ if (event->count > efispecid->num_algs) {
+ size = 0;
+ goto out;
+ }
for (i = 0; i < event->count; i++) {
halg_size = sizeof(event->digests[i].alg_id);
- memcpy(&halg, marker, halg_size);
+
+ /* Map the digest's algorithm identifier */
+ if (do_mapping) {
+ TPM_MEMUNMAP(mapping, mapping_size);
+ mapping_size = halg_size;
+ mapping = TPM_MEMREMAP((unsigned long)marker,
+ mapping_size);
+ if (!mapping) {
+ size = 0;
+ goto out;
+ }
+ } else {
+ mapping = marker;
+ }
+
+ memcpy(&halg, mapping, halg_size);
marker = marker + halg_size;
+
for (j = 0; j < efispecid->num_algs; j++) {
if (halg == efispecid->digest_sizes[j].alg_id) {
marker +=
@@ -166,18 +227,41 @@ static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
}
}
/* Algorithm without known length. Such event is unparseable. */
- if (j == efispecid->num_algs)
- return 0;
+ if (j == efispecid->num_algs) {
+ size = 0;
+ goto out;
+ }
+ }
+
+ /*
+ * Map the event size - we don't read from the event itself, so
+ * we don't need to map it
+ */
+ if (do_mapping) {
+ TPM_MEMUNMAP(mapping, mapping_size);
+ mapping_size += sizeof(event_field->event_size);
+ mapping = TPM_MEMREMAP((unsigned long)marker,
+ mapping_size);
+ if (!mapping) {
+ size = 0;
+ goto out;
+ }
+ } else {
+ mapping = marker;
}
- event_field = (struct tcg_event_field *)marker;
+ event_field = (struct tcg_event_field *)mapping;
+
marker = marker + sizeof(event_field->event_size)
+ event_field->event_size;
size = marker - marker_start;
if ((event->event_type == 0) && (event_field->event_size == 0))
- return 0;
-
+ size = 0;
+out:
+ if (do_mapping)
+ TPM_MEMUNMAP(mapping, mapping_size);
return size;
}
+
#endif
--
2.21.0.1020.gf2820cf01a-goog
^ permalink raw reply related
* [PATCH V7 4/4] efi: Attempt to get the TCG2 event log in the boot stub
From: Matthew Garrett @ 2019-05-20 20:55 UTC (permalink / raw)
To: linux-integrity
Cc: peterhuewe, jarkko.sakkinen, jgg, roberto.sassu, linux-efi,
linux-security-module, linux-kernel, tweek, bsz, Matthew Garrett
In-Reply-To: <20190520205501.177637-1-matthewgarrett@google.com>
From: Matthew Garrett <mjg59@google.com>
Right now we only attempt to obtain the SHA1-only event log. The
protocol also supports a crypto agile log format, which contains digests
for all algorithms in use. Attempt to obtain this first, and fall back
to obtaining the older format if the system doesn't support it. This is
lightly complicated by the event sizes being variable (as we don't know
in advance which algorithms are in use), and the interface giving us
back a pointer to the start of the final entry rather than a pointer to
the end of the log - as a result, we need to parse the final entry to
figure out its length in order to know how much data to copy up to the
OS.
Signed-off-by: Matthew Garrett <mjg59@google.com>
---
drivers/firmware/efi/libstub/tpm.c | 50 ++++++++++++++++++++----------
1 file changed, 33 insertions(+), 17 deletions(-)
diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c
index 5bd04f75d8d6..6b3b507a54eb 100644
--- a/drivers/firmware/efi/libstub/tpm.c
+++ b/drivers/firmware/efi/libstub/tpm.c
@@ -57,7 +57,7 @@ void efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg)
#endif
-static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
+void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg)
{
efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID;
@@ -67,6 +67,7 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
unsigned long first_entry_addr, last_entry_addr;
size_t log_size, last_entry_size;
efi_bool_t truncated;
+ int version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
void *tcg2_protocol = NULL;
status = efi_call_early(locate_protocol, &tcg2_guid, NULL,
@@ -74,14 +75,20 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
if (status != EFI_SUCCESS)
return;
- status = efi_call_proto(efi_tcg2_protocol, get_event_log, tcg2_protocol,
- EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2,
- &log_location, &log_last_entry, &truncated);
- if (status != EFI_SUCCESS)
- return;
+ status = efi_call_proto(efi_tcg2_protocol, get_event_log,
+ tcg2_protocol, version, &log_location,
+ &log_last_entry, &truncated);
+
+ if (status != EFI_SUCCESS || !log_location) {
+ version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
+ status = efi_call_proto(efi_tcg2_protocol, get_event_log,
+ tcg2_protocol, version, &log_location,
+ &log_last_entry, &truncated);
+ if (status != EFI_SUCCESS || !log_location)
+ return;
+
+ }
- if (!log_location)
- return;
first_entry_addr = (unsigned long) log_location;
/*
@@ -96,8 +103,23 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
* We need to calculate its size to deduce the full size of
* the logs.
*/
- last_entry_size = sizeof(struct tcpa_event) +
- ((struct tcpa_event *) last_entry_addr)->event_size;
+ if (version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) {
+ /*
+ * The TCG2 log format has variable length entries,
+ * and the information to decode the hash algorithms
+ * back into a size is contained in the first entry -
+ * pass a pointer to the final entry (to calculate its
+ * size) and the first entry (so we know how long each
+ * digest is)
+ */
+ last_entry_size =
+ __calc_tpm2_event_size((void *)last_entry_addr,
+ (void *)(long)log_location,
+ false);
+ } else {
+ last_entry_size = sizeof(struct tcpa_event) +
+ ((struct tcpa_event *) last_entry_addr)->event_size;
+ }
log_size = log_last_entry - log_location + last_entry_size;
}
@@ -114,7 +136,7 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
memset(log_tbl, 0, sizeof(*log_tbl) + log_size);
log_tbl->size = log_size;
- log_tbl->version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
+ log_tbl->version = version;
memcpy(log_tbl->log, (void *) first_entry_addr, log_size);
status = efi_call_early(install_configuration_table,
@@ -126,9 +148,3 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
err_free:
efi_call_early(free_pool, log_tbl);
}
-
-void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg)
-{
- /* Only try to retrieve the logs in 1.2 format. */
- efi_retrieve_tpm2_eventlog_1_2(sys_table_arg);
-}
--
2.21.0.1020.gf2820cf01a-goog
^ permalink raw reply related
* [PATCH V7 3/4] tpm: Append the final event log to the TPM event log
From: Matthew Garrett @ 2019-05-20 20:55 UTC (permalink / raw)
To: linux-integrity
Cc: peterhuewe, jarkko.sakkinen, jgg, roberto.sassu, linux-efi,
linux-security-module, linux-kernel, tweek, bsz, Matthew Garrett
In-Reply-To: <20190520205501.177637-1-matthewgarrett@google.com>
From: Matthew Garrett <mjg59@google.com>
Any events that are logged after GetEventsLog() is called are logged to
the EFI Final Events table. These events are defined as being in the
crypto agile log format, so we can just append them directly to the
existing log if it's in the same format. In theory we can also construct
old-style SHA1 log entries for devices that only return logs in that
format, but EDK2 doesn't generate the final event log in that case so
it doesn't seem worth it at the moment.
Signed-off-by: Matthew Garrett <mjg59@google.com>
---
drivers/char/tpm/eventlog/efi.c | 50 ++++++++++++++++++++++++++++-----
1 file changed, 43 insertions(+), 7 deletions(-)
diff --git a/drivers/char/tpm/eventlog/efi.c b/drivers/char/tpm/eventlog/efi.c
index 3e673ab22cb4..9179cf6bdee9 100644
--- a/drivers/char/tpm/eventlog/efi.c
+++ b/drivers/char/tpm/eventlog/efi.c
@@ -21,10 +21,13 @@
int tpm_read_log_efi(struct tpm_chip *chip)
{
+ struct efi_tcg2_final_events_table *final_tbl = NULL;
struct linux_efi_tpm_eventlog *log_tbl;
struct tpm_bios_log *log;
u32 log_size;
u8 tpm_log_version;
+ void *tmp;
+ int ret;
if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
return -ENODEV;
@@ -52,15 +55,48 @@ int tpm_read_log_efi(struct tpm_chip *chip)
/* malloc EventLog space */
log->bios_event_log = kmemdup(log_tbl->log, log_size, GFP_KERNEL);
- if (!log->bios_event_log)
- goto err_memunmap;
- log->bios_event_log_end = log->bios_event_log + log_size;
+ if (!log->bios_event_log) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ log->bios_event_log_end = log->bios_event_log + log_size;
tpm_log_version = log_tbl->version;
- memunmap(log_tbl);
- return tpm_log_version;
-err_memunmap:
+ ret = tpm_log_version;
+
+ if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR ||
+ efi_tpm_final_log_size == 0 ||
+ tpm_log_version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
+ goto out;
+
+ final_tbl = memremap(efi.tpm_final_log,
+ sizeof(*final_tbl) + efi_tpm_final_log_size,
+ MEMREMAP_WB);
+ if (!final_tbl) {
+ pr_err("Could not map UEFI TPM final log\n");
+ kfree(log->bios_event_log);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ tmp = krealloc(log->bios_event_log,
+ log_size + efi_tpm_final_log_size,
+ GFP_KERNEL);
+ if (!tmp) {
+ kfree(log->bios_event_log);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ log->bios_event_log = tmp;
+ memcpy((void *)log->bios_event_log + log_size,
+ final_tbl->events, efi_tpm_final_log_size);
+ log->bios_event_log_end = log->bios_event_log +
+ log_size + efi_tpm_final_log_size;
+
+out:
+ memunmap(final_tbl);
memunmap(log_tbl);
- return -ENOMEM;
+ return ret;
}
--
2.21.0.1020.gf2820cf01a-goog
^ permalink raw reply related
* [PATCH V7 1/4] tpm: Abstract crypto agile event size calculations
From: Matthew Garrett @ 2019-05-20 20:54 UTC (permalink / raw)
To: linux-integrity
Cc: peterhuewe, jarkko.sakkinen, jgg, roberto.sassu, linux-efi,
linux-security-module, linux-kernel, tweek, bsz, Matthew Garrett
In-Reply-To: <20190520205501.177637-1-matthewgarrett@google.com>
From: Matthew Garrett <mjg59@google.com>
We need to calculate the size of crypto agile events in multiple
locations, including in the EFI boot stub. The easiest way to do this is
to put it in a header file as an inline and leave a wrapper to ensure we
don't end up with multiple copies of it embedded in the existing code.
Signed-off-by: Matthew Garrett <mjg59@google.com>
---
drivers/char/tpm/eventlog/tpm2.c | 47 +---------------------
include/linux/tpm_eventlog.h | 68 ++++++++++++++++++++++++++++++++
2 files changed, 69 insertions(+), 46 deletions(-)
diff --git a/drivers/char/tpm/eventlog/tpm2.c b/drivers/char/tpm/eventlog/tpm2.c
index f824563fc28d..1a977bdd3bd2 100644
--- a/drivers/char/tpm/eventlog/tpm2.c
+++ b/drivers/char/tpm/eventlog/tpm2.c
@@ -40,52 +40,7 @@
static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
struct tcg_pcr_event *event_header)
{
- struct tcg_efi_specid_event_head *efispecid;
- struct tcg_event_field *event_field;
- void *marker;
- void *marker_start;
- u32 halg_size;
- size_t size;
- u16 halg;
- int i;
- int j;
-
- marker = event;
- marker_start = marker;
- marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
- + sizeof(event->count);
-
- efispecid = (struct tcg_efi_specid_event_head *)event_header->event;
-
- /* Check if event is malformed. */
- if (event->count > efispecid->num_algs)
- return 0;
-
- for (i = 0; i < event->count; i++) {
- halg_size = sizeof(event->digests[i].alg_id);
- memcpy(&halg, marker, halg_size);
- marker = marker + halg_size;
- for (j = 0; j < efispecid->num_algs; j++) {
- if (halg == efispecid->digest_sizes[j].alg_id) {
- marker +=
- efispecid->digest_sizes[j].digest_size;
- break;
- }
- }
- /* Algorithm without known length. Such event is unparseable. */
- if (j == efispecid->num_algs)
- return 0;
- }
-
- event_field = (struct tcg_event_field *)marker;
- marker = marker + sizeof(event_field->event_size)
- + event_field->event_size;
- size = marker - marker_start;
-
- if ((event->event_type == 0) && (event_field->event_size == 0))
- return 0;
-
- return size;
+ return __calc_tpm2_event_size(event, event_header);
}
static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
diff --git a/include/linux/tpm_eventlog.h b/include/linux/tpm_eventlog.h
index 81519f163211..6a86144e13f1 100644
--- a/include/linux/tpm_eventlog.h
+++ b/include/linux/tpm_eventlog.h
@@ -112,4 +112,72 @@ struct tcg_pcr_event2_head {
struct tpm_digest digests[];
} __packed;
+/**
+ * __calc_tpm2_event_size - calculate the size of a TPM2 event log entry
+ * @event: Pointer to the event whose size should be calculated
+ * @event_header: Pointer to the initial event containing the digest lengths
+ *
+ * The TPM2 event log format can contain multiple digests corresponding to
+ * separate PCR banks, and also contains a variable length of the data that
+ * was measured. This requires knowledge of how long each digest type is,
+ * and this information is contained within the first event in the log.
+ *
+ * We calculate the length by examining the number of events, and then looking
+ * at each event in turn to determine how much space is used for events in
+ * total. Once we've done this we know the offset of the data length field,
+ * and can calculate the total size of the event.
+ *
+ * Return: size of the event on success, <0 on failure
+ */
+
+static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
+ struct tcg_pcr_event *event_header)
+{
+ struct tcg_efi_specid_event_head *efispecid;
+ struct tcg_event_field *event_field;
+ void *marker;
+ void *marker_start;
+ u32 halg_size;
+ size_t size;
+ u16 halg;
+ int i;
+ int j;
+
+ marker = event;
+ marker_start = marker;
+ marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
+ + sizeof(event->count);
+
+ efispecid = (struct tcg_efi_specid_event_head *)event_header->event;
+
+ /* Check if event is malformed. */
+ if (event->count > efispecid->num_algs)
+ return 0;
+
+ for (i = 0; i < event->count; i++) {
+ halg_size = sizeof(event->digests[i].alg_id);
+ memcpy(&halg, marker, halg_size);
+ marker = marker + halg_size;
+ for (j = 0; j < efispecid->num_algs; j++) {
+ if (halg == efispecid->digest_sizes[j].alg_id) {
+ marker +=
+ efispecid->digest_sizes[j].digest_size;
+ break;
+ }
+ }
+ /* Algorithm without known length. Such event is unparseable. */
+ if (j == efispecid->num_algs)
+ return 0;
+ }
+
+ event_field = (struct tcg_event_field *)marker;
+ marker = marker + sizeof(event_field->event_size)
+ + event_field->event_size;
+ size = marker - marker_start;
+
+ if ((event->event_type == 0) && (event_field->event_size == 0))
+ return 0;
+
+ return size;
+}
#endif
--
2.21.0.1020.gf2820cf01a-goog
^ permalink raw reply related
* [PATCH V7 0/4] Add support for crypto agile logs
From: Matthew Garrett @ 2019-05-20 20:54 UTC (permalink / raw)
To: linux-integrity
Cc: peterhuewe, jarkko.sakkinen, jgg, roberto.sassu, linux-efi,
linux-security-module, linux-kernel, tweek, bsz
Identical to previous version except without the KSAN workaround - Ard
has a better solution for that.
^ permalink raw reply
* Re: [PATCH 1/4] evm: check hash algorithm passed to init_desc()
From: Mimi Zohar @ 2019-05-20 21:19 UTC (permalink / raw)
To: Roberto Sassu, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-doc, linux-security-module, linux-kernel,
silviu.vlasceanu, stable
In-Reply-To: <20190516161257.6640-1-roberto.sassu@huawei.com>
On Thu, 2019-05-16 at 18:12 +0200, Roberto Sassu wrote:
> This patch prevents memory access beyond the evm_tfm array by checking the
> validity of the index (hash algorithm) passed to init_desc(). The hash
> algorithm can be arbitrarily set if the security.ima xattr type is not
> EVM_XATTR_HMAC.
>
> Fixes: 5feeb61183dde ("evm: Allow non-SHA1 digital signatures")
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Cc: stable@vger.kernel.org
Thanks!
> ---
> security/integrity/evm/evm_crypto.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
> index e11564eb645b..82a38e801ee4 100644
> --- a/security/integrity/evm/evm_crypto.c
> +++ b/security/integrity/evm/evm_crypto.c
> @@ -89,6 +89,9 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo)
> tfm = &hmac_tfm;
> algo = evm_hmac;
> } else {
> + if (hash_algo >= HASH_ALGO__LAST)
> + return ERR_PTR(-EINVAL);
> +
> tfm = &evm_tfm[hash_algo];
> algo = hash_algo_name[hash_algo];
> }
^ permalink raw reply
* Re: [PATCH 2/4] evm: reset status in evm_inode_post_setattr()
From: Mimi Zohar @ 2019-05-20 21:19 UTC (permalink / raw)
To: Roberto Sassu, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-doc, linux-security-module, linux-kernel,
silviu.vlasceanu, stable
In-Reply-To: <20190516161257.6640-2-roberto.sassu@huawei.com>
On Thu, 2019-05-16 at 18:12 +0200, Roberto Sassu wrote:
> This patch adds a call to evm_reset_status() in evm_inode_post_setattr(),
> before security.evm is updated. The same is done in the other
> evm_inode_post_* functions.
>
> Fixes: 523b74b16bcbb ("evm: reset EVM status when file attributes change")
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Cc: stable@vger.kernel.org
Why all of a sudden do we also need to clear the EVM cached status
when modifying the file attributes? The HMAC is being recalculated.
If the reason is because of EVM portable and immutable signatures,
then the "Fixes" tag is incorrect.
Mimi
> ---
> security/integrity/evm/evm_main.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
> index b6d9f14bc234..b41c2d8a8834 100644
> --- a/security/integrity/evm/evm_main.c
> +++ b/security/integrity/evm/evm_main.c
> @@ -512,8 +512,11 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
> if (!evm_key_loaded())
> return;
>
> - if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
> + if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) {
> + evm_reset_status(dentry->d_inode);
> +
> evm_update_evmxattr(dentry, NULL, NULL, 0);
> + }
> }
>
> /*
^ permalink raw reply
* Re: [PATCH 3/4] ima: don't ignore INTEGRITY_UNKNOWN EVM status
From: Mimi Zohar @ 2019-05-20 21:20 UTC (permalink / raw)
To: Roberto Sassu, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-doc, linux-security-module, linux-kernel,
silviu.vlasceanu, stable
In-Reply-To: <20190516161257.6640-3-roberto.sassu@huawei.com>
On Thu, 2019-05-16 at 18:12 +0200, Roberto Sassu wrote:
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index 52e6fbb042cc..80e1c233656b 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -1588,6 +1588,9 @@
> Format: { "off" | "enforce" | "fix" | "log" }
> default: "enforce"
>
> + ima_appraise_req_evm
> + [IMA] require EVM for appraisal with file digests.
As much as possible we want to limit the number of new boot command
line options as possible. Is there a reason for not extending
"ima_appraise=" with "require-evm" or "enforce-evm"?
Mimi
> +
> ima_appraise_tcb [IMA] Deprecated. Use ima_policy= instead.
> The builtin appraise policy appraises all files
> owned by uid=0.
^ permalink raw reply
* Re: [PATCH 4/4] ima: only audit failed appraisal verifications
From: Mimi Zohar @ 2019-05-20 21:20 UTC (permalink / raw)
To: Roberto Sassu, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-doc, linux-security-module, linux-kernel,
silviu.vlasceanu, stable
In-Reply-To: <20190516161257.6640-4-roberto.sassu@huawei.com>
On Thu, 2019-05-16 at 18:12 +0200, Roberto Sassu wrote:
> This patch ensures that integrity_audit_msg() is called only when the
> status is not INTEGRITY_PASS.
>
> Fixes: 8606404fa555c ("ima: digital signature verification support")
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Cc: stable@vger.kernel.org
> ---
> security/integrity/ima/ima_appraise.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
> index a32ed5d7afd1..f5f4506bcb8e 100644
> --- a/security/integrity/ima/ima_appraise.c
> +++ b/security/integrity/ima/ima_appraise.c
> @@ -359,8 +359,9 @@ int ima_appraise_measurement(enum ima_hooks func,
> status = INTEGRITY_PASS;
> }
>
> - integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
> - op, cause, rc, 0);
> + if (status != INTEGRITY_PASS)
> + integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
> + filename, op, cause, rc, 0);
For some reason, the integrity verification has failed. In some
specific cases, we'll let it pass, but do we really want to remove any
indication that it failed in all cases?
Mimi
> } else {
> ima_cache_flags(iint, func);
> }
^ permalink raw reply
* [RFC 0/1] Add dm verity root hash pkcs7 sig validation.
From: Jaskaran Khurana @ 2019-05-20 21:54 UTC (permalink / raw)
To: linux-security-module, linux-kernel; +Cc: agk, snitzer, dm-devel, jmorris
This patch set adds in-kernel pkcs7 signature checking for the roothash of
the dm-verity hash tree.
The verification is to support cases where the roothash is not secured by
Trusted Boot, UEFI Secureboot or similar technologies.
One of the use cases for this is for dm-verity volumes mounted after boot,
the root hash provided during the creation of the dm-verity volume has to
be secure and thus in-kernel validation implemented here will be used
before we trust the root hash and allow the block device to be created.
Why we are doing validation in the Kernel?
The reason is to still be secure in cases where the attacker is able to
compromise the user mode application in which case the user mode validation
could not have been trusted.
The root hash signature validation in the kernel along with existing
dm-verity implementation gives a higher level of confidence in the
executable code or the protected data. Before allowing the creation of
the device mapper block device the kernel code will check that the detached
pkcs7 signature passed to it validates the roothash and the signature is
trusted by builtin keys set at kernel creation. The kernel should be
secured using Verified boot, UEFI Secure Boot or similar technologies so we
can trust it.
What about attacker mounting non dm-verity volumes to run executable
code?
This verification can be used to have a security architecture where a LSM
can enforce this verification for all the volumes and by doing this it can
ensure that all executable code runs from signed and trusted dm-verity
volumes.
Further patches will be posted that build on this and enforce this
verification based on policy for all the volumes on the system.
How are these changes tested?
veritysetup part of cryptsetup library was modified to take a optional
root-hash-sig parameter.
Commandline used to test the changes:
veritysetup open <data_device> <name> <hash_device> <root_hash>
--root-hash-sig=<root_hash_pkcs7_detached_sig>
The changes for veritysetup are in a topic branch for now at:
https://github.com/jaskarankhurana/veritysetup/tree/veritysetup_add_sig
Jaskaran Khurana (1):
Add dm verity root hash pkcs7 sig validation.
drivers/md/Kconfig | 23 ++++++
drivers/md/Makefile | 2 +-
drivers/md/dm-verity-target.c | 44 ++++++++--
drivers/md/dm-verity-verify-sig.c | 129 ++++++++++++++++++++++++++++++
drivers/md/dm-verity-verify-sig.h | 32 ++++++++
5 files changed, 222 insertions(+), 8 deletions(-)
create mode 100644 drivers/md/dm-verity-verify-sig.c
create mode 100644 drivers/md/dm-verity-verify-sig.h
--
2.17.1
^ permalink raw reply
* [RFC 1/1] Add dm verity root hash pkcs7 sig validation.
From: Jaskaran Khurana @ 2019-05-20 21:54 UTC (permalink / raw)
To: linux-security-module, linux-kernel; +Cc: agk, snitzer, dm-devel, jmorris
In-Reply-To: <20190520215422.23939-1-jaskarankhurana@linux.microsoft.com>
Adds in-kernel pkcs7 signature checking for the roothash of
the dm-verity hash tree.
The verification is to support cases where the roothash is not secured by
Trusted Boot, UEFI Secureboot or similar technologies.
One of the use cases for this is for dm-verity volumes mounted after boot,
the root hash provided during the creation of the dm-verity volume has to
be secure and thus in-kernel validation implemented here will be used
before we trust the root hash and allow the block device to be created.
The signature being provided for verification must verify the root hash and
must be trusted by the builtin keyring for verification to succeed.
Adds DM_VERITY_VERIFY_ROOTHASH_SIG: roothash verification
against the roothash signature file *if* specified, if signature file is
specified verification must succeed prior to creation of device mapper
block device.
Adds DM_VERITY_VERIFY_ROOTHASH_SIG_FORCE: roothash signature *must* be
specified for all dm verity volumes and verification must succeed prior
to creation of device mapper block device.
Signed-off-by: Jaskaran Khurana <jaskarankhurana@linux.microsoft.com>
---
drivers/md/Kconfig | 23 ++++++
drivers/md/Makefile | 2 +-
drivers/md/dm-verity-target.c | 44 ++++++++--
drivers/md/dm-verity-verify-sig.c | 129 ++++++++++++++++++++++++++++++
drivers/md/dm-verity-verify-sig.h | 32 ++++++++
5 files changed, 222 insertions(+), 8 deletions(-)
create mode 100644 drivers/md/dm-verity-verify-sig.c
create mode 100644 drivers/md/dm-verity-verify-sig.h
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index db269a348b20..da4115753f25 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -489,6 +489,29 @@ config DM_VERITY
If unsure, say N.
+config DM_VERITY_VERIFY_ROOTHASH_SIG
+ def_bool n
+ bool "Verity data device root hash signature verification support"
+ depends on DM_VERITY
+ select SYSTEM_DATA_VERIFICATION
+ help
+ The device mapper target created by DM-VERITY can be validated if the
+ pre-generated tree of cryptographic checksums passed has a pkcs#7
+ signature file that can validate the roothash of the tree.
+
+ If unsure, say N.
+
+config DM_VERITY_VERIFY_ROOTHASH_SIG_FORCE
+ def_bool n
+ bool "Forces all dm verity data device root hash should be signed"
+ depends on DM_VERITY_VERIFY_ROOTHASH_SIG
+ help
+ The device mapper target created by DM-VERITY will succeed only if the
+ pre-generated tree of cryptographic checksums passed also has a pkcs#7
+ signature file that can validate the roothash of the tree.
+
+ If unsure, say N.
+
config DM_VERITY_FEC
bool "Verity forward error correction support"
depends on DM_VERITY
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index be7a6eb92abc..8a8c142bcfe1 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -61,7 +61,7 @@ obj-$(CONFIG_DM_LOG_USERSPACE) += dm-log-userspace.o
obj-$(CONFIG_DM_ZERO) += dm-zero.o
obj-$(CONFIG_DM_RAID) += dm-raid.o
obj-$(CONFIG_DM_THIN_PROVISIONING) += dm-thin-pool.o
-obj-$(CONFIG_DM_VERITY) += dm-verity.o
+obj-$(CONFIG_DM_VERITY) += dm-verity.o dm-verity-verify-sig.o
obj-$(CONFIG_DM_CACHE) += dm-cache.o
obj-$(CONFIG_DM_CACHE_SMQ) += dm-cache-smq.o
obj-$(CONFIG_DM_ERA) += dm-era.o
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index f4c31ffaa88e..53aebfa8bc38 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -16,7 +16,7 @@
#include "dm-verity.h"
#include "dm-verity-fec.h"
-
+#include "dm-verity-verify-sig.h"
#include <linux/module.h>
#include <linux/reboot.h>
@@ -34,7 +34,11 @@
#define DM_VERITY_OPT_IGN_ZEROES "ignore_zero_blocks"
#define DM_VERITY_OPT_AT_MOST_ONCE "check_at_most_once"
-#define DM_VERITY_OPTS_MAX (2 + DM_VERITY_OPTS_FEC)
+#define DM_VERITY_OPTS_MAX (2 + DM_VERITY_OPTS_FEC + \
+ DM_VERITY_ROOT_HASH_VERIFICATION_OPTS)
+
+#define DM_VERITY_MANDATORY_ARGS 10
+
static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
@@ -855,7 +859,8 @@ static int verity_alloc_zero_digest(struct dm_verity *v)
return r;
}
-static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
+static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
+ struct dm_verity_sig_opts *verify_args)
{
int r;
unsigned argc;
@@ -904,6 +909,15 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
if (r)
return r;
continue;
+ } else if (verity_verify_is_sig_opt_arg(arg_name)) {
+ r = verity_verify_sig_parse_opt_args(as, v,
+ verify_args,
+ &argc, arg_name);
+ if (r) {
+ ti->error = "Could not parse the sig args";
+ return r;
+ }
+ continue;
}
ti->error = "Unrecognized verity feature request";
@@ -930,6 +944,7 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
{
struct dm_verity *v;
+ struct dm_verity_sig_opts verify_args = {0};
struct dm_arg_set as;
unsigned int num;
unsigned long long num_ll;
@@ -937,6 +952,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
int i;
sector_t hash_position;
char dummy;
+ char *root_hash_digest_to_validate = NULL;
v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL);
if (!v) {
@@ -956,7 +972,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
goto bad;
}
- if (argc < 10) {
+ if (argc < DM_VERITY_MANDATORY_ARGS) {
ti->error = "Not enough arguments";
r = -EINVAL;
goto bad;
@@ -1070,6 +1086,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
r = -EINVAL;
goto bad;
}
+ root_hash_digest_to_validate = argv[8];
if (strcmp(argv[9], "-")) {
v->salt_size = strlen(argv[9]) / 2;
@@ -1087,19 +1104,28 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
}
}
- argv += 10;
- argc -= 10;
+ argv += DM_VERITY_MANDATORY_ARGS;
+ argc -= DM_VERITY_MANDATORY_ARGS;
/* Optional parameters */
if (argc) {
as.argc = argc;
as.argv = argv;
- r = verity_parse_opt_args(&as, v);
+ r = verity_parse_opt_args(&as, v, &verify_args);
if (r < 0)
goto bad;
}
+ /* Root hash signature is a optional parameter*/
+ r = verity_verify_root_hash(root_hash_digest_to_validate,
+ strlen(root_hash_digest_to_validate),
+ verify_args.sig,
+ verify_args.sig_size);
+ if (r < 0) {
+ ti->error = "Root hash verification failed";
+ goto bad;
+ }
v->hash_per_block_bits =
__fls((1 << v->hash_dev_block_bits) / v->digest_size);
@@ -1165,9 +1191,13 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
ti->per_io_data_size = roundup(ti->per_io_data_size,
__alignof__(struct dm_verity_io));
+ verity_verify_sig_opts_cleanup(&verify_args);
+
return 0;
bad:
+
+ verity_verify_sig_opts_cleanup(&verify_args);
verity_dtr(ti);
return r;
diff --git a/drivers/md/dm-verity-verify-sig.c b/drivers/md/dm-verity-verify-sig.c
new file mode 100644
index 000000000000..491c84eb58ef
--- /dev/null
+++ b/drivers/md/dm-verity-verify-sig.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Author: Jaskaran Singh Khurana <jaskarankhurana@linux.microsoft.com>
+ *
+ * This file is released under the GPLv2.
+ */
+#include <linux/device-mapper.h>
+#include <linux/verification.h>
+#include "dm-verity.h"
+#include "dm-verity-verify-sig.h"
+
+#define DM_VERITY_VERIFY_ERR(s) DM_VERITY_ROOT_HASH_VERIFICATION " " s
+
+bool verity_verify_is_sig_opt_arg(const char *arg_name)
+{
+ return (!strcasecmp(arg_name,
+ DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG));
+}
+EXPORT_SYMBOL_GPL(verity_verify_is_sig_opt_arg);
+
+int verity_verify_sig_parse_opt_args(struct dm_arg_set *as,
+ struct dm_verity *v,
+ struct dm_verity_sig_opts *sig_opts,
+ unsigned int *argc,
+ const char *arg_name)
+{
+ const char *sig_size;
+ const char *sig_buf;
+ char dummy;
+ struct dm_target *ti = v->ti;
+ int r = 0;
+
+ if (*argc < DM_VERITY_ROOT_HASH_VERIFICATION_OPTS - 1) {
+ ti->error = DM_VERITY_VERIFY_ERR("sig values not specified");
+ return -EINVAL;
+ }
+
+ sig_size = dm_shift_arg(as);
+ (*argc)--;
+
+ if (strcasecmp(arg_name, DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG) ||
+ sscanf(sig_size, "%u%c",
+ &sig_opts->sig_size, &dummy) != 1) {
+ ti->error = DM_VERITY_VERIFY_ERR("invalid signature size");
+ return -EINVAL;
+ }
+
+ sig_buf = dm_shift_arg(as);
+ (*argc)--;
+
+ if (strlen(sig_buf) != sig_opts->sig_size * 2) {
+ ti->error = DM_VERITY_VERIFY_ERR("sig buffer, size: mismatch");
+ return -EINVAL;
+ }
+
+ sig_opts->sig = kmalloc(sig_opts->sig_size, GFP_KERNEL);
+ if (!sig_opts->sig) {
+ r = -ENOMEM;
+ goto end;
+ }
+
+ r = hex2bin(sig_opts->sig, sig_buf, sig_opts->sig_size);
+
+ if (r < 0) {
+ ti->error = DM_VERITY_VERIFY_ERR("invalid roothash sig buf");
+ r = -EINVAL;
+ goto end;
+ }
+
+end:
+ if (r < 0)
+ verity_verify_sig_opts_cleanup(sig_opts);
+ return r;
+}
+EXPORT_SYMBOL_GPL(verity_verify_sig_parse_opt_args);
+
+#ifdef CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG
+/*
+ * verify_verify_roothash - Verify the root hash of the verity hash device
+ * using builtin trusted keys.
+ *
+ * @root_hash: For verity, the roothash/data to be verified.
+ * @root_hash_len: Size of the roothash/data to be verified.
+ * @sig_data: The trusted signature that verifies the roothash/data.
+ * @sig_len: Size of the signature.
+ *
+ */
+int verity_verify_root_hash(const void *root_hash, size_t root_hash_len,
+ const void *sig_data, size_t sig_len)
+{
+ int r;
+
+ if (!root_hash || root_hash_len == 0)
+ return -EINVAL;
+
+ if (!sig_data || sig_len == 0) {
+ if (IS_ENABLED(CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_FORCE))
+ return -EINVAL;
+ else
+ return 0;
+ }
+
+ r = verify_pkcs7_signature(root_hash, root_hash_len, sig_data, sig_len,
+ NULL, VERIFYING_UNSPECIFIED_SIGNATURE, NULL,
+ NULL);
+ if (r < 0)
+ goto end;
+
+end:
+ return r;
+}
+#else
+int verity_verify_root_hash(const void *root_hash, size_t root_hash_len,
+ const void *sig_data, size_t sig_len)
+{
+ return 0;
+}
+#endif
+EXPORT_SYMBOL_GPL(verity_verify_root_hash);
+
+void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts)
+{
+ kfree(sig_opts->sig);
+ sig_opts->sig = NULL;
+ sig_opts->sig_size = 0;
+}
+EXPORT_SYMBOL_GPL(verity_verify_sig_opts_cleanup);
diff --git a/drivers/md/dm-verity-verify-sig.h b/drivers/md/dm-verity-verify-sig.h
new file mode 100644
index 000000000000..411808624d7e
--- /dev/null
+++ b/drivers/md/dm-verity-verify-sig.h
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Author: Jaskaran Singh Khurana <jaskarankhurana@linux.microsoft.com>
+ *
+ * This file is released under the GPLv2.
+ */
+#ifndef DM_VERITY_SIG_VERIFICATION_H
+#define DM_VERITY_SIG_VERIFICATION_H
+
+#define DM_VERITY_ROOT_HASH_VERIFICATION "DM Verity Sig Verification"
+#define DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG "root_hash_sig"
+#define DM_VERITY_ROOT_HASH_VERIFICATION_OPTS 3
+
+struct dm_verity_sig_opts {
+ unsigned int sig_size;
+ u8 *sig;
+};
+
+int verity_verify_root_hash(const void *data, size_t data_len,
+ const void *sig_data, size_t sig_len);
+
+bool verity_verify_is_sig_opt_arg(const char *arg_name);
+
+int verity_verify_sig_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
+ struct dm_verity_sig_opts *sig_opts,
+ unsigned int *argc, const char *arg_name);
+
+void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts);
+
+#endif /* DM_VERITY_SIG_VERIFICATION_H */
--
2.17.1
^ permalink raw reply related
* [PATCH] Smack: Restore the smackfsdef mount option
From: Casey Schaufler @ 2019-05-20 22:48 UTC (permalink / raw)
To: LKML, Al Viro, dhowells; +Cc: jose.bollo, casey, Linux Security Module list
The 5.1 mount system rework changed the smackfsdef mount option
to smackfsdefault. This fixes the regression by making smackfsdef
treated the same way as smackfsdefault. The change was made in
commit c3300aaf95fb4 from Al Viro.
Reported-by: Jose Bollo <jose.bollo@iot.bzh>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
security/smack/smack_lsm.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index b9abcdb36a73..915cf598e164 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -68,6 +68,7 @@ static struct {
int len;
int opt;
} smk_mount_opts[] = {
+ {"smackfsdef", sizeof("smackfsdef") - 1, Opt_fsdefault},
A(fsdefault), A(fsfloor), A(fshat), A(fsroot), A(fstransmute)
};
#undef A
@@ -682,6 +683,7 @@ static int smack_fs_context_dup(struct fs_context *fc,
}
static const struct fs_parameter_spec smack_param_specs[] = {
+ fsparam_string("fsdef", Opt_fsdefault),
fsparam_string("fsdefault", Opt_fsdefault),
fsparam_string("fsfloor", Opt_fsfloor),
fsparam_string("fshat", Opt_fshat),
^ permalink raw reply related
* [PATCH v6 0/3] add new ima hook ima_kexec_cmdline to measure kexec boot cmdline args
From: Prakhar Srivastava @ 2019-05-21 0:06 UTC (permalink / raw)
To: linux-integrity, linux-security-module, linux-kernel
Cc: mjg59, zohar, roberto.sassu, vgoyal, Prakhar Srivastava
The motive behind the patch series is to measure the boot cmdline args
used for soft reboot/kexec case.
For secure boot attestation, it is necessary to measure the kernel
command line and the kernel version. For cold boot, the boot loader
can be enhanced to measure these parameters.
(https://mjg59.dreamwidth.org/48897.html)
However, for attestation across soft reboot boundary, these values
also need to be measured during kexec_file_load.
Currently for Kexec(kexec_file_load)/soft reboot scenario the boot cmdline
args for the next kernel are not measured. For
normal case of boot/hardreboot the cmdline args are measured into the TPM.
The hash of boot command line is calculated and added to the current
running kernel's measurement list. On a soft reboot like kexec, the PCRs
are not reset to zero. Refer to commit 94c3aac567a9 ("ima: on soft
reboot, restore the measurement list") patch description.
To achive the above the patch series does the following
-adds a new ima hook: ima_kexec_cmdline which measures the cmdline args
into the ima log, behind a new ima policy entry KEXEC_CMDLINE.
-since the cmldine args cannot be appraised, a new template field(buf) is
added. The template field contains the buffer passed(cmldine args), which
can be used to appraise/attest at a later stage.
-call the ima_kexec_cmdline(...) hook from kexec_file_load call.
The ima logs need to carried over to the next kernel, which will be followed
up by other patchsets for x86_64 and arm64.
Changelog:
V6:
-add a new ima hook and policy to measure the cmdline
args(ima_kexec_cmdline)
-add a new template field buf to contain the buffer measured.
[suggested by Mimi Zohar]
add new fields to ima_event_data to store/read buffer data.
[suggested by Roberto]
-call ima_kexec_cmdline from kexec_file_load path
v5:
-add a new ima hook and policy to measure the cmdline
args(ima_kexec_cmdline)
-add a new template field buf to contain the buffer measured.
[suggested by Mimi Zohar]
-call ima_kexec_cmdline from kexec_file_load path
v4:
- per feedback from LSM community, removed the LSM hook and renamed the
IMA policy to KEXEC_CMDLINE
v3: (rebase changes to next-general)
- Add policy checks for buffer[suggested by Mimi Zohar]
- use the IMA_XATTR to add buffer
- Add kexec_cmdline used for kexec file load
- Add an LSM hook to allow usage by other LSM.[suggestd by Mimi Zohar]
v2:
- Add policy checks for buffer[suggested by Mimi Zohar]
- Add an LSM hook to allow usage by other LSM.[suggestd by Mimi Zohar]
- use the IMA_XATTR to add buffer instead of sig template
v1:
-Add kconfigs to control the ima_buffer_check
-measure the cmdline args suffixed with the kernel file name
-add the buffer to the template sig field.
Prakhar Srivastava (3):
Add a new ima hook ima_kexec_cmdline to measure cmdline args
add a new ima template field buf
call ima_kexec_cmdline to measure the cmdline args
Documentation/ABI/testing/ima_policy | 1 +
Documentation/security/IMA-templates.rst | 2 +-
include/linux/ima.h | 2 +
kernel/kexec_file.c | 8 ++-
security/integrity/ima/ima.h | 3 +
security/integrity/ima/ima_api.c | 5 +-
security/integrity/ima/ima_init.c | 2 +-
security/integrity/ima/ima_main.c | 80 +++++++++++++++++++++++
security/integrity/ima/ima_policy.c | 9 +++
security/integrity/ima/ima_template.c | 2 +
security/integrity/ima/ima_template_lib.c | 20 ++++++
security/integrity/ima/ima_template_lib.h | 4 ++
12 files changed, 131 insertions(+), 7 deletions(-)
--
2.17.1
^ permalink raw reply
* [PATCH v6 3/3] call ima_kexec_cmdline to measure the cmdline args
From: Prakhar Srivastava @ 2019-05-21 0:06 UTC (permalink / raw)
To: linux-integrity, linux-security-module, linux-kernel
Cc: mjg59, zohar, roberto.sassu, vgoyal, Prakhar Srivastava
In-Reply-To: <20190521000645.16227-1-prsriva02@gmail.com>
During soft reboot(kexec_file_load) boot cmdline args
are not measured.Thus the new kernel on load boots with
an assumption of cold reboot.
This patch makes a call to the ima hook ima_kexec_cmdline,
added in "Add a new ima hook ima_kexec_cmdline to measure
cmdline args"
to measure the boot cmdline args into the ima log.
- call ima_kexec_cmdline from kexec_file_load.
- move the call ima_add_kexec_buffer after the cmdline
args have been measured.
Signed-off-by: Prakhar Srivastava <prsriva02@gmail.com>
---
kernel/kexec_file.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index f1d0e00a3971..fcc04a230925 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -198,9 +198,6 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
return ret;
image->kernel_buf_len = size;
- /* IMA needs to pass the measurement list to the next kernel. */
- ima_add_kexec_buffer(image);
-
/* Call arch image probe handlers */
ret = arch_kexec_kernel_image_probe(image, image->kernel_buf,
image->kernel_buf_len);
@@ -241,8 +238,13 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
ret = -EINVAL;
goto out;
}
+
+ ima_kexec_cmdline(image->cmdline_buf, image->cmdline_buf_len - 1);
}
+ /* IMA needs to pass the measurement list to the next kernel. */
+ ima_add_kexec_buffer(image);
+
/* Call arch image load handlers */
ldata = arch_kexec_kernel_image_load(image);
--
2.17.1
^ permalink raw reply related
* [PATCH v6 2/3] add a new ima template field buf
From: Prakhar Srivastava @ 2019-05-21 0:06 UTC (permalink / raw)
To: linux-integrity, linux-security-module, linux-kernel
Cc: mjg59, zohar, roberto.sassu, vgoyal, Prakhar Srivastava
In-Reply-To: <20190521000645.16227-1-prsriva02@gmail.com>
A buffer(cmdline args) measured into ima cannot be appraised
without already being aware of the buffer contents.Since we
don't know what cmdline args will be passed (or need to validate
what was passed) it is not possible to appraise it.
Since hashs are non reversible the raw buffer is needed to
recompute the hash.
To regenrate the hash of the buffer and appraise the same
the contents of the buffer need to be available.
A new template field buf is added to the existing ima template
fields, which can be used to store/read the buffer itself.
Two new fields are added to the ima_event_data to carry the
buf and buf_len whenever necessary.
Updated the process_buffer_measurement call to add the buf
to the ima_event_data.
process_buffer_measurement added in "Add a new ima hook
ima_kexec_cmdline to measure cmdline args"
- Add a new template field 'buf' to be used to store/read
the buffer data.
- Added two new fields to ima_event_data to hold the buf and
buf_len [Suggested by Roberto]
-Updated process_buffer_meaurement to add the buffer to
ima_event_data
Signed-off-by: Prakhar Srivastava <prsriva02@gmail.com>
---
Documentation/security/IMA-templates.rst | 2 +-
security/integrity/ima/ima.h | 2 ++
security/integrity/ima/ima_api.c | 4 ++--
security/integrity/ima/ima_init.c | 2 +-
security/integrity/ima/ima_main.c | 4 +++-
security/integrity/ima/ima_template.c | 2 ++
security/integrity/ima/ima_template_lib.c | 20 ++++++++++++++++++++
security/integrity/ima/ima_template_lib.h | 4 ++++
8 files changed, 35 insertions(+), 5 deletions(-)
diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst
index 2cd0e273cc9a..9cddb66727ee 100644
--- a/Documentation/security/IMA-templates.rst
+++ b/Documentation/security/IMA-templates.rst
@@ -70,7 +70,7 @@ descriptors by adding their identifier to the format string
prefix is shown only if the hash algorithm is not SHA1 or MD5);
- 'n-ng': the name of the event, without size limitations;
- 'sig': the file signature.
-
+ - 'buf': the buffer data that was used to generate the hash without size limitations.
Below, there is the list of defined template descriptors:
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 226a26d8de09..4a82541dc3b6 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -65,6 +65,8 @@ struct ima_event_data {
struct evm_ima_xattr_data *xattr_value;
int xattr_len;
const char *violation;
+ const void *buf;
+ int buf_len;
};
/* IMA template field data definition */
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 800d965232e5..c12f1cd38f8f 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -134,7 +134,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
struct ima_template_entry *entry;
struct inode *inode = file_inode(file);
struct ima_event_data event_data = {iint, file, filename, NULL, 0,
- cause};
+ cause, NULL, 0};
int violation = 1;
int result;
@@ -286,7 +286,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
struct inode *inode = file_inode(file);
struct ima_template_entry *entry;
struct ima_event_data event_data = {iint, file, filename, xattr_value,
- xattr_len, NULL};
+ xattr_len, NULL, NULL, 0};
int violation = 0;
if (iint->measured_pcrs & (0x1 << pcr))
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index 6c9295449751..0c34d3100b5b 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -50,7 +50,7 @@ static int __init ima_add_boot_aggregate(void)
struct ima_template_entry *entry;
struct integrity_iint_cache tmp_iint, *iint = &tmp_iint;
struct ima_event_data event_data = {iint, NULL, boot_aggregate_name,
- NULL, 0, NULL};
+ NULL, 0, NULL, NULL, 0};
int result = -ENOMEM;
int violation = 0;
struct {
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index a88c28918a63..6c5691b65b84 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -594,7 +594,7 @@ static void process_buffer_measurement(const void *buf, int size,
struct ima_template_entry *entry = NULL;
struct integrity_iint_cache tmp_iint, *iint = &tmp_iint;
struct ima_event_data event_data = {iint, NULL, NULL,
- NULL, 0, NULL};
+ NULL, 0, NULL, NULL, 0};
struct {
struct ima_digest_data hdr;
char digest[IMA_MAX_DIGEST_SIZE];
@@ -611,6 +611,8 @@ static void process_buffer_measurement(const void *buf, int size,
memset(&hash, 0, sizeof(hash));
event_data.filename = eventname;
+ event_data.buf = buf;
+ event_data.buf_len = size;
iint->ima_hash = &hash.hdr;
iint->ima_hash->algo = ima_hash_algo;
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index b631b8bc7624..a76d1c04162a 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -43,6 +43,8 @@ static const struct ima_template_field supported_fields[] = {
.field_show = ima_show_template_string},
{.field_id = "sig", .field_init = ima_eventsig_init,
.field_show = ima_show_template_sig},
+ {.field_id = "buf", .field_init = ima_eventbuf_init,
+ .field_show = ima_show_template_buf},
};
#define MAX_TEMPLATE_NAME_LEN 15
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index 513b457ae900..43d1404141c1 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -162,6 +162,12 @@ void ima_show_template_sig(struct seq_file *m, enum ima_show_type show,
ima_show_template_field_data(m, show, DATA_FMT_HEX, field_data);
}
+void ima_show_template_buf(struct seq_file *m, enum ima_show_type show,
+ struct ima_field_data *field_data)
+{
+ ima_show_template_field_data(m, show, DATA_FMT_HEX, field_data);
+}
+
/**
* ima_parse_buf() - Parses lengths and data from an input buffer
* @bufstartp: Buffer start address.
@@ -389,3 +395,17 @@ int ima_eventsig_init(struct ima_event_data *event_data,
return ima_write_template_field_data(xattr_value, event_data->xattr_len,
DATA_FMT_HEX, field_data);
}
+
+/*
+ * ima_eventbuf_init - include the buffer(kexec-cmldine) as part of the
+ * template data.
+ */
+int ima_eventbuf_init(struct ima_event_data *event_data,
+ struct ima_field_data *field_data)
+{
+ if ((!event_data->buf) || (event_data->buf_len == 0))
+ return 0;
+
+ return ima_write_template_field_data(event_data->buf, event_data->buf_len,
+ DATA_FMT_HEX, field_data);
+}
diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h
index 6a3d8b831deb..f0178bc60c55 100644
--- a/security/integrity/ima/ima_template_lib.h
+++ b/security/integrity/ima/ima_template_lib.h
@@ -29,6 +29,8 @@ void ima_show_template_string(struct seq_file *m, enum ima_show_type show,
struct ima_field_data *field_data);
void ima_show_template_sig(struct seq_file *m, enum ima_show_type show,
struct ima_field_data *field_data);
+void ima_show_template_buf(struct seq_file *m, enum ima_show_type show,
+ struct ima_field_data *field_data);
int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp,
int maxfields, struct ima_field_data *fields, int *curfields,
unsigned long *len_mask, int enforce_mask, char *bufname);
@@ -42,4 +44,6 @@ int ima_eventname_ng_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
int ima_eventsig_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
+int ima_eventbuf_init(struct ima_event_data *event_data,
+ struct ima_field_data *field_data);
#endif /* __LINUX_IMA_TEMPLATE_LIB_H */
--
2.17.1
^ permalink raw reply related
* [PATCH v6 1/3] Add a new ima hook ima_kexec_cmdline to measure cmdline args
From: Prakhar Srivastava @ 2019-05-21 0:06 UTC (permalink / raw)
To: linux-integrity, linux-security-module, linux-kernel
Cc: mjg59, zohar, roberto.sassu, vgoyal, Prakhar Srivastava
In-Reply-To: <20190521000645.16227-1-prsriva02@gmail.com>
Currently during kexec_file_load(soft reboot) the cmdline args
passed are not measured and the PCR values are not reset.
This results in the new kernel to assume a secure boot was
followed. The boot args used to launch the new kernel need to be
measured and carried over to the next kernel to be used for
attestation. IMA supports only measuring files, no functionality
exists to measure a buffer(kexec cmdline).
This change adds a new functionality to measure buffers
process_buffer_measurement which uses the hash of the buffer
instead of file hash to add an entry in the ima log.
A new ima hook ima_kexec_cmdline is also defined which calls
into process_buffer_measurement to add the kexec_cmdline args
to the log.
A new policy KEXEC_CMDLINE is also defined to control measuring the
kexec_cmdline buffer.
This patch only adds IMA_MEASURE as a supported functionality.
- A new ima hook ima_kexec_cmdline is defined to be called by the
kexec code.
- A new function process_buffer_measurement is defined to measure
the buffer hash into the ima log.
- A new func policy KEXEC_CMDLINE is defined to control the measurement.
Signed-off-by: Prakhar Srivastava <prsriva02@gmail.com>
---
Documentation/ABI/testing/ima_policy | 1 +
include/linux/ima.h | 2 +
security/integrity/ima/ima.h | 1 +
security/integrity/ima/ima_api.c | 1 +
security/integrity/ima/ima_main.c | 77 ++++++++++++++++++++++++++++
security/integrity/ima/ima_policy.c | 9 ++++
6 files changed, 91 insertions(+)
diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index 74c6702de74e..62e7cd687e9c 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -29,6 +29,7 @@ Description:
base: func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK]
[FIRMWARE_CHECK]
[KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK]
+ [KEXEC_CMDLINE]
mask:= [[^]MAY_READ] [[^]MAY_WRITE] [[^]MAY_APPEND]
[[^]MAY_EXEC]
fsmagic:= hex value
diff --git a/include/linux/ima.h b/include/linux/ima.h
index dc12fbcf484c..2e2c77280be8 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -26,6 +26,7 @@ extern int ima_read_file(struct file *file, enum kernel_read_file_id id);
extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
enum kernel_read_file_id id);
extern void ima_post_path_mknod(struct dentry *dentry);
+extern void ima_kexec_cmdline(const void *buf, int size);
#ifdef CONFIG_IMA_KEXEC
extern void ima_add_kexec_buffer(struct kimage *image);
@@ -92,6 +93,7 @@ static inline void ima_post_path_mknod(struct dentry *dentry)
return;
}
+static inline void ima_kexec_cmdline(const void *buf, int size) {}
#endif /* CONFIG_IMA */
#ifndef CONFIG_IMA_KEXEC
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index d213e835c498..226a26d8de09 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -184,6 +184,7 @@ static inline unsigned long ima_hash_key(u8 *digest)
hook(KEXEC_KERNEL_CHECK) \
hook(KEXEC_INITRAMFS_CHECK) \
hook(POLICY_CHECK) \
+ hook(KEXEC_CMDLINE) \
hook(MAX_CHECK)
#define __ima_hook_enumify(ENUM) ENUM,
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index c7505fb122d4..800d965232e5 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -169,6 +169,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
* subj=, obj=, type=, func=, mask=, fsmagic=
* subj,obj, and type: are LSM specific.
* func: FILE_CHECK | BPRM_CHECK | CREDS_CHECK | MMAP_CHECK | MODULE_CHECK
+ * | KEXEC_CMDLINE
* mask: contains the permission mask
* fsmagic: hex value
*
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 357edd140c09..a88c28918a63 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -576,6 +576,83 @@ int ima_load_data(enum kernel_load_data_id id)
return 0;
}
+/*
+ * process_buffer_measurement - Measure the buffer to ima log.
+ * @buf: pointer to the buffer that needs to be added to the log.
+ * @size: size of buffer(in bytes).
+ * @eventname: event name to be used for the buffer entry.
+ * @cred: a pointer to a credentials structure for user validation.
+ * @secid: the secid of the task to be validated.
+ *
+ * Based on policy, the buffer is measured into the ima log.
+ */
+static void process_buffer_measurement(const void *buf, int size,
+ const char *eventname, const struct cred *cred,
+ u32 secid)
+{
+ int ret = 0;
+ struct ima_template_entry *entry = NULL;
+ struct integrity_iint_cache tmp_iint, *iint = &tmp_iint;
+ struct ima_event_data event_data = {iint, NULL, NULL,
+ NULL, 0, NULL};
+ struct {
+ struct ima_digest_data hdr;
+ char digest[IMA_MAX_DIGEST_SIZE];
+ } hash;
+ int violation = 0;
+ int pcr = CONFIG_IMA_MEASURE_PCR_IDX;
+ int action = 0;
+
+ action = ima_get_action(NULL, cred, secid, 0, KEXEC_CMDLINE, &pcr);
+ if (!(action & IMA_MEASURE))
+ goto out;
+
+ memset(iint, 0, sizeof(*iint));
+ memset(&hash, 0, sizeof(hash));
+
+ event_data.filename = eventname;
+
+ iint->ima_hash = &hash.hdr;
+ iint->ima_hash->algo = ima_hash_algo;
+ iint->ima_hash->length = hash_digest_size[ima_hash_algo];
+
+ ret = ima_calc_buffer_hash(buf, size, iint->ima_hash);
+ if (ret < 0)
+ goto out;
+
+ ret = ima_alloc_init_template(&event_data, &entry);
+ if (ret < 0)
+ goto out;
+
+ if (action & IMA_MEASURE)
+ ret = ima_store_template(entry, violation, NULL, buf, pcr);
+
+ if (ret < 0) {
+ ima_free_template_entry(entry);
+ }
+
+out:
+ return;
+}
+
+/**
+ * ima_kexec_cmdline - measure kexec cmdline boot args
+ * @buf: pointer to buffer
+ * @size: size of buffer
+ *
+ * Buffers can only be measured, not appraised.
+ */
+void ima_kexec_cmdline(const void *buf, int size)
+{
+ u32 secid;
+
+ if (buf && size != 0) {
+ security_task_getsecid(current, &secid);
+ process_buffer_measurement(buf, size, "kexec-cmdline",
+ current_cred(), secid);
+ }
+}
+
static int __init init_ima(void)
{
int error;
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index e0cc323f948f..413e5921b248 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -291,6 +291,13 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
{
int i;
+ /* only incase of KEXEC_CMDLINE, inode is NULL */
+ if (func == KEXEC_CMDLINE) {
+ if ((rule->flags & IMA_FUNC) &&
+ (rule->func == func) && (!inode))
+ return true;
+ return false;
+ }
if ((rule->flags & IMA_FUNC) &&
(rule->func != func && func != POST_SETATTR))
return false;
@@ -869,6 +876,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
entry->func = KEXEC_INITRAMFS_CHECK;
else if (strcmp(args[0].from, "POLICY_CHECK") == 0)
entry->func = POLICY_CHECK;
+ else if (strcmp(args[0].from, "KEXEC_CMDLINE") == 0)
+ entry->func = KEXEC_CMDLINE;
else
result = -EINVAL;
if (!result)
--
2.17.1
^ permalink raw reply related
* Re: [RFC 1/1] Add dm verity root hash pkcs7 sig validation.
From: Singh, Balbir @ 2019-05-21 5:12 UTC (permalink / raw)
To: Jaskaran Khurana, linux-security-module, linux-kernel
Cc: agk, snitzer, dm-devel, jmorris
In-Reply-To: <20190520215422.23939-2-jaskarankhurana@linux.microsoft.com>
On 5/21/19 7:54 AM, Jaskaran Khurana wrote:
> Adds in-kernel pkcs7 signature checking for the roothash of
> the dm-verity hash tree.
>
> The verification is to support cases where the roothash is not secured by
> Trusted Boot, UEFI Secureboot or similar technologies.
> One of the use cases for this is for dm-verity volumes mounted after boot,
> the root hash provided during the creation of the dm-verity volume has to
> be secure and thus in-kernel validation implemented here will be used
> before we trust the root hash and allow the block device to be created.
>
The first patch was your cover letter, I'd suggest name it that way in
the subject.
> The signature being provided for verification must verify the root hash and
> must be trusted by the builtin keyring for verification to succeed.
>
> Adds DM_VERITY_VERIFY_ROOTHASH_SIG: roothash verification
> against the roothash signature file *if* specified, if signature file is
> specified verification must succeed prior to creation of device mapper
> block device.
>
> Adds DM_VERITY_VERIFY_ROOTHASH_SIG_FORCE: roothash signature *must* be
> specified for all dm verity volumes and verification must succeed prior
> to creation of device mapper block device.
>
> Signed-off-by: Jaskaran Khurana <jaskarankhurana@linux.microsoft.com>
> ---
> drivers/md/Kconfig | 23 ++++++
> drivers/md/Makefile | 2 +-
> drivers/md/dm-verity-target.c | 44 ++++++++--
> drivers/md/dm-verity-verify-sig.c | 129 ++++++++++++++++++++++++++++++
> drivers/md/dm-verity-verify-sig.h | 32 ++++++++
> 5 files changed, 222 insertions(+), 8 deletions(-)
> create mode 100644 drivers/md/dm-verity-verify-sig.c
> create mode 100644 drivers/md/dm-verity-verify-sig.h
>
> diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
> index db269a348b20..da4115753f25 100644
> --- a/drivers/md/Kconfig
> +++ b/drivers/md/Kconfig
> @@ -489,6 +489,29 @@ config DM_VERITY
>
> If unsure, say N.
>
> +config DM_VERITY_VERIFY_ROOTHASH_SIG
> + def_bool n
> + bool "Verity data device root hash signature verification support"
> + depends on DM_VERITY
> + select SYSTEM_DATA_VERIFICATION
> + help
> + The device mapper target created by DM-VERITY can be validated if the
> + pre-generated tree of cryptographic checksums passed has a pkcs#7
> + signature file that can validate the roothash of the tree.
> +
> + If unsure, say N.
> +
> +config DM_VERITY_VERIFY_ROOTHASH_SIG_FORCE
> + def_bool n
> + bool "Forces all dm verity data device root hash should be signed"
> + depends on DM_VERITY_VERIFY_ROOTHASH_SIG
> + help
> + The device mapper target created by DM-VERITY will succeed only if the
> + pre-generated tree of cryptographic checksums passed also has a pkcs#7
> + signature file that can validate the roothash of the tree.
> +
> + If unsure, say N.
> +
> config DM_VERITY_FEC
> bool "Verity forward error correction support"
> depends on DM_VERITY
> diff --git a/drivers/md/Makefile b/drivers/md/Makefile
> index be7a6eb92abc..8a8c142bcfe1 100644
> --- a/drivers/md/Makefile
> +++ b/drivers/md/Makefile
> @@ -61,7 +61,7 @@ obj-$(CONFIG_DM_LOG_USERSPACE) += dm-log-userspace.o
> obj-$(CONFIG_DM_ZERO) += dm-zero.o
> obj-$(CONFIG_DM_RAID) += dm-raid.o
> obj-$(CONFIG_DM_THIN_PROVISIONING) += dm-thin-pool.o
> -obj-$(CONFIG_DM_VERITY) += dm-verity.o
> +obj-$(CONFIG_DM_VERITY) += dm-verity.o dm-verity-verify-sig.o
> obj-$(CONFIG_DM_CACHE) += dm-cache.o
> obj-$(CONFIG_DM_CACHE_SMQ) += dm-cache-smq.o
> obj-$(CONFIG_DM_ERA) += dm-era.o
> diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
> index f4c31ffaa88e..53aebfa8bc38 100644
> --- a/drivers/md/dm-verity-target.c
> +++ b/drivers/md/dm-verity-target.c
> @@ -16,7 +16,7 @@
>
> #include "dm-verity.h"
> #include "dm-verity-fec.h"
> -
> +#include "dm-verity-verify-sig.h"
> #include <linux/module.h>
> #include <linux/reboot.h>
>
> @@ -34,7 +34,11 @@
> #define DM_VERITY_OPT_IGN_ZEROES "ignore_zero_blocks"
> #define DM_VERITY_OPT_AT_MOST_ONCE "check_at_most_once"
>
> -#define DM_VERITY_OPTS_MAX (2 + DM_VERITY_OPTS_FEC)
> +#define DM_VERITY_OPTS_MAX (2 + DM_VERITY_OPTS_FEC + \
> + DM_VERITY_ROOT_HASH_VERIFICATION_OPTS)
> +
> +#define DM_VERITY_MANDATORY_ARGS 10
> +
>
> static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
>
> @@ -855,7 +859,8 @@ static int verity_alloc_zero_digest(struct dm_verity *v)
> return r;
> }
>
> -static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
> +static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
> + struct dm_verity_sig_opts *verify_args)
> {
> int r;
> unsigned argc;
> @@ -904,6 +909,15 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
> if (r)
> return r;
> continue;
> + } else if (verity_verify_is_sig_opt_arg(arg_name)) {
> + r = verity_verify_sig_parse_opt_args(as, v,
> + verify_args,
> + &argc, arg_name);
> + if (r) {
> + ti->error = "Could not parse the sig args";
> + return r;
> + }
> + continue;
> }
>
> ti->error = "Unrecognized verity feature request";
> @@ -930,6 +944,7 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
> static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
> {
> struct dm_verity *v;
> + struct dm_verity_sig_opts verify_args = {0};
> struct dm_arg_set as;
> unsigned int num;
> unsigned long long num_ll;
> @@ -937,6 +952,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
> int i;
> sector_t hash_position;
> char dummy;
> + char *root_hash_digest_to_validate = NULL;
>
> v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL);
> if (!v) {
> @@ -956,7 +972,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
> goto bad;
> }
>
> - if (argc < 10) {
> + if (argc < DM_VERITY_MANDATORY_ARGS) {
> ti->error = "Not enough arguments";
> r = -EINVAL;
> goto bad;
> @@ -1070,6 +1086,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
> r = -EINVAL;
> goto bad;
> }
> + root_hash_digest_to_validate = argv[8];
>
> if (strcmp(argv[9], "-")) {
> v->salt_size = strlen(argv[9]) / 2;
> @@ -1087,19 +1104,28 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
> }
> }
>
> - argv += 10;
> - argc -= 10;
> + argv += DM_VERITY_MANDATORY_ARGS;
> + argc -= DM_VERITY_MANDATORY_ARGS;
This cleanup should be in a separate patch in the series
>
> /* Optional parameters */
> if (argc) {
> as.argc = argc;
> as.argv = argv;
>
> - r = verity_parse_opt_args(&as, v);
> + r = verity_parse_opt_args(&as, v, &verify_args);
> if (r < 0)
> goto bad;
> }
>
> + /* Root hash signature is a optional parameter*/
> + r = verity_verify_root_hash(root_hash_digest_to_validate,
> + strlen(root_hash_digest_to_validate),
> + verify_args.sig,
> + verify_args.sig_size);
> + if (r < 0) {
> + ti->error = "Root hash verification failed";
> + goto bad;
> + }
> v->hash_per_block_bits =
> __fls((1 << v->hash_dev_block_bits) / v->digest_size);
>
> @@ -1165,9 +1191,13 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
> ti->per_io_data_size = roundup(ti->per_io_data_size,
> __alignof__(struct dm_verity_io));
>
> + verity_verify_sig_opts_cleanup(&verify_args);
> +
> return 0;
>
> bad:
> +
> + verity_verify_sig_opts_cleanup(&verify_args);
> verity_dtr(ti);
>
> return r;
> diff --git a/drivers/md/dm-verity-verify-sig.c b/drivers/md/dm-verity-verify-sig.c
> new file mode 100644
> index 000000000000..491c84eb58ef
> --- /dev/null
> +++ b/drivers/md/dm-verity-verify-sig.c
> @@ -0,0 +1,129 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2019 Microsoft Corporation.
> + *
> + * Author: Jaskaran Singh Khurana <jaskarankhurana@linux.microsoft.com>
> + *
> + * This file is released under the GPLv2.
> + */
> +#include <linux/device-mapper.h>
> +#include <linux/verification.h>
> +#include "dm-verity.h"
> +#include "dm-verity-verify-sig.h"
> +
> +#define DM_VERITY_VERIFY_ERR(s) DM_VERITY_ROOT_HASH_VERIFICATION " " s
> +
> +bool verity_verify_is_sig_opt_arg(const char *arg_name)
> +{
> + return (!strcasecmp(arg_name,
> + DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG));
> +}
> +EXPORT_SYMBOL_GPL(verity_verify_is_sig_opt_arg);
> +
> +int verity_verify_sig_parse_opt_args(struct dm_arg_set *as,
> + struct dm_verity *v,
> + struct dm_verity_sig_opts *sig_opts,
> + unsigned int *argc,
> + const char *arg_name)
> +{
> + const char *sig_size;
> + const char *sig_buf;
> + char dummy;
> + struct dm_target *ti = v->ti;
> + int r = 0;
> +
> + if (*argc < DM_VERITY_ROOT_HASH_VERIFICATION_OPTS - 1) {
> + ti->error = DM_VERITY_VERIFY_ERR("sig values not specified");
Can you can sig values to Signature values for readability
> + return -EINVAL;
> + }
> +
> + sig_size = dm_shift_arg(as);
> + (*argc)--;
> +
> + if (strcasecmp(arg_name, DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG) ||
> + sscanf(sig_size, "%u%c",
> + &sig_opts->sig_size, &dummy) != 1) {
> + ti->error = DM_VERITY_VERIFY_ERR("invalid signature size");
Not sure why this is the best way to verifify the signature size
> + return -EINVAL;
> + }
> +
> + sig_buf = dm_shift_arg(as);
> + (*argc)--;
> +
> + if (strlen(sig_buf) != sig_opts->sig_size * 2) {
> + ti->error = DM_VERITY_VERIFY_ERR("sig buffer, size: mismatch");
> + return -EINVAL;
> + }
Can you explain the sig_opts->sig_size * 2 magic with a comment?
> +
> + sig_opts->sig = kmalloc(sig_opts->sig_size, GFP_KERNEL);
> + if (!sig_opts->sig) {
> + r = -ENOMEM;
> + goto end;
Good to check for NULL, but GFP_KERNEL will OOM if allocations fail
> + }
> +
> + r = hex2bin(sig_opts->sig, sig_buf, sig_opts->sig_size);
> +
> + if (r < 0) {
> + ti->error = DM_VERITY_VERIFY_ERR("invalid roothash sig buf");
> + r = -EINVAL;
> + goto end;
> + }
> +
> +end:
> + if (r < 0)
> + verity_verify_sig_opts_cleanup(sig_opts);
> + return r;
> +}
> +EXPORT_SYMBOL_GPL(verity_verify_sig_parse_opt_args);
> +
> +#ifdef CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG
> +/*
> + * verify_verify_roothash - Verify the root hash of the verity hash device
> + * using builtin trusted keys.
> + *
> + * @root_hash: For verity, the roothash/data to be verified.
> + * @root_hash_len: Size of the roothash/data to be verified.
> + * @sig_data: The trusted signature that verifies the roothash/data.
> + * @sig_len: Size of the signature.
> + *
> + */
> +int verity_verify_root_hash(const void *root_hash, size_t root_hash_len,
> + const void *sig_data, size_t sig_len)
> +{
> + int r;
ret?
> +
> + if (!root_hash || root_hash_len == 0)
> + return -EINVAL;
> +
> + if (!sig_data || sig_len == 0) {
> + if (IS_ENABLED(CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_FORCE))
> + return -EINVAL;
> + else
> + return 0;
> + }
> +
> + r = verify_pkcs7_signature(root_hash, root_hash_len, sig_data, sig_len,
> + NULL, VERIFYING_UNSPECIFIED_SIGNATURE, NULL,
> + NULL);
> + if (r < 0)
> + goto end;
> +
> +end:
goto end makes no sense if r is right down here, have you missed some code here?
Otherwise you can just remove the 4 lines above.
> + return r;
> +}
> +#else
> +int verity_verify_root_hash(const void *root_hash, size_t root_hash_len,
> + const void *sig_data, size_t sig_len)
> +{
> + return 0;
> +}
> +#endif
> +EXPORT_SYMBOL_GPL(verity_verify_root_hash);
> +
> +void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts)
> +{
> + kfree(sig_opts->sig);
> + sig_opts->sig = NULL;
> + sig_opts->sig_size = 0;
> +}
> +EXPORT_SYMBOL_GPL(verity_verify_sig_opts_cleanup);
> diff --git a/drivers/md/dm-verity-verify-sig.h b/drivers/md/dm-verity-verify-sig.h
> new file mode 100644
> index 000000000000..411808624d7e
> --- /dev/null
> +++ b/drivers/md/dm-verity-verify-sig.h
> @@ -0,0 +1,32 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2019 Microsoft Corporation.
> + *
> + * Author: Jaskaran Singh Khurana <jaskarankhurana@linux.microsoft.com>
> + *
> + * This file is released under the GPLv2.
> + */
> +#ifndef DM_VERITY_SIG_VERIFICATION_H
> +#define DM_VERITY_SIG_VERIFICATION_H
> +
> +#define DM_VERITY_ROOT_HASH_VERIFICATION "DM Verity Sig Verification"
> +#define DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG "root_hash_sig"
> +#define DM_VERITY_ROOT_HASH_VERIFICATION_OPTS 3
> +
> +struct dm_verity_sig_opts {
> + unsigned int sig_size;
> + u8 *sig;
> +};
> +
> +int verity_verify_root_hash(const void *data, size_t data_len,
> + const void *sig_data, size_t sig_len);
> +
> +bool verity_verify_is_sig_opt_arg(const char *arg_name);
> +
> +int verity_verify_sig_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
> + struct dm_verity_sig_opts *sig_opts,
> + unsigned int *argc, const char *arg_name);
> +
> +void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts);
> +
> +#endif /* DM_VERITY_SIG_VERIFICATION_H */
Balbir Singh.
>
^ permalink raw reply
* Re: [PATCH v6 2/3] add a new ima template field buf
From: Roberto Sassu @ 2019-05-21 7:11 UTC (permalink / raw)
To: Prakhar Srivastava, linux-integrity, linux-security-module,
linux-kernel
Cc: mjg59, zohar, vgoyal
In-Reply-To: <20190521000645.16227-3-prsriva02@gmail.com>
On 5/21/2019 2:06 AM, Prakhar Srivastava wrote:
> A buffer(cmdline args) measured into ima cannot be appraised
> without already being aware of the buffer contents.Since we
Space before 'Since'.
> don't know what cmdline args will be passed (or need to validate
> what was passed) it is not possible to appraise it.
>
> Since hashs are non reversible the raw buffer is needed to
> recompute the hash.
Hashes.
> To regenrate the hash of the buffer and appraise the same
Regenerate.
> the contents of the buffer need to be available.
>
> A new template field buf is added to the existing ima template
> fields, which can be used to store/read the buffer itself.
> Two new fields are added to the ima_event_data to carry the
> buf and buf_len whenever necessary.
>
> Updated the process_buffer_measurement call to add the buf
> to the ima_event_data.
> process_buffer_measurement added in "Add a new ima hook
> ima_kexec_cmdline to measure cmdline args"
>
> - Add a new template field 'buf' to be used to store/read
> the buffer data.
> - Added two new fields to ima_event_data to hold the buf and
> buf_len [Suggested by Roberto]
> -Updated process_buffer_meaurement to add the buffer to
Space after -.
> ima_event_data
>
> Signed-off-by: Prakhar Srivastava <prsriva02@gmail.com>
> ---
> Documentation/security/IMA-templates.rst | 2 +-
> security/integrity/ima/ima.h | 2 ++
> security/integrity/ima/ima_api.c | 4 ++--
> security/integrity/ima/ima_init.c | 2 +-
> security/integrity/ima/ima_main.c | 4 +++-
> security/integrity/ima/ima_template.c | 2 ++
> security/integrity/ima/ima_template_lib.c | 20 ++++++++++++++++++++
> security/integrity/ima/ima_template_lib.h | 4 ++++
> 8 files changed, 35 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/security/IMA-templates.rst b/Documentation/security/IMA-templates.rst
> index 2cd0e273cc9a..9cddb66727ee 100644
> --- a/Documentation/security/IMA-templates.rst
> +++ b/Documentation/security/IMA-templates.rst
> @@ -70,7 +70,7 @@ descriptors by adding their identifier to the format string
> prefix is shown only if the hash algorithm is not SHA1 or MD5);
> - 'n-ng': the name of the event, without size limitations;
> - 'sig': the file signature.
; instead of .
> -
Keep the new line.
Apart from that, the patch looks good to me.
Reviewed-by: Roberto Sassu <roberto.sassu@huawei.com>
Roberto
> + - 'buf': the buffer data that was used to generate the hash without size limitations.
>
> Below, there is the list of defined template descriptors:
>
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index 226a26d8de09..4a82541dc3b6 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -65,6 +65,8 @@ struct ima_event_data {
> struct evm_ima_xattr_data *xattr_value;
> int xattr_len;
> const char *violation;
> + const void *buf;
> + int buf_len;
> };
>
> /* IMA template field data definition */
> diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
> index 800d965232e5..c12f1cd38f8f 100644
> --- a/security/integrity/ima/ima_api.c
> +++ b/security/integrity/ima/ima_api.c
> @@ -134,7 +134,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
> struct ima_template_entry *entry;
> struct inode *inode = file_inode(file);
> struct ima_event_data event_data = {iint, file, filename, NULL, 0,
> - cause};
> + cause, NULL, 0};
> int violation = 1;
> int result;
>
> @@ -286,7 +286,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
> struct inode *inode = file_inode(file);
> struct ima_template_entry *entry;
> struct ima_event_data event_data = {iint, file, filename, xattr_value,
> - xattr_len, NULL};
> + xattr_len, NULL, NULL, 0};
> int violation = 0;
>
> if (iint->measured_pcrs & (0x1 << pcr))
> diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
> index 6c9295449751..0c34d3100b5b 100644
> --- a/security/integrity/ima/ima_init.c
> +++ b/security/integrity/ima/ima_init.c
> @@ -50,7 +50,7 @@ static int __init ima_add_boot_aggregate(void)
> struct ima_template_entry *entry;
> struct integrity_iint_cache tmp_iint, *iint = &tmp_iint;
> struct ima_event_data event_data = {iint, NULL, boot_aggregate_name,
> - NULL, 0, NULL};
> + NULL, 0, NULL, NULL, 0};
> int result = -ENOMEM;
> int violation = 0;
> struct {
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index a88c28918a63..6c5691b65b84 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -594,7 +594,7 @@ static void process_buffer_measurement(const void *buf, int size,
> struct ima_template_entry *entry = NULL;
> struct integrity_iint_cache tmp_iint, *iint = &tmp_iint;
> struct ima_event_data event_data = {iint, NULL, NULL,
> - NULL, 0, NULL};
> + NULL, 0, NULL, NULL, 0};
> struct {
> struct ima_digest_data hdr;
> char digest[IMA_MAX_DIGEST_SIZE];
> @@ -611,6 +611,8 @@ static void process_buffer_measurement(const void *buf, int size,
> memset(&hash, 0, sizeof(hash));
>
> event_data.filename = eventname;
> + event_data.buf = buf;
> + event_data.buf_len = size;
>
> iint->ima_hash = &hash.hdr;
> iint->ima_hash->algo = ima_hash_algo;
> diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
> index b631b8bc7624..a76d1c04162a 100644
> --- a/security/integrity/ima/ima_template.c
> +++ b/security/integrity/ima/ima_template.c
> @@ -43,6 +43,8 @@ static const struct ima_template_field supported_fields[] = {
> .field_show = ima_show_template_string},
> {.field_id = "sig", .field_init = ima_eventsig_init,
> .field_show = ima_show_template_sig},
> + {.field_id = "buf", .field_init = ima_eventbuf_init,
> + .field_show = ima_show_template_buf},
> };
> #define MAX_TEMPLATE_NAME_LEN 15
>
> diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
> index 513b457ae900..43d1404141c1 100644
> --- a/security/integrity/ima/ima_template_lib.c
> +++ b/security/integrity/ima/ima_template_lib.c
> @@ -162,6 +162,12 @@ void ima_show_template_sig(struct seq_file *m, enum ima_show_type show,
> ima_show_template_field_data(m, show, DATA_FMT_HEX, field_data);
> }
>
> +void ima_show_template_buf(struct seq_file *m, enum ima_show_type show,
> + struct ima_field_data *field_data)
> +{
> + ima_show_template_field_data(m, show, DATA_FMT_HEX, field_data);
> +}
> +
> /**
> * ima_parse_buf() - Parses lengths and data from an input buffer
> * @bufstartp: Buffer start address.
> @@ -389,3 +395,17 @@ int ima_eventsig_init(struct ima_event_data *event_data,
> return ima_write_template_field_data(xattr_value, event_data->xattr_len,
> DATA_FMT_HEX, field_data);
> }
> +
> +/*
> + * ima_eventbuf_init - include the buffer(kexec-cmldine) as part of the
> + * template data.
> + */
> +int ima_eventbuf_init(struct ima_event_data *event_data,
> + struct ima_field_data *field_data)
> +{
> + if ((!event_data->buf) || (event_data->buf_len == 0))
> + return 0;
> +
> + return ima_write_template_field_data(event_data->buf, event_data->buf_len,
> + DATA_FMT_HEX, field_data);
> +}
> diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h
> index 6a3d8b831deb..f0178bc60c55 100644
> --- a/security/integrity/ima/ima_template_lib.h
> +++ b/security/integrity/ima/ima_template_lib.h
> @@ -29,6 +29,8 @@ void ima_show_template_string(struct seq_file *m, enum ima_show_type show,
> struct ima_field_data *field_data);
> void ima_show_template_sig(struct seq_file *m, enum ima_show_type show,
> struct ima_field_data *field_data);
> +void ima_show_template_buf(struct seq_file *m, enum ima_show_type show,
> + struct ima_field_data *field_data);
> int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp,
> int maxfields, struct ima_field_data *fields, int *curfields,
> unsigned long *len_mask, int enforce_mask, char *bufname);
> @@ -42,4 +44,6 @@ int ima_eventname_ng_init(struct ima_event_data *event_data,
> struct ima_field_data *field_data);
> int ima_eventsig_init(struct ima_event_data *event_data,
> struct ima_field_data *field_data);
> +int ima_eventbuf_init(struct ima_event_data *event_data,
> + struct ima_field_data *field_data);
> #endif /* __LINUX_IMA_TEMPLATE_LIB_H */
>
--
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063
Managing Director: Bo PENG, Jian LI, Yanli SHI
^ permalink raw reply
* Re: [PATCH 3/4] ima: don't ignore INTEGRITY_UNKNOWN EVM status
From: Roberto Sassu @ 2019-05-21 7:26 UTC (permalink / raw)
To: Mimi Zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-doc, linux-security-module, linux-kernel,
silviu.vlasceanu, stable
In-Reply-To: <1558387212.4039.77.camel@linux.ibm.com>
On 5/20/2019 11:20 PM, Mimi Zohar wrote:
> On Thu, 2019-05-16 at 18:12 +0200, Roberto Sassu wrote:
>> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
>> index 52e6fbb042cc..80e1c233656b 100644
>> --- a/Documentation/admin-guide/kernel-parameters.txt
>> +++ b/Documentation/admin-guide/kernel-parameters.txt
>> @@ -1588,6 +1588,9 @@
>> Format: { "off" | "enforce" | "fix" | "log" }
>> default: "enforce"
>>
>> + ima_appraise_req_evm
>> + [IMA] require EVM for appraisal with file digests.
>
> As much as possible we want to limit the number of new boot command
> line options as possible. Is there a reason for not extending
> "ima_appraise=" with "require-evm" or "enforce-evm"?
ima-appraise= can be disabled with CONFIG_IMA_APPRAISE_BOOTPARAM, which
probably is done when the system is in production.
Should I allow to use ima-appraise=require-evm even if
CONFIG_IMA_APPRAISE_BOOTPARAM=n?
Thanks
Roberto
--
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063
Managing Director: Bo PENG, Jian LI, Yanli SHI
^ permalink raw reply
* Re: [PATCH 4/4] ima: only audit failed appraisal verifications
From: Roberto Sassu @ 2019-05-21 7:32 UTC (permalink / raw)
To: Mimi Zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-doc, linux-security-module, linux-kernel,
silviu.vlasceanu, stable
In-Reply-To: <1558387225.4039.78.camel@linux.ibm.com>
On 5/20/2019 11:20 PM, Mimi Zohar wrote:
> On Thu, 2019-05-16 at 18:12 +0200, Roberto Sassu wrote:
>> This patch ensures that integrity_audit_msg() is called only when the
>> status is not INTEGRITY_PASS.
>>
>> Fixes: 8606404fa555c ("ima: digital signature verification support")
>> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
>> Cc: stable@vger.kernel.org
>> ---
>> security/integrity/ima/ima_appraise.c | 5 +++--
>> 1 file changed, 3 insertions(+), 2 deletions(-)
>>
>> diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
>> index a32ed5d7afd1..f5f4506bcb8e 100644
>> --- a/security/integrity/ima/ima_appraise.c
>> +++ b/security/integrity/ima/ima_appraise.c
>> @@ -359,8 +359,9 @@ int ima_appraise_measurement(enum ima_hooks func,
>> status = INTEGRITY_PASS;
>> }
>>
>> - integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
>> - op, cause, rc, 0);
>> + if (status != INTEGRITY_PASS)
>> + integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
>> + filename, op, cause, rc, 0);
>
> For some reason, the integrity verification has failed. In some
> specific cases, we'll let it pass, but do we really want to remove any
> indication that it failed in all cases?
Ok. It is fine for me to discard the patch.
Roberto
--
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063
Managing Director: Bo PENG, Jian LI, Yanli SHI
^ permalink raw reply
* Re: [RFC 1/1] Add dm verity root hash pkcs7 sig validation.
From: Milan Broz @ 2019-05-21 7:38 UTC (permalink / raw)
To: Jaskaran Khurana, linux-security-module, linux-kernel
Cc: agk, snitzer, dm-devel, jmorris
In-Reply-To: <20190520215422.23939-2-jaskarankhurana@linux.microsoft.com>
On 20/05/2019 23:54, Jaskaran Khurana wrote:
> Adds in-kernel pkcs7 signature checking for the roothash of
> the dm-verity hash tree.
>
> The verification is to support cases where the roothash is not secured by
> Trusted Boot, UEFI Secureboot or similar technologies.
> One of the use cases for this is for dm-verity volumes mounted after boot,
> the root hash provided during the creation of the dm-verity volume has to
> be secure and thus in-kernel validation implemented here will be used
> before we trust the root hash and allow the block device to be created.
>
> The signature being provided for verification must verify the root hash and
> must be trusted by the builtin keyring for verification to succeed.
>
> Adds DM_VERITY_VERIFY_ROOTHASH_SIG: roothash verification
> against the roothash signature file *if* specified, if signature file is
> specified verification must succeed prior to creation of device mapper
> block device.
>
> Adds DM_VERITY_VERIFY_ROOTHASH_SIG_FORCE: roothash signature *must* be
> specified for all dm verity volumes and verification must succeed prior
> to creation of device mapper block device.
I am not sure this is a good idea. If I understand it correctly, this will
block creating another dm-verity mappings without PKCS7 signature, and these
are used in many other environments and applications that could possibly
run on that system later.
(But I have no idea how to solve it better though :-)
...
> + /* Root hash signature is a optional parameter*/
> + r = verity_verify_root_hash(root_hash_digest_to_validate,
> + strlen(root_hash_digest_to_validate),
> + verify_args.sig,
> + verify_args.sig_size);
> + if (r < 0) {
> + ti->error = "Root hash verification failed";
> + goto bad;
> + }
You are sending the PKCS7 signature as a (quite large) binary blob inside the mapping table.
I am not sure if it is possible here (I guess so), but why not put this it kernel keyring
and then just reference it from mapping table?
(We use kernel keyring in libcryptsetup already for dm-crypt.)
It will also solve an issue in userspace patch, when you are reading the signature
file too late (devices can be suspended in that moment, so I would prefer to download
sig file to keyring in advance, and then just reference it in mapping table).
(I guess you will send merge request for veritysetup userspace part later.)
Milan
^ permalink raw reply
* Re: [PATCH V7 4/4] efi: Attempt to get the TCG2 event log in the boot stub
From: Ard Biesheuvel @ 2019-05-21 9:26 UTC (permalink / raw)
To: Matthew Garrett
Cc: linux-integrity, Peter Hüwe, Jarkko Sakkinen,
Jason Gunthorpe, Roberto Sassu, linux-efi, linux-security-module,
Linux Kernel Mailing List, Thiebaud Weksteen, Bartosz Szczepanek,
Matthew Garrett
In-Reply-To: <20190520205501.177637-5-matthewgarrett@google.com>
On Mon, 20 May 2019 at 21:55, Matthew Garrett <matthewgarrett@google.com> wrote:
>
> From: Matthew Garrett <mjg59@google.com>
>
> Right now we only attempt to obtain the SHA1-only event log. The
> protocol also supports a crypto agile log format, which contains digests
> for all algorithms in use. Attempt to obtain this first, and fall back
> to obtaining the older format if the system doesn't support it. This is
> lightly complicated by the event sizes being variable (as we don't know
> in advance which algorithms are in use), and the interface giving us
> back a pointer to the start of the final entry rather than a pointer to
> the end of the log - as a result, we need to parse the final entry to
> figure out its length in order to know how much data to copy up to the
> OS.
>
> Signed-off-by: Matthew Garrett <mjg59@google.com>
Provided that this gets a tested-by from Bartosz,
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> drivers/firmware/efi/libstub/tpm.c | 50 ++++++++++++++++++++----------
> 1 file changed, 33 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c
> index 5bd04f75d8d6..6b3b507a54eb 100644
> --- a/drivers/firmware/efi/libstub/tpm.c
> +++ b/drivers/firmware/efi/libstub/tpm.c
> @@ -57,7 +57,7 @@ void efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg)
>
> #endif
>
> -static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
> +void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg)
> {
> efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
> efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID;
> @@ -67,6 +67,7 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
> unsigned long first_entry_addr, last_entry_addr;
> size_t log_size, last_entry_size;
> efi_bool_t truncated;
> + int version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
> void *tcg2_protocol = NULL;
>
> status = efi_call_early(locate_protocol, &tcg2_guid, NULL,
> @@ -74,14 +75,20 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
> if (status != EFI_SUCCESS)
> return;
>
> - status = efi_call_proto(efi_tcg2_protocol, get_event_log, tcg2_protocol,
> - EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2,
> - &log_location, &log_last_entry, &truncated);
> - if (status != EFI_SUCCESS)
> - return;
> + status = efi_call_proto(efi_tcg2_protocol, get_event_log,
> + tcg2_protocol, version, &log_location,
> + &log_last_entry, &truncated);
> +
> + if (status != EFI_SUCCESS || !log_location) {
> + version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
> + status = efi_call_proto(efi_tcg2_protocol, get_event_log,
> + tcg2_protocol, version, &log_location,
> + &log_last_entry, &truncated);
> + if (status != EFI_SUCCESS || !log_location)
> + return;
> +
> + }
>
> - if (!log_location)
> - return;
> first_entry_addr = (unsigned long) log_location;
>
> /*
> @@ -96,8 +103,23 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
> * We need to calculate its size to deduce the full size of
> * the logs.
> */
> - last_entry_size = sizeof(struct tcpa_event) +
> - ((struct tcpa_event *) last_entry_addr)->event_size;
> + if (version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) {
> + /*
> + * The TCG2 log format has variable length entries,
> + * and the information to decode the hash algorithms
> + * back into a size is contained in the first entry -
> + * pass a pointer to the final entry (to calculate its
> + * size) and the first entry (so we know how long each
> + * digest is)
> + */
> + last_entry_size =
> + __calc_tpm2_event_size((void *)last_entry_addr,
> + (void *)(long)log_location,
> + false);
> + } else {
> + last_entry_size = sizeof(struct tcpa_event) +
> + ((struct tcpa_event *) last_entry_addr)->event_size;
> + }
> log_size = log_last_entry - log_location + last_entry_size;
> }
>
> @@ -114,7 +136,7 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
>
> memset(log_tbl, 0, sizeof(*log_tbl) + log_size);
> log_tbl->size = log_size;
> - log_tbl->version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
> + log_tbl->version = version;
> memcpy(log_tbl->log, (void *) first_entry_addr, log_size);
>
> status = efi_call_early(install_configuration_table,
> @@ -126,9 +148,3 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
> err_free:
> efi_call_early(free_pool, log_tbl);
> }
> -
> -void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg)
> -{
> - /* Only try to retrieve the logs in 1.2 format. */
> - efi_retrieve_tpm2_eventlog_1_2(sys_table_arg);
> -}
> --
> 2.21.0.1020.gf2820cf01a-goog
>
^ permalink raw reply
* Re: [PATCH V7 2/4] tpm: Reserve the TPM final events table
From: Ard Biesheuvel @ 2019-05-21 9:29 UTC (permalink / raw)
To: Matthew Garrett
Cc: linux-integrity, Peter Hüwe, Jarkko Sakkinen,
Jason Gunthorpe, Roberto Sassu, linux-efi, linux-security-module,
Linux Kernel Mailing List, Thiebaud Weksteen, Bartosz Szczepanek,
Matthew Garrett
In-Reply-To: <20190520205501.177637-3-matthewgarrett@google.com>
On Mon, 20 May 2019 at 21:55, Matthew Garrett <matthewgarrett@google.com> wrote:
>
> From: Matthew Garrett <mjg59@google.com>
>
> UEFI systems provide a boot services protocol for obtaining the TPM
> event log, but this is unusable after ExitBootServices() is called.
> Unfortunately ExitBootServices() itself triggers additional TPM events
> that then can't be obtained using this protocol. The platform provides a
> mechanism for the OS to obtain these events by recording them to a
> separate UEFI configuration table which the OS can then map.
>
> Unfortunately this table isn't self describing in terms of providing its
> length, so we need to parse the events inside it to figure out how long
> it is. Since the table isn't mapped at this point, we need to extend the
> length calculation function to be able to map the event as it goes
> along.
>
> (Fixes by Bartosz Szczepanek <bsz@semihalf.com>)
>
> Signed-off-by: Matthew Garrett <mjg59@google.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> drivers/char/tpm/eventlog/tpm2.c | 2 +-
> drivers/firmware/efi/efi.c | 2 +
> drivers/firmware/efi/tpm.c | 62 ++++++++++++++++++-
> include/linux/efi.h | 9 +++
> include/linux/tpm_eventlog.h | 102 ++++++++++++++++++++++++++++---
> 5 files changed, 164 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/char/tpm/eventlog/tpm2.c b/drivers/char/tpm/eventlog/tpm2.c
> index 1a977bdd3bd2..de1d9f7e5a92 100644
> --- a/drivers/char/tpm/eventlog/tpm2.c
> +++ b/drivers/char/tpm/eventlog/tpm2.c
> @@ -40,7 +40,7 @@
> static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
> struct tcg_pcr_event *event_header)
> {
> - return __calc_tpm2_event_size(event, event_header);
> + return __calc_tpm2_event_size(event, event_header, false);
> }
>
> static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
> diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
> index 55b77c576c42..6b11c41e0575 100644
> --- a/drivers/firmware/efi/efi.c
> +++ b/drivers/firmware/efi/efi.c
> @@ -53,6 +53,7 @@ struct efi __read_mostly efi = {
> .mem_attr_table = EFI_INVALID_TABLE_ADDR,
> .rng_seed = EFI_INVALID_TABLE_ADDR,
> .tpm_log = EFI_INVALID_TABLE_ADDR,
> + .tpm_final_log = EFI_INVALID_TABLE_ADDR,
> .mem_reserve = EFI_INVALID_TABLE_ADDR,
> };
> EXPORT_SYMBOL(efi);
> @@ -485,6 +486,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
> {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
> {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
> {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
> + {LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log},
> {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve},
> {NULL_GUID, NULL, NULL},
> };
> diff --git a/drivers/firmware/efi/tpm.c b/drivers/firmware/efi/tpm.c
> index 3a689b40ccc0..2c912ea08166 100644
> --- a/drivers/firmware/efi/tpm.c
> +++ b/drivers/firmware/efi/tpm.c
> @@ -4,34 +4,90 @@
> * Thiebaud Weksteen <tweek@google.com>
> */
>
> +#define TPM_MEMREMAP(start, size) early_memremap(start, size)
> +#define TPM_MEMUNMAP(start, size) early_memunmap(start, size)
> +
> #include <linux/efi.h>
> #include <linux/init.h>
> #include <linux/memblock.h>
> +#include <linux/tpm_eventlog.h>
>
> #include <asm/early_ioremap.h>
>
> +int efi_tpm_final_log_size;
> +EXPORT_SYMBOL(efi_tpm_final_log_size);
> +
> +static int tpm2_calc_event_log_size(void *data, int count, void *size_info)
> +{
> + struct tcg_pcr_event2_head *header;
> + int event_size, size = 0;
> +
> + while (count > 0) {
> + header = data + size;
> + event_size = __calc_tpm2_event_size(header, size_info, true);
> + if (event_size == 0)
> + return -1;
> + size += event_size;
> + count--;
> + }
> +
> + return size;
> +}
> +
> /*
> * Reserve the memory associated with the TPM Event Log configuration table.
> */
> int __init efi_tpm_eventlog_init(void)
> {
> struct linux_efi_tpm_eventlog *log_tbl;
> + struct efi_tcg2_final_events_table *final_tbl;
> unsigned int tbl_size;
> + int ret = 0;
>
> - if (efi.tpm_log == EFI_INVALID_TABLE_ADDR)
> + if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) {
> + /*
> + * We can't calculate the size of the final events without the
> + * first entry in the TPM log, so bail here.
> + */
> return 0;
> + }
>
> log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl));
> if (!log_tbl) {
> pr_err("Failed to map TPM Event Log table @ 0x%lx\n",
> - efi.tpm_log);
> + efi.tpm_log);
> efi.tpm_log = EFI_INVALID_TABLE_ADDR;
> return -ENOMEM;
> }
>
> tbl_size = sizeof(*log_tbl) + log_tbl->size;
> memblock_reserve(efi.tpm_log, tbl_size);
> +
> + if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR)
> + goto out;
> +
> + final_tbl = early_memremap(efi.tpm_final_log, sizeof(*final_tbl));
> +
> + if (!final_tbl) {
> + pr_err("Failed to map TPM Final Event Log table @ 0x%lx\n",
> + efi.tpm_final_log);
> + efi.tpm_final_log = EFI_INVALID_TABLE_ADDR;
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + tbl_size = tpm2_calc_event_log_size(efi.tpm_final_log
> + + sizeof(final_tbl->version)
> + + sizeof(final_tbl->nr_events),
> + final_tbl->nr_events,
> + log_tbl->log);
> + memblock_reserve((unsigned long)final_tbl,
> + tbl_size + sizeof(*final_tbl));
> + early_memunmap(final_tbl, sizeof(*final_tbl));
> + efi_tpm_final_log_size = tbl_size;
> +
> +out:
> early_memunmap(log_tbl, sizeof(*log_tbl));
> - return 0;
> + return ret;
> }
>
> diff --git a/include/linux/efi.h b/include/linux/efi.h
> index 54357a258b35..e33c70a52a9d 100644
> --- a/include/linux/efi.h
> +++ b/include/linux/efi.h
> @@ -689,6 +689,7 @@ void efi_native_runtime_setup(void);
> #define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
> #define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
> #define LINUX_EFI_TPM_EVENT_LOG_GUID EFI_GUID(0xb7799cb0, 0xeca2, 0x4943, 0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa)
> +#define LINUX_EFI_TPM_FINAL_LOG_GUID EFI_GUID(0x1e2ed096, 0x30e2, 0x4254, 0xbd, 0x89, 0x86, 0x3b, 0xbe, 0xf8, 0x23, 0x25)
> #define LINUX_EFI_MEMRESERVE_TABLE_GUID EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5, 0xa8, 0xf0, 0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2)
>
> typedef struct {
> @@ -996,6 +997,7 @@ extern struct efi {
> unsigned long mem_attr_table; /* memory attributes table */
> unsigned long rng_seed; /* UEFI firmware random seed */
> unsigned long tpm_log; /* TPM2 Event Log table */
> + unsigned long tpm_final_log; /* TPM2 Final Events Log table */
> unsigned long mem_reserve; /* Linux EFI memreserve table */
> efi_get_time_t *get_time;
> efi_set_time_t *set_time;
> @@ -1707,6 +1709,13 @@ struct linux_efi_tpm_eventlog {
>
> extern int efi_tpm_eventlog_init(void);
>
> +struct efi_tcg2_final_events_table {
> + u64 version;
> + u64 nr_events;
> + u8 events[];
> +};
> +extern int efi_tpm_final_log_size;
> +
> /*
> * efi_runtime_service() function identifiers.
> * "NONE" is used by efi_recover_from_page_fault() to check if the page
> diff --git a/include/linux/tpm_eventlog.h b/include/linux/tpm_eventlog.h
> index 6a86144e13f1..63238c84dc0b 100644
> --- a/include/linux/tpm_eventlog.h
> +++ b/include/linux/tpm_eventlog.h
> @@ -112,10 +112,35 @@ struct tcg_pcr_event2_head {
> struct tpm_digest digests[];
> } __packed;
>
> +struct tcg_algorithm_size {
> + u16 algorithm_id;
> + u16 algorithm_size;
> +};
> +
> +struct tcg_algorithm_info {
> + u8 signature[16];
> + u32 platform_class;
> + u8 spec_version_minor;
> + u8 spec_version_major;
> + u8 spec_errata;
> + u8 uintn_size;
> + u32 number_of_algorithms;
> + struct tcg_algorithm_size digest_sizes[];
> +};
> +
> +#ifndef TPM_MEMREMAP
> +#define TPM_MEMREMAP(start, size) NULL
> +#endif
> +
> +#ifndef TPM_MEMUNMAP
> +#define TPM_MEMUNMAP(start, size) do{} while(0)
> +#endif
> +
> /**
> * __calc_tpm2_event_size - calculate the size of a TPM2 event log entry
> * @event: Pointer to the event whose size should be calculated
> * @event_header: Pointer to the initial event containing the digest lengths
> + * @do_mapping: Whether or not the event needs to be mapped
> *
> * The TPM2 event log format can contain multiple digests corresponding to
> * separate PCR banks, and also contains a variable length of the data that
> @@ -131,10 +156,13 @@ struct tcg_pcr_event2_head {
> */
>
> static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
> - struct tcg_pcr_event *event_header)
> + struct tcg_pcr_event *event_header,
> + bool do_mapping)
> {
> struct tcg_efi_specid_event_head *efispecid;
> struct tcg_event_field *event_field;
> + void *mapping = NULL;
> + int mapping_size;
> void *marker;
> void *marker_start;
> u32 halg_size;
> @@ -148,16 +176,49 @@ static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
> marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
> + sizeof(event->count);
>
> + /* Map the event header */
> + if (do_mapping) {
> + mapping_size = marker - marker_start;
> + mapping = TPM_MEMREMAP((unsigned long)marker_start,
> + mapping_size);
> + if (!mapping) {
> + size = 0;
> + goto out;
> + }
> + } else {
> + mapping = marker_start;
> + }
> +
> + event = (struct tcg_pcr_event2_head *)mapping;
> +
> efispecid = (struct tcg_efi_specid_event_head *)event_header->event;
>
> /* Check if event is malformed. */
> - if (event->count > efispecid->num_algs)
> - return 0;
> + if (event->count > efispecid->num_algs) {
> + size = 0;
> + goto out;
> + }
>
> for (i = 0; i < event->count; i++) {
> halg_size = sizeof(event->digests[i].alg_id);
> - memcpy(&halg, marker, halg_size);
> +
> + /* Map the digest's algorithm identifier */
> + if (do_mapping) {
> + TPM_MEMUNMAP(mapping, mapping_size);
> + mapping_size = halg_size;
> + mapping = TPM_MEMREMAP((unsigned long)marker,
> + mapping_size);
> + if (!mapping) {
> + size = 0;
> + goto out;
> + }
> + } else {
> + mapping = marker;
> + }
> +
> + memcpy(&halg, mapping, halg_size);
> marker = marker + halg_size;
> +
> for (j = 0; j < efispecid->num_algs; j++) {
> if (halg == efispecid->digest_sizes[j].alg_id) {
> marker +=
> @@ -166,18 +227,41 @@ static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
> }
> }
> /* Algorithm without known length. Such event is unparseable. */
> - if (j == efispecid->num_algs)
> - return 0;
> + if (j == efispecid->num_algs) {
> + size = 0;
> + goto out;
> + }
> + }
> +
> + /*
> + * Map the event size - we don't read from the event itself, so
> + * we don't need to map it
> + */
> + if (do_mapping) {
> + TPM_MEMUNMAP(mapping, mapping_size);
> + mapping_size += sizeof(event_field->event_size);
> + mapping = TPM_MEMREMAP((unsigned long)marker,
> + mapping_size);
> + if (!mapping) {
> + size = 0;
> + goto out;
> + }
> + } else {
> + mapping = marker;
> }
>
> - event_field = (struct tcg_event_field *)marker;
> + event_field = (struct tcg_event_field *)mapping;
> +
> marker = marker + sizeof(event_field->event_size)
> + event_field->event_size;
> size = marker - marker_start;
>
> if ((event->event_type == 0) && (event_field->event_size == 0))
> - return 0;
> -
> + size = 0;
> +out:
> + if (do_mapping)
> + TPM_MEMUNMAP(mapping, mapping_size);
> return size;
> }
> +
> #endif
> --
> 2.21.0.1020.gf2820cf01a-goog
>
^ permalink raw reply
* Re: [PATCH V7 0/4] Add support for crypto agile logs
From: Jarkko Sakkinen @ 2019-05-21 11:45 UTC (permalink / raw)
To: Matthew Garrett
Cc: linux-integrity, peterhuewe, jgg, roberto.sassu, linux-efi,
linux-security-module, linux-kernel, tweek, bsz
In-Reply-To: <20190520205501.177637-1-matthewgarrett@google.com>
On Mon, May 20, 2019 at 01:54:57PM -0700, Matthew Garrett wrote:
> Identical to previous version except without the KSAN workaround - Ard
> has a better solution for that.
I'll check in detail through tomorrow but probably will get merged
now that we have Ard's ack's (thanks Ard for all the trouble!) :-)
/Jarkko
^ permalink raw reply
* Re: [PATCH 3/4] ima: don't ignore INTEGRITY_UNKNOWN EVM status
From: Mimi Zohar @ 2019-05-21 11:48 UTC (permalink / raw)
To: Roberto Sassu, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-doc, linux-security-module, linux-kernel,
silviu.vlasceanu, stable
In-Reply-To: <e81b761c-9133-a432-4d06-3cfe57e29e4b@huawei.com>
On Tue, 2019-05-21 at 09:26 +0200, Roberto Sassu wrote:
> On 5/20/2019 11:20 PM, Mimi Zohar wrote:
> > On Thu, 2019-05-16 at 18:12 +0200, Roberto Sassu wrote:
> >> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> >> index 52e6fbb042cc..80e1c233656b 100644
> >> --- a/Documentation/admin-guide/kernel-parameters.txt
> >> +++ b/Documentation/admin-guide/kernel-parameters.txt
> >> @@ -1588,6 +1588,9 @@
> >> Format: { "off" | "enforce" | "fix" | "log" }
> >> default: "enforce"
> >>
> >> + ima_appraise_req_evm
> >> + [IMA] require EVM for appraisal with file digests.
> >
> > As much as possible we want to limit the number of new boot command
> > line options as possible. Is there a reason for not extending
> > "ima_appraise=" with "require-evm" or "enforce-evm"?
>
> ima-appraise= can be disabled with CONFIG_IMA_APPRAISE_BOOTPARAM, which
> probably is done when the system is in production.
>
> Should I allow to use ima-appraise=require-evm even if
> CONFIG_IMA_APPRAISE_BOOTPARAM=n?
Yes, that should be fine. It's making "ima_appraise" stricter.
Mimi
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox