From f53c2a8a7a054286b6388dfc69a52986d8e98418 Mon Sep 17 00:00:00 2001 From: Bojun Pan Date: Fri, 11 Sep 2020 17:45:28 -0700 Subject: [PATCH] msm: ipa: correct the pointer in idr for FnR stats counter The stats counter which saved in idr was some stack memory which could be freed and cause memory corruption. The fix is to use the memory allocated in heap instead. Change-Id: Ie398b0271571fcff41cdb85de4d77d202b6552b5 Signed-off-by: Bojun Pan --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 9 +++++++ drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 2 ++ drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 29 +++++++++++++++------ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 3eb8c2b79341..e8a1a9383a1c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -7284,6 +7284,13 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, result = -ENOMEM; goto fail_hdr_offset_cache; } + ipa3_ctx->fnr_stats_cache = kmem_cache_create("IPA_FNR_STATS", + sizeof(struct ipa_ioc_flt_rt_counter_alloc), 0, 0, NULL); + if (!ipa3_ctx->fnr_stats_cache) { + IPAERR(":ipa fnr stats cache create failed\n"); + result = -ENOMEM; + goto fail_fnr_stats_cache; + } ipa3_ctx->hdr_proc_ctx_cache = kmem_cache_create("IPA_HDR_PROC_CTX", sizeof(struct ipa3_hdr_proc_ctx_entry), 0, 0, NULL); if (!ipa3_ctx->hdr_proc_ctx_cache) { @@ -7535,6 +7542,8 @@ fail_rt_tbl_cache: fail_hdr_proc_ctx_offset_cache: kmem_cache_destroy(ipa3_ctx->hdr_proc_ctx_cache); fail_hdr_proc_ctx_cache: + kmem_cache_destroy(ipa3_ctx->fnr_stats_cache); +fail_fnr_stats_cache: kmem_cache_destroy(ipa3_ctx->hdr_offset_cache); fail_hdr_offset_cache: kmem_cache_destroy(ipa3_ctx->hdr_cache); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 435550eb21f6..a0699b6555b1 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1853,6 +1853,7 @@ struct ipa3_app_clock_vote { * @rt_rule_cache: routing rule cache * @hdr_cache: header cache * @hdr_offset_cache: header offset cache + * @fnr_stats_cache: FnR stats cache * @hdr_proc_ctx_cache: processing context cache * @hdr_proc_ctx_offset_cache: processing context offset cache * @rt_tbl_cache: routing table cache @@ -1957,6 +1958,7 @@ struct ipa3_context { struct kmem_cache *rt_rule_cache; struct kmem_cache *hdr_cache; struct kmem_cache *hdr_offset_cache; + struct kmem_cache *fnr_stats_cache; struct kmem_cache *hdr_proc_ctx_cache; struct kmem_cache *hdr_proc_ctx_offset_cache; struct kmem_cache *rt_tbl_cache; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index adf855d0a658..aafd3c918672 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -6918,13 +6918,21 @@ static int __ipa3_alloc_counter_hdl return id; } -int ipa3_alloc_counter_id(struct ipa_ioc_flt_rt_counter_alloc *counter) +int ipa3_alloc_counter_id(struct ipa_ioc_flt_rt_counter_alloc *header) { int i, unused_cnt, unused_max, unused_start_id; + struct ipa_ioc_flt_rt_counter_alloc *counter; idr_preload(GFP_KERNEL); spin_lock(&ipa3_ctx->flt_rt_counters.hdl_lock); + counter = kmem_cache_zalloc(ipa3_ctx->fnr_stats_cache, GFP_KERNEL); + if (!counter) { + IPAERR_RL("failed to alloc fnr stats counter object\n"); + spin_unlock(&ipa3_ctx->flt_rt_counters.hdl_lock); + return -ENOMEM; + } + memcpy(counter, header, sizeof(struct ipa_ioc_flt_rt_counter_alloc)); /* allocate hw counters */ counter->hw_counter.start_id = 0; counter->hw_counter.end_id = 0; @@ -7024,7 +7032,7 @@ mark_hw_cnt: unused_start_id = counter->hw_counter.start_id; if (unused_start_id < 1 || unused_start_id > IPA_FLT_RT_HW_COUNTER) { - IPAERR("unexpected hw_counter start id %d\n", + IPAERR_RL("unexpected hw_counter start id %d\n", unused_start_id); goto err; } @@ -7039,7 +7047,7 @@ mark_sw_cnt: - IPA_FLT_RT_HW_COUNTER; if (unused_start_id < 1 || unused_start_id > IPA_FLT_RT_SW_COUNTER) { - IPAERR("unexpected sw_counter start id %d\n", + IPAERR_RL("unexpected sw_counter start id %d\n", unused_start_id); goto err; } @@ -7051,10 +7059,12 @@ done: counter->hdl = __ipa3_alloc_counter_hdl(counter); spin_unlock(&ipa3_ctx->flt_rt_counters.hdl_lock); idr_preload_end(); + memcpy(header, counter, sizeof(struct ipa_ioc_flt_rt_counter_alloc)); return 0; err: counter->hdl = -1; + kmem_cache_free(ipa3_ctx->fnr_stats_cache, counter); spin_unlock(&ipa3_ctx->flt_rt_counters.hdl_lock); idr_preload_end(); return -ENOMEM; @@ -7068,7 +7078,7 @@ void ipa3_counter_remove_hdl(int hdl) spin_lock(&ipa3_ctx->flt_rt_counters.hdl_lock); counter = idr_find(&ipa3_ctx->flt_rt_counters.hdl, hdl); if (counter == NULL) { - IPAERR("unexpected hdl %d\n", hdl); + IPAERR_RL("unexpected hdl %d\n", hdl); goto err; } /* remove counters belong to this hdl, set used back to 0 */ @@ -7078,7 +7088,7 @@ void ipa3_counter_remove_hdl(int hdl) memset(&ipa3_ctx->flt_rt_counters.used_hw + offset, 0, counter->hw_counter.num_counters * sizeof(bool)); } else { - IPAERR("unexpected hdl %d\n", hdl); + IPAERR_RL("unexpected hdl %d\n", hdl); goto err; } offset = counter->sw_counter.start_id - 1 - IPA_FLT_RT_HW_COUNTER; @@ -7087,11 +7097,12 @@ void ipa3_counter_remove_hdl(int hdl) memset(&ipa3_ctx->flt_rt_counters.used_sw + offset, 0, counter->sw_counter.num_counters * sizeof(bool)); } else { - IPAERR("unexpected hdl %d\n", hdl); + IPAERR_RL("unexpected hdl %d\n", hdl); goto err; } /* remove the handle */ idr_remove(&ipa3_ctx->flt_rt_counters.hdl, hdl); + kmem_cache_free(ipa3_ctx->fnr_stats_cache, counter); err: spin_unlock(&ipa3_ctx->flt_rt_counters.hdl_lock); } @@ -7108,8 +7119,10 @@ void ipa3_counter_id_remove_all(void) memset(&ipa3_ctx->flt_rt_counters.used_sw, 0, sizeof(ipa3_ctx->flt_rt_counters.used_sw)); /* remove all handles */ - idr_for_each_entry(&ipa3_ctx->flt_rt_counters.hdl, counter, hdl) + idr_for_each_entry(&ipa3_ctx->flt_rt_counters.hdl, counter, hdl) { idr_remove(&ipa3_ctx->flt_rt_counters.hdl, hdl); + kmem_cache_free(ipa3_ctx->fnr_stats_cache, counter); + } spin_unlock(&ipa3_ctx->flt_rt_counters.hdl_lock); } @@ -7653,7 +7666,7 @@ u32 ipa3_get_num_pipes(void) /** * ipa3_disable_apps_wan_cons_deaggr()- - * set ipa_ctx->ipa_client_apps_wan_cons_agg_gro + * set ipa3_ctx->ipa_client_apps_wan_cons_agg_gro * * Return value: 0 or negative in case of failure */