• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2021 SUSE LLC <mdoucha@suse.cz>
4  * Copyright (c) 2022 Linux Test Project
5  *
6  * CVE-2020-25704
7  *
8  * Check for memory leak in PERF_EVENT_IOC_SET_FILTER ioctl command. Fixed in:
9  *
10  *  commit 7bdb157cdebbf95a1cd94ed2e01b338714075d00
11  *  Author: kiyin(尹亮) <kiyin@tencent.com>
12  *  Date:   Wed Nov 4 08:23:22 2020 +0300
13  *
14  *  perf/core: Fix a memory leak in perf_event_parse_addr_filter()
15  */
16 
17 #include "config.h"
18 #include "tst_test.h"
19 #include "tst_timer.h"
20 #include "lapi/syscalls.h"
21 
22 #include "perf_event_open.h"
23 
24 #define INTEL_PT_PATH "/sys/bus/event_source/devices/intel_pt/type"
25 
26 const int iterations = 12000000;
27 static int fd = -1;
28 static int runtime;
29 
setup(void)30 static void setup(void)
31 {
32 	struct perf_event_attr ev = {
33 		.size = sizeof(struct perf_event_attr),
34 		.exclude_kernel = 1,
35 		.exclude_hv = 1,
36 		.exclude_idle = 1
37 	};
38 
39 	/* intel_pt is currently the only event source that supports filters */
40 	if (access(INTEL_PT_PATH, F_OK))
41 		tst_brk(TCONF, "intel_pt is not available");
42 
43 	SAFE_FILE_SCANF(INTEL_PT_PATH, "%d", &ev.type);
44 	fd = perf_event_open(&ev, getpid(), -1, -1, 0);
45 
46 	runtime = tst_remaining_runtime();
47 }
48 
49 /*
50  * Check how fast we can do the iterations after 5 seconds of runtime.
51  * If the rate is too small to complete for current runtime then
52  * stop the test.
53  */
check_progress(int i)54 static void check_progress(int i)
55 {
56 	static float iter_per_ms;
57 	long long elapsed_ms;
58 
59 	if (iter_per_ms)
60 		return;
61 
62 	if (i % 1000 != 0)
63 		return;
64 
65 	tst_timer_stop();
66 	elapsed_ms = tst_timer_elapsed_ms();
67 	if (elapsed_ms > 5000) {
68 		iter_per_ms = (float) i / elapsed_ms;
69 		tst_res(TINFO, "rate: %f iters/ms", iter_per_ms);
70 		tst_res(TINFO, "needed rate for current test runtime: %f iters/ms",
71 			(float) iterations / (runtime * 1000));
72 
73 		if (iter_per_ms * 1000 * (runtime - 1) < iterations)
74 			tst_brk(TCONF, "System too slow to complete test in specified runtime");
75 	}
76 }
77 
run(void)78 static void run(void)
79 {
80 	long diff;
81 	int i;
82 
83 	diff = SAFE_READ_MEMINFO("MemAvailable:");
84 	tst_timer_start(CLOCK_MONOTONIC);
85 
86 	/* leak about 100MB of RAM */
87 	for (i = 0; i < iterations; i++) {
88 		ioctl(fd, PERF_EVENT_IOC_SET_FILTER, "filter,0/0@abcd");
89 		check_progress(i);
90 	}
91 
92 	diff -= SAFE_READ_MEMINFO("MemAvailable:");
93 
94 	if (diff > 50 * 1024)
95 		tst_res(TFAIL, "Likely kernel memory leak detected");
96 	else
97 		tst_res(TPASS, "No memory leak found");
98 }
99 
cleanup(void)100 static void cleanup(void)
101 {
102 	if (fd >= 0)
103 		SAFE_CLOSE(fd);
104 }
105 
106 static struct tst_test test = {
107 	.test_all = run,
108 	.setup = setup,
109 	.cleanup = cleanup,
110 	.needs_root = 1,
111 	.max_runtime = 300,
112 	.tags = (const struct tst_tag[]) {
113 		{"linux-git", "7bdb157cdebb"},
114 		{"CVE", "2020-25704"},
115 		{}
116 	}
117 };
118