Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 1873735

Browse files
committed
Merge tag 'edac_urgent_for_v6.9_rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras
Pull EDAC fixes from Borislav Petkov: - Fix more issues in the AMD FMPM driver * tag 'edac_urgent_for_v6.9_rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras: RAS: Avoid build errors when CONFIG_DEBUG_FS=n RAS/AMD/FMPM: Safely handle saved records of various sizes RAS/AMD/FMPM: Avoid NULL ptr deref in get_saved_records()
2 parents 5dad262 + a6b227d commit 1873735

File tree

2 files changed

+43
-18
lines changed

2 files changed

+43
-18
lines changed

drivers/ras/amd/fmpm.c

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ static unsigned int max_nr_fru;
150150
/* Total length of record including headers and list of descriptor entries. */
151151
static size_t max_rec_len;
152152

153+
#define FMPM_MAX_REC_LEN (sizeof(struct fru_rec) + (sizeof(struct cper_fru_poison_desc) * 255))
154+
153155
/* Total number of SPA entries across all FRUs. */
154156
static unsigned int spa_nr_entries;
155157

@@ -475,6 +477,16 @@ static void set_rec_fields(struct fru_rec *rec)
475477
struct cper_section_descriptor *sec_desc = &rec->sec_desc;
476478
struct cper_record_header *hdr = &rec->hdr;
477479

480+
/*
481+
* This is a saved record created with fewer max_nr_entries.
482+
* Update the record lengths and keep everything else as-is.
483+
*/
484+
if (hdr->record_length && hdr->record_length < max_rec_len) {
485+
pr_debug("Growing record 0x%016llx from %u to %zu bytes\n",
486+
hdr->record_id, hdr->record_length, max_rec_len);
487+
goto update_lengths;
488+
}
489+
478490
memcpy(hdr->signature, CPER_SIG_RECORD, CPER_SIG_SIZE);
479491
hdr->revision = CPER_RECORD_REV;
480492
hdr->signature_end = CPER_SIG_END;
@@ -489,19 +501,21 @@ static void set_rec_fields(struct fru_rec *rec)
489501
hdr->error_severity = CPER_SEV_RECOVERABLE;
490502

491503
hdr->validation_bits = 0;
492-
hdr->record_length = max_rec_len;
493504
hdr->creator_id = CPER_CREATOR_FMP;
494505
hdr->notification_type = CPER_NOTIFY_MCE;
495506
hdr->record_id = cper_next_record_id();
496507
hdr->flags = CPER_HW_ERROR_FLAGS_PREVERR;
497508

498509
sec_desc->section_offset = sizeof(struct cper_record_header);
499-
sec_desc->section_length = max_rec_len - sizeof(struct cper_record_header);
500510
sec_desc->revision = CPER_SEC_REV;
501511
sec_desc->validation_bits = 0;
502512
sec_desc->flags = CPER_SEC_PRIMARY;
503513
sec_desc->section_type = CPER_SECTION_TYPE_FMP;
504514
sec_desc->section_severity = CPER_SEV_RECOVERABLE;
515+
516+
update_lengths:
517+
hdr->record_length = max_rec_len;
518+
sec_desc->section_length = max_rec_len - sizeof(struct cper_record_header);
505519
}
506520

507521
static int save_new_records(void)
@@ -512,16 +526,18 @@ static int save_new_records(void)
512526
int ret = 0;
513527

514528
for_each_fru(i, rec) {
515-
if (rec->hdr.record_length)
529+
/* No need to update saved records that match the current record size. */
530+
if (rec->hdr.record_length == max_rec_len)
516531
continue;
517532

533+
if (!rec->hdr.record_length)
534+
set_bit(i, new_records);
535+
518536
set_rec_fields(rec);
519537

520538
ret = update_record_on_storage(rec);
521539
if (ret)
522540
goto out_clear;
523-
524-
set_bit(i, new_records);
525541
}
526542

527543
return ret;
@@ -641,12 +657,7 @@ static int get_saved_records(void)
641657
int ret, pos;
642658
ssize_t len;
643659

644-
/*
645-
* Assume saved records match current max size.
646-
*
647-
* However, this may not be true depending on module parameters.
648-
*/
649-
old = kmalloc(max_rec_len, GFP_KERNEL);
660+
old = kmalloc(FMPM_MAX_REC_LEN, GFP_KERNEL);
650661
if (!old) {
651662
ret = -ENOMEM;
652663
goto out;
@@ -663,21 +674,31 @@ static int get_saved_records(void)
663674
* Make sure to clear temporary buffer between reads to avoid
664675
* leftover data from records of various sizes.
665676
*/
666-
memset(old, 0, max_rec_len);
677+
memset(old, 0, FMPM_MAX_REC_LEN);
667678

668-
len = erst_read_record(record_id, &old->hdr, max_rec_len,
679+
len = erst_read_record(record_id, &old->hdr, FMPM_MAX_REC_LEN,
669680
sizeof(struct fru_rec), &CPER_CREATOR_FMP);
670681
if (len < 0)
671682
continue;
672683

673-
if (len > max_rec_len) {
674-
pr_debug("Found record larger than max_rec_len\n");
684+
new = get_valid_record(old);
685+
if (!new) {
686+
erst_clear(record_id);
675687
continue;
676688
}
677689

678-
new = get_valid_record(old);
679-
if (!new)
680-
erst_clear(record_id);
690+
if (len > max_rec_len) {
691+
unsigned int saved_nr_entries;
692+
693+
saved_nr_entries = len - sizeof(struct fru_rec);
694+
saved_nr_entries /= sizeof(struct cper_fru_poison_desc);
695+
696+
pr_warn("Saved record found with %u entries.\n", saved_nr_entries);
697+
pr_warn("Please increase max_nr_entries to %u.\n", saved_nr_entries);
698+
699+
ret = -EINVAL;
700+
goto out_end;
701+
}
681702

682703
/* Restore the record */
683704
memcpy(new, old, len);

drivers/ras/debugfs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
#include <linux/debugfs.h>
66

7+
#if IS_ENABLED(CONFIG_DEBUG_FS)
78
struct dentry *ras_get_debugfs_root(void);
9+
#else
10+
static inline struct dentry *ras_get_debugfs_root(void) { return NULL; }
11+
#endif /* DEBUG_FS */
812

913
#endif /* __RAS_DEBUGFS_H__ */

0 commit comments

Comments
 (0)