Skip to content

Commit 7457c49

Browse files
author
Mamatha Inamdar
committed
powerpc/papr_scm: Fix leaking nvdimm_events_map elements
JIRA: https://issues.redhat.com/browse/RHEL-81000 CVE: CVE-2022-49353 commit 0e0946e Author: Vaibhav Jain <vaibhav@linux.ibm.com> Date: Wed May 11 13:56:36 2022 +0530 powerpc/papr_scm: Fix leaking nvdimm_events_map elements Right now 'char *' elements allocated for individual 'stat_id' in 'papr_scm_priv.nvdimm_events_map[]' during papr_scm_pmu_check_events(), get leaked in papr_scm_remove() and papr_scm_pmu_register(), papr_scm_pmu_check_events() error paths. Also individual 'stat_id' arent NULL terminated 'char *' instead they are fixed 8-byte sized identifiers. However papr_scm_pmu_register() assumes it to be a NULL terminated 'char *' and at other places it assumes it to be a 'papr_scm_perf_stat.stat_id' sized string which is 8-byes in size. Fix this by allocating the memory for papr_scm_priv.nvdimm_events_map to also include space for 'stat_id' entries. This is possible since number of available events/stat_ids are known upfront. This saves some memory and one extra level of indirection from 'nvdimm_events_map' to 'stat_id'. Also rest of the code can continue to call 'kfree(papr_scm_priv.nvdimm_events_map)' without needing to iterate over the array and free up individual elements. Fixes: 4c08d4b ("powerpc/papr_scm: Add perf interface support") Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20220511082637.646714-1-vaibhav@linux.ibm.com Signed-off-by: Mamatha Inamdar <minamdar@redhat.com>
1 parent 5150d3a commit 7457c49

File tree

1 file changed

+23
-29
lines changed

1 file changed

+23
-29
lines changed

arch/powerpc/platforms/pseries/papr_scm.c

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ struct papr_scm_priv {
126126
u64 health_bitmap_inject_mask;
127127

128128
/* array to have event_code and stat_id mappings */
129-
char **nvdimm_events_map;
129+
u8 *nvdimm_events_map;
130130
};
131131

132132
static int papr_scm_pmem_flush(struct nd_region *nd_region,
@@ -370,7 +370,7 @@ static int papr_scm_pmu_get_value(struct perf_event *event, struct device *dev,
370370

371371
stat = &stats->scm_statistic[0];
372372
memcpy(&stat->stat_id,
373-
p->nvdimm_events_map[event->attr.config],
373+
&p->nvdimm_events_map[event->attr.config * sizeof(stat->stat_id)],
374374
sizeof(stat->stat_id));
375375
stat->stat_val = 0;
376376

@@ -462,14 +462,13 @@ static int papr_scm_pmu_check_events(struct papr_scm_priv *p, struct nvdimm_pmu
462462
{
463463
struct papr_scm_perf_stat *stat;
464464
struct papr_scm_perf_stats *stats;
465-
int index, rc, count;
466465
u32 available_events;
467-
468-
if (!p->stat_buffer_len)
469-
return -ENOENT;
466+
int index, rc = 0;
470467

471468
available_events = (p->stat_buffer_len - sizeof(struct papr_scm_perf_stats))
472469
/ sizeof(struct papr_scm_perf_stat);
470+
if (available_events == 0)
471+
return -EOPNOTSUPP;
473472

474473
/* Allocate the buffer for phyp where stats are written */
475474
stats = kzalloc(p->stat_buffer_len, GFP_KERNEL);
@@ -478,35 +477,30 @@ static int papr_scm_pmu_check_events(struct papr_scm_priv *p, struct nvdimm_pmu
478477
return rc;
479478
}
480479

481-
/* Allocate memory to nvdimm_event_map */
482-
p->nvdimm_events_map = kcalloc(available_events, sizeof(char *), GFP_KERNEL);
483-
if (!p->nvdimm_events_map) {
484-
rc = -ENOMEM;
485-
goto out_stats;
486-
}
487-
488480
/* Called to get list of events supported */
489481
rc = drc_pmem_query_stats(p, stats, 0);
490482
if (rc)
491-
goto out_nvdimm_events_map;
492-
493-
for (index = 0, stat = stats->scm_statistic, count = 0;
494-
index < available_events; index++, ++stat) {
495-
p->nvdimm_events_map[count] = kmemdup_nul(stat->stat_id, 8, GFP_KERNEL);
496-
if (!p->nvdimm_events_map[count]) {
497-
rc = -ENOMEM;
498-
goto out_nvdimm_events_map;
499-
}
483+
goto out;
500484

501-
count++;
485+
/*
486+
* Allocate memory and populate nvdimm_event_map.
487+
* Allocate an extra element for NULL entry
488+
*/
489+
p->nvdimm_events_map = kcalloc(available_events + 1,
490+
sizeof(stat->stat_id),
491+
GFP_KERNEL);
492+
if (!p->nvdimm_events_map) {
493+
rc = -ENOMEM;
494+
goto out;
502495
}
503-
p->nvdimm_events_map[count] = NULL;
504-
kfree(stats);
505-
return 0;
506496

507-
out_nvdimm_events_map:
508-
kfree(p->nvdimm_events_map);
509-
out_stats:
497+
/* Copy all stat_ids to event map */
498+
for (index = 0, stat = stats->scm_statistic;
499+
index < available_events; index++, ++stat) {
500+
memcpy(&p->nvdimm_events_map[index * sizeof(stat->stat_id)],
501+
&stat->stat_id, sizeof(stat->stat_id));
502+
}
503+
out:
510504
kfree(stats);
511505
return rc;
512506
}

0 commit comments

Comments
 (0)