From: "kiyin(尹亮)" kiyin@tencent.com
commit 7bdb157cdebbf95a1cd94ed2e01b338714075d00 upstream
As shown through runtime testing, the "filename" allocation is not always freed in perf_event_parse_addr_filter().
There are three possible ways that this could happen:
- It could be allocated twice on subsequent iterations through the loop, - or leaked on the success path, - or on the failure path.
Clean up the code flow to make it obvious that 'filename' is always freed in the reallocation path and in the two return paths as well.
We rely on the fact that kfree(NULL) is NOP and filename is initialized with NULL.
This fixes the leak. No other side effects expected.
[ Dan Carpenter: cleaned up the code flow & added a changelog. ] [ Ingo Molnar: updated the changelog some more. ]
Fixes: 375637bc5249 ("perf/core: Introduce address range filtering") Signed-off-by: "kiyin(尹亮)" kiyin@tencent.com Signed-off-by: Dan Carpenter dan.carpenter@oracle.com Signed-off-by: Ingo Molnar mingo@kernel.org Cc: "Srivatsa S. Bhat" srivatsa@csail.mit.edu Cc: Anthony Liguori aliguori@amazon.com [sudip: Backported to 4.9: adjust context] Signed-off-by: Sudip Mukherjee sudipm.mukherjee@gmail.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- kernel/events/core.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
--- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -8261,6 +8261,7 @@ perf_event_parse_addr_filter(struct perf if (token == IF_SRC_FILE || token == IF_SRC_FILEADDR) { int fpos = filter->range ? 2 : 1;
+ kfree(filename); filename = match_strdup(&args[fpos]); if (!filename) { ret = -ENOMEM; @@ -8292,10 +8293,7 @@ perf_event_parse_addr_filter(struct perf ret = kern_path(filename, LOOKUP_FOLLOW, &filter->path); if (ret) - goto fail_free_name; - - kfree(filename); - filename = NULL; + goto fail;
ret = -EINVAL; if (!filter->path.dentry || @@ -8313,13 +8311,13 @@ perf_event_parse_addr_filter(struct perf if (state != IF_STATE_ACTION) goto fail;
+ kfree(filename); kfree(orig);
return 0;
-fail_free_name: - kfree(filename); fail: + kfree(filename); free_filters_list(filters); kfree(orig);