lkml.org 
[lkml]   [2022]   [Jun]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.18 646/879] powerpc/papr_scm: Fix leaking nvdimm_events_map elements
    Date
    From: Vaibhav Jain <vaibhav@linux.ibm.com>

    [ Upstream commit 0e0946e22f3665d27325d389ff45ade6e93f3678 ]

    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: 4c08d4bbc089 ("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: Sasha Levin <sashal@kernel.org>
    ---
    arch/powerpc/platforms/pseries/papr_scm.c | 54 ++++++++++-------------
    1 file changed, 24 insertions(+), 30 deletions(-)

    diff --git a/arch/powerpc/platforms/pseries/papr_scm.c b/arch/powerpc/platforms/pseries/papr_scm.c
    index 39962c905542..181b855b3050 100644
    --- a/arch/powerpc/platforms/pseries/papr_scm.c
    +++ b/arch/powerpc/platforms/pseries/papr_scm.c
    @@ -125,8 +125,8 @@ struct papr_scm_priv {
    /* The bits which needs to be overridden */
    u64 health_bitmap_inject_mask;

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

    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,

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

    @@ -462,14 +462,13 @@ static int papr_scm_pmu_check_events(struct papr_scm_priv *p, struct nvdimm_pmu
    {
    struct papr_scm_perf_stat *stat;
    struct papr_scm_perf_stats *stats;
    - int index, rc, count;
    u32 available_events;
    -
    - if (!p->stat_buffer_len)
    - return -ENOENT;
    + int index, rc = 0;

    available_events = (p->stat_buffer_len - sizeof(struct papr_scm_perf_stats))
    / sizeof(struct papr_scm_perf_stat);
    + if (available_events == 0)
    + return -EOPNOTSUPP;

    /* Allocate the buffer for phyp where stats are written */
    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
    return rc;
    }

    - /* Allocate memory to nvdimm_event_map */
    - p->nvdimm_events_map = kcalloc(available_events, sizeof(char *), GFP_KERNEL);
    - if (!p->nvdimm_events_map) {
    - rc = -ENOMEM;
    - goto out_stats;
    - }
    -
    /* Called to get list of events supported */
    rc = drc_pmem_query_stats(p, stats, 0);
    if (rc)
    - goto out_nvdimm_events_map;
    -
    - for (index = 0, stat = stats->scm_statistic, count = 0;
    - index < available_events; index++, ++stat) {
    - p->nvdimm_events_map[count] = kmemdup_nul(stat->stat_id, 8, GFP_KERNEL);
    - if (!p->nvdimm_events_map[count]) {
    - rc = -ENOMEM;
    - goto out_nvdimm_events_map;
    - }
    + goto out;

    - count++;
    + /*
    + * Allocate memory and populate nvdimm_event_map.
    + * Allocate an extra element for NULL entry
    + */
    + p->nvdimm_events_map = kcalloc(available_events + 1,
    + sizeof(stat->stat_id),
    + GFP_KERNEL);
    + if (!p->nvdimm_events_map) {
    + rc = -ENOMEM;
    + goto out;
    }
    - p->nvdimm_events_map[count] = NULL;
    - kfree(stats);
    - return 0;

    -out_nvdimm_events_map:
    - kfree(p->nvdimm_events_map);
    -out_stats:
    + /* Copy all stat_ids to event map */
    + for (index = 0, stat = stats->scm_statistic;
    + index < available_events; index++, ++stat) {
    + memcpy(&p->nvdimm_events_map[index * sizeof(stat->stat_id)],
    + &stat->stat_id, sizeof(stat->stat_id));
    + }
    +out:
    kfree(stats);
    return rc;
    }
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-06-08 03:41    [W:2.708 / U:0.196 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site