forked from Minki/linux
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: Tony Luck <tony.luck@intel.com> Cc: <stable@vger.kernel.org> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
This commit is contained in:
parent
d67e199611
commit
4c62360d75
@ -305,10 +305,17 @@ const char *cper_mem_err_unpack(struct trace_seq *p,
|
||||
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;
|
||||
|
||||
/* 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)
|
||||
printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_PA)
|
||||
@ -405,8 +412,10 @@ static void cper_estatus_print_section(
|
||||
} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
|
||||
struct cper_sec_mem_err *mem_err = (void *)(gdata + 1);
|
||||
printk("%s""section_type: memory error\n", newpfx);
|
||||
if (gdata->error_data_length >= sizeof(*mem_err))
|
||||
cper_print_mem(newpfx, mem_err);
|
||||
if (gdata->error_data_length >=
|
||||
sizeof(struct cper_sec_mem_err_old))
|
||||
cper_print_mem(newpfx, mem_err,
|
||||
gdata->error_data_length);
|
||||
else
|
||||
goto err_section_too_small;
|
||||
} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) {
|
||||
|
@ -340,7 +340,27 @@ struct cper_ia_proc_ctx {
|
||||
__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 {
|
||||
__u64 validation_bits;
|
||||
__u64 error_status;
|
||||
|
Loading…
Reference in New Issue
Block a user