Commit 4c62360d authored by Luck, Tony's avatar Luck, Tony Committed by Matt Fleming

efi: Handle memory error structures produced based on old versions of standard

The memory error record structure includes as its first field a
bitmask of which subsequent fields are valid. The allows new fields
to be added to the structure while keeping compatibility with older
software that parses these records. This mechanism was used between
versions 2.2 and 2.3 to add four new fields, growing the size of the
structure from 73 bytes to 80. But Linux just added all the new
fields so this test:
	if (gdata->error_data_length >= sizeof(*mem_err))
		cper_print_mem(newpfx, mem_err);
	else
		goto err_section_too_small;
now make Linux complain about old format records being too short.

Add a definition for the old format of the structure and use that
for the minimum size check. Pass the actual size to cper_print_mem()
so it can sanity check the validation_bits field to ensure that if
a BIOS using the old format sets bits as if it were new, we won't
access fields beyond the end of the structure.
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarMatt Fleming <matt.fleming@intel.com>
parent d67e1996
...@@ -305,10 +305,17 @@ const char *cper_mem_err_unpack(struct trace_seq *p, ...@@ -305,10 +305,17 @@ const char *cper_mem_err_unpack(struct trace_seq *p,
return ret; return ret;
} }
static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem) static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
int len)
{ {
struct cper_mem_err_compact cmem; struct cper_mem_err_compact cmem;
/* Don't trust UEFI 2.1/2.2 structure with bad validation bits */
if (len == sizeof(struct cper_sec_mem_err_old) &&
(mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) {
pr_err(FW_WARN "valid bits set for fields beyond structure\n");
return;
}
if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS) if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status); printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
if (mem->validation_bits & CPER_MEM_VALID_PA) if (mem->validation_bits & CPER_MEM_VALID_PA)
...@@ -405,8 +412,10 @@ static void cper_estatus_print_section( ...@@ -405,8 +412,10 @@ static void cper_estatus_print_section(
} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) { } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
struct cper_sec_mem_err *mem_err = (void *)(gdata + 1); struct cper_sec_mem_err *mem_err = (void *)(gdata + 1);
printk("%s""section_type: memory error\n", newpfx); printk("%s""section_type: memory error\n", newpfx);
if (gdata->error_data_length >= sizeof(*mem_err)) if (gdata->error_data_length >=
cper_print_mem(newpfx, mem_err); sizeof(struct cper_sec_mem_err_old))
cper_print_mem(newpfx, mem_err,
gdata->error_data_length);
else else
goto err_section_too_small; goto err_section_too_small;
} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) { } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) {
......
...@@ -340,7 +340,27 @@ struct cper_ia_proc_ctx { ...@@ -340,7 +340,27 @@ struct cper_ia_proc_ctx {
__u64 mm_reg_addr; __u64 mm_reg_addr;
}; };
/* Memory Error Section */ /* Old Memory Error Section UEFI 2.1, 2.2 */
struct cper_sec_mem_err_old {
__u64 validation_bits;
__u64 error_status;
__u64 physical_addr;
__u64 physical_addr_mask;
__u16 node;
__u16 card;
__u16 module;
__u16 bank;
__u16 device;
__u16 row;
__u16 column;
__u16 bit_pos;
__u64 requestor_id;
__u64 responder_id;
__u64 target_id;
__u8 error_type;
};
/* Memory Error Section UEFI >= 2.3 */
struct cper_sec_mem_err { struct cper_sec_mem_err {
__u64 validation_bits; __u64 validation_bits;
__u64 error_status; __u64 error_status;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment