[PATCH v2 1/2] efi/cper: validate ARM context headers before reading their size
Pengpeng Hou <[email protected]>
| Newsgroups | gmane.linux.acpi.devel,gmane.linux.kernel |
|---|---|
| Message-ID | <[email protected]> |
ARM processor CPER sections contain a fixed header, a fixed-size
error-information array and variable-size context records. The parser
derives the remaining byte count in int after subtracting
firmware-controlled unsigned values, then reads ctx_info->size before
proving that a complete context header remains.
Keep the remaining extent in size_t. Validate the section header and
error-information count before advancing, then require each context
header, payload and 16-byte-aligned record to fit before it is read or
consumed.
Fixes: c6d8c8ef1d0d ("efi: Move ARM CPER code to new file")
Assisted-by: Codex:gpt-5
Signed-off-by: Pengpeng Hou <[email protected]>
---
drivers/firmware/efi/cper-arm.c | 53 ++++++++++++++++++++++++++-------
1 file changed, 42 insertions(+), 11 deletions(-)
diff --git a/drivers/firmware/efi/cper-arm.c b/drivers/firmware/efi/cper-arm.c
index b21cb1232d82..e2f973d7a4a4 100644
--- a/drivers/firmware/efi/cper-arm.c
+++ b/drivers/firmware/efi/cper-arm.c
@@ -229,26 +229,39 @@ void cper_print_proc_arm(const char *pfx,
const struct cper_sec_proc_arm *proc,
u32 length)
{
- int i, len, max_ctx_type;
+ int i, max_ctx_type;
struct cper_arm_err_info *err_info;
struct cper_arm_ctx_info *ctx_info;
char newpfx[64], infopfx[ARRAY_SIZE(newpfx) + 1];
char error_type[120];
+ size_t len;
- printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
+ if (length < sizeof(*proc)) {
+ printk("%ssection length is too small\n", pfx);
+ printk("%sfirmware-generated error record is incorrect\n", pfx);
+ return;
+ }
- len = proc->section_length - (sizeof(*proc) +
- proc->err_info_num * (sizeof(*err_info)));
+ printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
- if (len < 0 || proc->section_length > length) {
- printk("%ssection length: %d, CPER size: %d\n",
+ if (proc->section_length < sizeof(*proc) ||
+ proc->section_length > length) {
+ printk("%ssection length: %u, CPER size: %u\n",
pfx, proc->section_length, length);
printk("%ssection length is too %s\n", pfx,
- (len < 0) ? "small" : "big");
+ proc->section_length < sizeof(*proc) ? "small" : "big");
+ printk("%sfirmware-generated error record is incorrect\n", pfx);
+ return;
+ }
+
+ len = proc->section_length - sizeof(*proc);
+ if (proc->err_info_num > len / sizeof(*err_info)) {
+ printk("%ssection length is too small\n", pfx);
printk("%sfirmware-generated error record is incorrect\n", pfx);
printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
return;
}
+ len -= proc->err_info_num * sizeof(*err_info);
if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n",
@@ -313,10 +326,28 @@ void cper_print_proc_arm(const char *pfx,
ctx_info = (struct cper_arm_ctx_info *)err_info;
max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1;
for (i = 0; i < proc->context_info_num; i++) {
- int size = ALIGN(sizeof(*ctx_info) + ctx_info->size, 16);
+ size_t size;
printk("%sContext info structure %d:\n", pfx, i);
- if (len < size) {
+ if (len < sizeof(*ctx_info)) {
+ printk("%ssection length is too small\n", newpfx);
+ printk("%sfirmware-generated error record is incorrect\n", pfx);
+ return;
+ }
+ if (ctx_info->size > len - sizeof(*ctx_info)) {
+ printk("%ssection length is too small\n", newpfx);
+ printk("%sfirmware-generated error record is incorrect\n", pfx);
+ return;
+ }
+
+ size = sizeof(*ctx_info) + ctx_info->size;
+ if (size > SIZE_MAX - 15) {
+ printk("%scontext record size is too big\n", newpfx);
+ printk("%sfirmware-generated error record is incorrect\n", pfx);
+ return;
+ }
+ size = ALIGN(size, 16);
+ if (size > len) {
printk("%ssection length is too small\n", newpfx);
printk("%sfirmware-generated error record is incorrect\n", pfx);
return;
@@ -331,11 +362,11 @@ void cper_print_proc_arm(const char *pfx,
print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
(ctx_info + 1), ctx_info->size, 0);
len -= size;
- ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
+ ctx_info = (struct cper_arm_ctx_info *)((u8 *)ctx_info + size);
}
if (len > 0) {
- printk("%sVendor specific error info has %u bytes:\n", pfx,
+ printk("%sVendor specific error info has %zu bytes:\n", pfx,
len);
print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,
len, true);
--
2.50.1 (Apple Git-155)