mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-22 15:03:53 +02:00
perf tools: Fix use-after-free in help_unknown_cmd()
[ Upstream commit1fdf938168
] Currently perf aborts when it finds an invalid command. I guess it depends on the environment as I have some custom commands in the path. $ perf bad-command perf: 'bad-command' is not a perf-command. See 'perf --help'. Aborted (core dumped) It's because the exclude_cmds() in libsubcmd has a use-after-free when it removes some entries. After copying one to another entry, it keeps the pointer in the both position. And the next copy operation will free the later one but it's the same entry in the previous one. For example, let's say cmds = { A, B, C, D, E } and excludes = { B, E }. ci cj ei cmds-name excludes -----------+-------------------- 0 0 0 | A B : cmp < 0, ci == cj 1 1 0 | B B : cmp == 0 2 1 1 | C E : cmp < 0, ci != cj At this point, it frees cmds->names[1] and cmds->names[1] is assigned to cmds->names[2]. 3 2 1 | D E : cmp < 0, ci != cj Now it frees cmds->names[2] but it's the same as cmds->names[1]. So accessing cmds->names[1] will be invalid. This makes the subcmd tests succeed. $ perf test subcmd 69: libsubcmd help tests : 69.1: Load subcmd names : Ok 69.2: Uniquify subcmd names : Ok 69.3: Exclude duplicate subcmd names : Ok Fixes:4b96679170
("libsubcmd: Avoid SEGV/use-after-free when commands aren't excluded") Reviewed-by: Ian Rogers <irogers@google.com> Link: https://lore.kernel.org/r/20250701201027.1171561-3-namhyung@kernel.org Signed-off-by: Namhyung Kim <namhyung@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
a99cae46ab
commit
9fe9f94599
|
@ -9,6 +9,7 @@
|
|||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <assert.h>
|
||||
#include "subcmd-util.h"
|
||||
#include "help.h"
|
||||
#include "exec-cmd.h"
|
||||
|
@ -82,10 +83,11 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
|
|||
ci++;
|
||||
cj++;
|
||||
} else {
|
||||
zfree(&cmds->names[cj]);
|
||||
cmds->names[cj++] = cmds->names[ci++];
|
||||
cmds->names[cj++] = cmds->names[ci];
|
||||
cmds->names[ci++] = NULL;
|
||||
}
|
||||
} else if (cmp == 0) {
|
||||
zfree(&cmds->names[ci]);
|
||||
ci++;
|
||||
ei++;
|
||||
} else if (cmp > 0) {
|
||||
|
@ -94,12 +96,12 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
|
|||
}
|
||||
if (ci != cj) {
|
||||
while (ci < cmds->cnt) {
|
||||
zfree(&cmds->names[cj]);
|
||||
cmds->names[cj++] = cmds->names[ci++];
|
||||
cmds->names[cj++] = cmds->names[ci];
|
||||
cmds->names[ci++] = NULL;
|
||||
}
|
||||
}
|
||||
for (ci = cj; ci < cmds->cnt; ci++)
|
||||
zfree(&cmds->names[ci]);
|
||||
assert(cmds->names[ci] == NULL);
|
||||
cmds->cnt = cj;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user