xref: /linux/tools/perf/util/aslr.c (revision 00599d4841790d05401820a96cf7edb193888b00)
1febea9ecSIan Rogers // SPDX-License-Identifier: GPL-2.0
2febea9ecSIan Rogers #include "aslr.h"
3febea9ecSIan Rogers 
4febea9ecSIan Rogers #include "addr_location.h"
5febea9ecSIan Rogers #include "debug.h"
6febea9ecSIan Rogers #include "event.h"
7febea9ecSIan Rogers #include "evsel.h"
8febea9ecSIan Rogers #include "evlist.h"
9febea9ecSIan Rogers #include "machine.h"
10febea9ecSIan Rogers #include "map.h"
11febea9ecSIan Rogers #include "thread.h"
12febea9ecSIan Rogers #include "tool.h"
13febea9ecSIan Rogers #include "session.h"
14febea9ecSIan Rogers #include "data.h"
15febea9ecSIan Rogers #include "dso.h"
16febea9ecSIan Rogers #include "pmus.h"
17febea9ecSIan Rogers 
18febea9ecSIan Rogers #include <internal/lib.h>  /* page_size */
19febea9ecSIan Rogers #include <linux/compiler.h>
20febea9ecSIan Rogers #include <linux/zalloc.h>
21d6dbf2d4SIan Rogers #include <errno.h>
22febea9ecSIan Rogers #include <inttypes.h>
23febea9ecSIan Rogers #include <unistd.h>
24575c6d2bSIan Rogers #include <byteswap.h>
25febea9ecSIan Rogers 
26febea9ecSIan Rogers /**
27febea9ecSIan Rogers  * struct remap_addresses_key - Key for mapping original addresses to remapped ones.
28febea9ecSIan Rogers  * @dso: Pointer to the DSO (Dynamic Shared Object) associated with the mapping.
29febea9ecSIan Rogers  * @invariant: Unique offset invariant within the VMA (Virtual Memory Area).
30febea9ecSIan Rogers  *             Calculated as `start - pgoff`. This value remains constant when
31febea9ecSIan Rogers  *             perf's internal `maps__fixup_overlap_and_insert` splits a map into
32febea9ecSIan Rogers  *             fragmented VMA pieces due to overlapping events, allowing us to
33febea9ecSIan Rogers  *             resolve split maps consistently back to the original VMA.
34febea9ecSIan Rogers  * @pid: Process ID associated with the mapping.
35febea9ecSIan Rogers  */
36febea9ecSIan Rogers struct remap_addresses_key {
37febea9ecSIan Rogers 	struct machine *machine;
38febea9ecSIan Rogers 	struct dso *dso;
39febea9ecSIan Rogers 	u64 invariant;
40febea9ecSIan Rogers 	pid_t pid;
41febea9ecSIan Rogers };
42febea9ecSIan Rogers 
43febea9ecSIan Rogers struct aslr_mapping {
44febea9ecSIan Rogers 	struct list_head node;
45febea9ecSIan Rogers 	u64 orig_start;
46febea9ecSIan Rogers 	u64 len;
47febea9ecSIan Rogers 	u64 remap_start;
48febea9ecSIan Rogers };
49febea9ecSIan Rogers 
50d6dbf2d4SIan Rogers struct aslr_evsel_priv {
51d6dbf2d4SIan Rogers 	u64 orig_sample_type;
52d6dbf2d4SIan Rogers 	u64 orig_sample_regs_user;
53d6dbf2d4SIan Rogers 	u64 orig_sample_regs_intr;
54d6dbf2d4SIan Rogers 	int orig_sample_size;
55d6dbf2d4SIan Rogers };
56d6dbf2d4SIan Rogers 
57d6dbf2d4SIan Rogers static size_t evsel_hash(long key, void *ctx __maybe_unused)
58d6dbf2d4SIan Rogers {
59d6dbf2d4SIan Rogers 	return (size_t)key;
60d6dbf2d4SIan Rogers }
61d6dbf2d4SIan Rogers 
62d6dbf2d4SIan Rogers static bool evsel_equal(long key1, long key2, void *ctx __maybe_unused)
63d6dbf2d4SIan Rogers {
64d6dbf2d4SIan Rogers 	return key1 == key2;
65d6dbf2d4SIan Rogers }
66d6dbf2d4SIan Rogers 
67febea9ecSIan Rogers struct process_top_address {
68febea9ecSIan Rogers 	u64 remapped_max;
69febea9ecSIan Rogers };
70febea9ecSIan Rogers struct aslr_tool {
71febea9ecSIan Rogers 	/** @tool: The tool implemented here and a pointer to a delegate to process the data. */
72febea9ecSIan Rogers 	struct delegate_tool tool;
73febea9ecSIan Rogers 	/** @machines: The machines with the input, not remapped, virtual address layout. */
74febea9ecSIan Rogers 	struct machines machines;
75febea9ecSIan Rogers 	/** @event_copy: Buffer used to create an event to pass to the delegate. */
76febea9ecSIan Rogers 	char event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8);
77febea9ecSIan Rogers 	/** @remap_addresses: mapping from remap_addresses_key to remapped address. */
78febea9ecSIan Rogers 	struct hashmap remap_addresses;
79febea9ecSIan Rogers 	/** @top_addresses: mapping from process to max remapped address. */
80febea9ecSIan Rogers 	struct hashmap top_addresses;
81d6dbf2d4SIan Rogers 	/**
82d6dbf2d4SIan Rogers 	 * @evsel_orig_attrs: mapping from evsel pointer to its original
83d6dbf2d4SIan Rogers 	 *                    unstripped sample_type and registers bitmasks.
84d6dbf2d4SIan Rogers 	 */
85d6dbf2d4SIan Rogers 	struct hashmap evsel_orig_attrs;
86febea9ecSIan Rogers };
87febea9ecSIan Rogers 
88febea9ecSIan Rogers static const pid_t kernel_pid = -1;
89febea9ecSIan Rogers 
90febea9ecSIan Rogers /* Start remapping user processes from a small non-zero offset. */
91febea9ecSIan Rogers static const u64 user_space_start = 0x200000;
92febea9ecSIan Rogers static const u64 kernel_space_start_64 = 0xffff800010000000ULL;
93febea9ecSIan Rogers static const u64 kernel_space_start_32 = 0x80000000ULL;
94febea9ecSIan Rogers 
95febea9ecSIan Rogers static size_t remap_addresses__hash(long _key, void *ctx __maybe_unused)
96febea9ecSIan Rogers {
97febea9ecSIan Rogers 	struct remap_addresses_key *key = (struct remap_addresses_key *)_key;
98febea9ecSIan Rogers 	void *dso_ptr = key->dso ? RC_CHK_ACCESS(key->dso) : NULL;
99febea9ecSIan Rogers 
100febea9ecSIan Rogers 	return (size_t)key->machine ^ (size_t)dso_ptr ^ key->invariant ^ key->pid;
101febea9ecSIan Rogers }
102febea9ecSIan Rogers 
103febea9ecSIan Rogers static bool remap_addresses__equal(long _key1, long _key2, void *ctx __maybe_unused)
104febea9ecSIan Rogers {
105febea9ecSIan Rogers 	struct remap_addresses_key *key1 = (struct remap_addresses_key *)_key1;
106febea9ecSIan Rogers 	struct remap_addresses_key *key2 = (struct remap_addresses_key *)_key2;
107febea9ecSIan Rogers 
108febea9ecSIan Rogers 	return key1->machine == key2->machine &&
109febea9ecSIan Rogers 	       RC_CHK_EQUAL(key1->dso, key2->dso) &&
110febea9ecSIan Rogers 	       key1->invariant == key2->invariant &&
111febea9ecSIan Rogers 	       key1->pid == key2->pid;
112febea9ecSIan Rogers }
113febea9ecSIan Rogers 
114febea9ecSIan Rogers struct top_addresses_key {
115febea9ecSIan Rogers 	struct machine *machine;
116febea9ecSIan Rogers 	pid_t pid;
117febea9ecSIan Rogers };
118febea9ecSIan Rogers 
119febea9ecSIan Rogers static size_t top_addresses__hash(long _key, void *ctx __maybe_unused)
120febea9ecSIan Rogers {
121febea9ecSIan Rogers 	struct top_addresses_key *key = (struct top_addresses_key *)_key;
122febea9ecSIan Rogers 
123febea9ecSIan Rogers 	return (size_t)key->machine ^ key->pid;
124febea9ecSIan Rogers }
125febea9ecSIan Rogers 
126febea9ecSIan Rogers static bool top_addresses__equal(long _key1, long _key2, void *ctx __maybe_unused)
127febea9ecSIan Rogers {
128febea9ecSIan Rogers 	struct top_addresses_key *key1 = (struct top_addresses_key *)_key1;
129febea9ecSIan Rogers 	struct top_addresses_key *key2 = (struct top_addresses_key *)_key2;
130febea9ecSIan Rogers 
131febea9ecSIan Rogers 	return key1->machine == key2->machine && key1->pid == key2->pid;
132febea9ecSIan Rogers }
133febea9ecSIan Rogers 
134febea9ecSIan Rogers static u64 round_up_to_page_size(u64 addr)
135febea9ecSIan Rogers {
136febea9ecSIan Rogers 	return (addr + page_size - 1) & ~((u64)page_size - 1);
137febea9ecSIan Rogers }
138febea9ecSIan Rogers 
139575c6d2bSIan Rogers static u64 aslr_tool__remap_address(struct aslr_tool *aslr,
140575c6d2bSIan Rogers 				    struct thread *aslr_thread,
141575c6d2bSIan Rogers 				    u8 cpumode,
142575c6d2bSIan Rogers 				    u64 addr)
143575c6d2bSIan Rogers {
144575c6d2bSIan Rogers 	struct addr_location al;
145575c6d2bSIan Rogers 	struct remap_addresses_key key;
146575c6d2bSIan Rogers 	u64 *remapped_invariant_ptr = NULL;
147575c6d2bSIan Rogers 	u64 remap_addr = 0;
148575c6d2bSIan Rogers 	u8 effective_cpumode = cpumode;
149d6dbf2d4SIan Rogers 	struct dso *dso;
150d6dbf2d4SIan Rogers 	const char *dso_name;
151575c6d2bSIan Rogers 
152575c6d2bSIan Rogers 	if (!aslr_thread)
153575c6d2bSIan Rogers 		return 0; /* No thread. */
154575c6d2bSIan Rogers 
155575c6d2bSIan Rogers 	addr_location__init(&al);
156575c6d2bSIan Rogers 	if (!thread__find_map(aslr_thread, cpumode, addr, &al)) {
157575c6d2bSIan Rogers 		/*
158575c6d2bSIan Rogers 		 * If lookup fails with specified cpumode, try fallback to the other space
159575c6d2bSIan Rogers 		 * to be robust against bad cpumode in samples.
160575c6d2bSIan Rogers 		 */
161575c6d2bSIan Rogers 		if (cpumode == PERF_RECORD_MISC_KERNEL)
162575c6d2bSIan Rogers 			effective_cpumode = PERF_RECORD_MISC_USER;
163575c6d2bSIan Rogers 		else if (cpumode == PERF_RECORD_MISC_USER)
164575c6d2bSIan Rogers 			effective_cpumode = PERF_RECORD_MISC_KERNEL;
165575c6d2bSIan Rogers 		else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL)
166575c6d2bSIan Rogers 			effective_cpumode = PERF_RECORD_MISC_GUEST_USER;
167575c6d2bSIan Rogers 		else if (cpumode == PERF_RECORD_MISC_GUEST_USER)
168575c6d2bSIan Rogers 			effective_cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
169575c6d2bSIan Rogers 
170575c6d2bSIan Rogers 		if (!thread__find_map(aslr_thread, effective_cpumode, addr, &al)) {
171575c6d2bSIan Rogers 			addr_location__exit(&al);
172575c6d2bSIan Rogers 			return 0; /* No mmap. */
173575c6d2bSIan Rogers 		}
174575c6d2bSIan Rogers 	}
175575c6d2bSIan Rogers 
176d6dbf2d4SIan Rogers 	dso = map__dso(al.map);
177d6dbf2d4SIan Rogers 	dso_name = dso ? dso__long_name(dso) : NULL;
178d6dbf2d4SIan Rogers 
179575c6d2bSIan Rogers 	key.machine = maps__machine(thread__maps(aslr_thread));
180d6dbf2d4SIan Rogers 	key.dso = dso;
181d6dbf2d4SIan Rogers 	if (dso && !is_anon_memory(dso_name) && !is_no_dso_memory(dso_name))
182575c6d2bSIan Rogers 		key.invariant = map__start(al.map) - map__pgoff(al.map);
183d6dbf2d4SIan Rogers 	else
184d6dbf2d4SIan Rogers 		key.invariant = map__start(al.map);
185575c6d2bSIan Rogers 	key.pid = (effective_cpumode == PERF_RECORD_MISC_KERNEL ||
186575c6d2bSIan Rogers 		   effective_cpumode == PERF_RECORD_MISC_GUEST_KERNEL) ?
187575c6d2bSIan Rogers 		  kernel_pid : thread__pid(aslr_thread);
188575c6d2bSIan Rogers 
189575c6d2bSIan Rogers 	if (hashmap__find(&aslr->remap_addresses, &key, &remapped_invariant_ptr)) {
190575c6d2bSIan Rogers 		remap_addr = *remapped_invariant_ptr + map__pgoff(al.map) +
191575c6d2bSIan Rogers 			     (addr - map__start(al.map));
192575c6d2bSIan Rogers 	} else {
193575c6d2bSIan Rogers 		pr_debug("Cannot find a remapped entry for address %" PRIx64 " in mapping %" PRIx64 "(%zu) for pid=%d\n",
194575c6d2bSIan Rogers 			 addr, map__start(al.map), map__size(al.map), key.pid);
195575c6d2bSIan Rogers 	}
196575c6d2bSIan Rogers 
197575c6d2bSIan Rogers 	addr_location__exit(&al);
198575c6d2bSIan Rogers 	return remap_addr;
199575c6d2bSIan Rogers }
200575c6d2bSIan Rogers 
201febea9ecSIan Rogers struct aslr_machine_priv {
202febea9ecSIan Rogers 	bool kernel_maps_loaded;
203febea9ecSIan Rogers };
204febea9ecSIan Rogers 
205febea9ecSIan Rogers static int aslr_tool__preload_kernel_maps(struct machine *machine)
206febea9ecSIan Rogers {
207febea9ecSIan Rogers 	struct aslr_machine_priv *mpriv = machine->priv;
208febea9ecSIan Rogers 
209febea9ecSIan Rogers 	if (!mpriv) {
210febea9ecSIan Rogers 		mpriv = zalloc(sizeof(*mpriv));
211febea9ecSIan Rogers 		if (!mpriv)
212febea9ecSIan Rogers 			return -ENOMEM;
213febea9ecSIan Rogers 		machine->priv = mpriv;
214febea9ecSIan Rogers 	}
215febea9ecSIan Rogers 
216febea9ecSIan Rogers 	if (!mpriv->kernel_maps_loaded) {
217febea9ecSIan Rogers 		struct maps *kmaps = machine__kernel_maps(machine);
218febea9ecSIan Rogers 
219febea9ecSIan Rogers 		if (kmaps) {
220febea9ecSIan Rogers 			int err = maps__load_maps(kmaps);
221febea9ecSIan Rogers 
222febea9ecSIan Rogers 			if (err < 0) {
223febea9ecSIan Rogers 				pr_err("ASLR: Failed to preload kernel maps for machine pid %d\n",
224febea9ecSIan Rogers 				       machine->pid);
225febea9ecSIan Rogers 				return err;
226febea9ecSIan Rogers 			}
227febea9ecSIan Rogers 		}
228febea9ecSIan Rogers 		mpriv->kernel_maps_loaded = true;
229febea9ecSIan Rogers 	}
230febea9ecSIan Rogers 	return 0;
231febea9ecSIan Rogers }
232febea9ecSIan Rogers 
233febea9ecSIan Rogers static void aslr_tool__free_machine_priv(struct machine *machine)
234febea9ecSIan Rogers {
235febea9ecSIan Rogers 	free(machine->priv);
236febea9ecSIan Rogers 	machine->priv = NULL;
237febea9ecSIan Rogers }
238febea9ecSIan Rogers 
239febea9ecSIan Rogers static void aslr_tool__destroy_machines_priv(struct machines *machines)
240febea9ecSIan Rogers {
241febea9ecSIan Rogers 	struct rb_node *nd;
242febea9ecSIan Rogers 
243febea9ecSIan Rogers 	aslr_tool__free_machine_priv(&machines->host);
244febea9ecSIan Rogers 	for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) {
245febea9ecSIan Rogers 		struct machine *machine = rb_entry(nd, struct machine, rb_node);
246febea9ecSIan Rogers 
247febea9ecSIan Rogers 		aslr_tool__free_machine_priv(machine);
248febea9ecSIan Rogers 	}
249febea9ecSIan Rogers }
250febea9ecSIan Rogers 
251febea9ecSIan Rogers static u64 aslr_tool__findnew_mapping(struct aslr_tool *aslr,
252febea9ecSIan Rogers 				      struct machine *session_machine,
253febea9ecSIan Rogers 				      struct thread *aslr_thread,
254febea9ecSIan Rogers 				      u8 cpumode, u64 start,
255febea9ecSIan Rogers 				      u64 len, u64 pgoff)
256febea9ecSIan Rogers {
257febea9ecSIan Rogers 	/* Address location for dso lookup. */
258febea9ecSIan Rogers 	struct addr_location al;
259febea9ecSIan Rogers 	/* Original ASLR address based key for the remap table. */
260febea9ecSIan Rogers 	struct remap_addresses_key remap_key;
261febea9ecSIan Rogers 	/* The address in the ASLR sanitized address space less pg_off. */
262febea9ecSIan Rogers 	u64 *remapped_invariant_ptr;
263febea9ecSIan Rogers 	/* Key for the maximum address in a process. */
264febea9ecSIan Rogers 	struct top_addresses_key top_addr_key;
265febea9ecSIan Rogers 	/* Value in top address table. */
266febea9ecSIan Rogers 	struct process_top_address *top = NULL;
267febea9ecSIan Rogers 	/* Address in ASLR sanitized address space. */
268febea9ecSIan Rogers 	u64 remap_addr;
269febea9ecSIan Rogers 	/* Potentially allocated remap table key. */
270febea9ecSIan Rogers 	struct remap_addresses_key *new_remap_key = NULL;
271febea9ecSIan Rogers 	/*
272febea9ecSIan Rogers 	 * Potentially allocated remap table key.
273febea9ecSIan Rogers 	 * TODO: Avoid allocation necessary for perf 32-bit binary support.
274febea9ecSIan Rogers 	 */
275febea9ecSIan Rogers 	u64 *new_remap_val = NULL;
276febea9ecSIan Rogers 	int err;
277febea9ecSIan Rogers 
278febea9ecSIan Rogers 	if (!aslr_thread)
279febea9ecSIan Rogers 		return 0;
280febea9ecSIan Rogers 
281febea9ecSIan Rogers 	/* The key to look up an incoming address to the outgoing value. */
282febea9ecSIan Rogers 	addr_location__init(&al);
283febea9ecSIan Rogers 	remap_key.machine = maps__machine(thread__maps(aslr_thread));
284febea9ecSIan Rogers 	remap_key.pid = (cpumode == PERF_RECORD_MISC_KERNEL ||
285febea9ecSIan Rogers 			 cpumode == PERF_RECORD_MISC_GUEST_KERNEL) ?
286febea9ecSIan Rogers 			kernel_pid : thread__pid(aslr_thread);
287febea9ecSIan Rogers 	if (thread__find_map(aslr_thread, cpumode, start, &al)) {
288febea9ecSIan Rogers 		struct dso *dso = map__dso(al.map);
289febea9ecSIan Rogers 		const char *dso_name = dso ? dso__long_name(dso) : NULL;
290febea9ecSIan Rogers 
291febea9ecSIan Rogers 		remap_key.dso = dso;
292febea9ecSIan Rogers 		if (dso && !is_anon_memory(dso_name) && !is_no_dso_memory(dso_name))
293febea9ecSIan Rogers 			remap_key.invariant = map__start(al.map) - map__pgoff(al.map);
294febea9ecSIan Rogers 		else
295febea9ecSIan Rogers 			remap_key.invariant = map__start(al.map);
296febea9ecSIan Rogers 	} else {
297febea9ecSIan Rogers 		remap_key.dso = NULL;
298febea9ecSIan Rogers 		remap_key.invariant = start;
299febea9ecSIan Rogers 	}
300febea9ecSIan Rogers 
301febea9ecSIan Rogers 	/* The key to look up top allocated address. */
302febea9ecSIan Rogers 	top_addr_key.machine = remap_key.machine;
303febea9ecSIan Rogers 	top_addr_key.pid = remap_key.pid;
304febea9ecSIan Rogers 
305febea9ecSIan Rogers 	if (hashmap__find(&aslr->remap_addresses, &remap_key, &remapped_invariant_ptr)) {
306febea9ecSIan Rogers 		/* Mmap already exists. */
307febea9ecSIan Rogers 		u64 calculated_max;
308febea9ecSIan Rogers 
309febea9ecSIan Rogers 		if (al.map) {
310febea9ecSIan Rogers 			/*
311febea9ecSIan Rogers 			 * The cached value is the base of the invariant. We add the
312febea9ecSIan Rogers 			 * offset into the VMA (start - map__start), plus the map's
313febea9ecSIan Rogers 			 * pgoff, to get the precise virtual address within this chunk.
314febea9ecSIan Rogers 			 */
315febea9ecSIan Rogers 			remap_addr = *remapped_invariant_ptr + map__pgoff(al.map) +
316febea9ecSIan Rogers 				     (start - map__start(al.map));
317febea9ecSIan Rogers 		} else {
318febea9ecSIan Rogers 			/*
319febea9ecSIan Rogers 			 * For unmapped memory (e.g. kernel anonymous), the cached value
320febea9ecSIan Rogers 			 * was stored offset by pgoff. Adding pgoff yields the true remap_addr.
321febea9ecSIan Rogers 			 */
322febea9ecSIan Rogers 			remap_addr = *remapped_invariant_ptr + pgoff;
323febea9ecSIan Rogers 		}
324febea9ecSIan Rogers 
325febea9ecSIan Rogers 		calculated_max = remap_addr + len;
326febea9ecSIan Rogers 
327febea9ecSIan Rogers 		/* See if top mapping was expanded. */
328febea9ecSIan Rogers 		if (hashmap__find(&aslr->top_addresses, &top_addr_key, &top)) {
329febea9ecSIan Rogers 			if (calculated_max > top->remapped_max)
330febea9ecSIan Rogers 				top->remapped_max = calculated_max;
331febea9ecSIan Rogers 		}
332febea9ecSIan Rogers 		addr_location__exit(&al);
333febea9ecSIan Rogers 		return remap_addr;
334febea9ecSIan Rogers 	}
335febea9ecSIan Rogers 	/* No mmap, create an entry from the top address. */
336febea9ecSIan Rogers 	if (hashmap__find(&aslr->top_addresses, &top_addr_key, &top)) {
337febea9ecSIan Rogers 		struct addr_location prev_al;
338febea9ecSIan Rogers 		bool is_contiguous = false;
339febea9ecSIan Rogers 
340febea9ecSIan Rogers 		/* Current max allocated mmap address within the process. */
341febea9ecSIan Rogers 		remap_addr = top->remapped_max;
342febea9ecSIan Rogers 
343febea9ecSIan Rogers 		addr_location__init(&prev_al);
344febea9ecSIan Rogers 		if (thread__find_map(aslr_thread, cpumode, start - 1, &prev_al)) {
345febea9ecSIan Rogers 			if (map__end(prev_al.map) == start)
346febea9ecSIan Rogers 				is_contiguous = true;
347febea9ecSIan Rogers 		}
348febea9ecSIan Rogers 		addr_location__exit(&prev_al);
349febea9ecSIan Rogers 
350febea9ecSIan Rogers 		if (is_contiguous) {
351febea9ecSIan Rogers 			/* Contiguous mapping, do not add 1 page gap! */
352febea9ecSIan Rogers 			remap_addr = round_up_to_page_size(remap_addr);
353febea9ecSIan Rogers 		} else {
354febea9ecSIan Rogers 			/* Give 1 page gap from current max page. */
355febea9ecSIan Rogers 			remap_addr = round_up_to_page_size(remap_addr);
356febea9ecSIan Rogers 			remap_addr += page_size;
357febea9ecSIan Rogers 		}
358febea9ecSIan Rogers 		if (remap_addr + len > top->remapped_max)
359febea9ecSIan Rogers 			top->remapped_max = remap_addr + len;
360febea9ecSIan Rogers 	} else {
361febea9ecSIan Rogers 		/* First address of the process, allocate key and first top address. */
362febea9ecSIan Rogers 		struct top_addresses_key *tk;
363febea9ecSIan Rogers 		struct process_top_address *top_val;
364febea9ecSIan Rogers 		struct perf_env *env = session_machine ? session_machine->env : NULL;
365febea9ecSIan Rogers 		bool is_64 = env ? perf_env__kernel_is_64_bit(env) : (sizeof(void *) == 8);
366febea9ecSIan Rogers 		u64 kernel_start_addr = is_64 ? kernel_space_start_64 : kernel_space_start_32;
367febea9ecSIan Rogers 
368febea9ecSIan Rogers 		remap_addr = (cpumode == PERF_RECORD_MISC_KERNEL ||
369febea9ecSIan Rogers 			      cpumode == PERF_RECORD_MISC_GUEST_KERNEL) ?
370febea9ecSIan Rogers 			     kernel_start_addr : user_space_start;
371febea9ecSIan Rogers 		remap_addr = round_up_to_page_size(remap_addr);
372febea9ecSIan Rogers 
373febea9ecSIan Rogers 		tk = malloc(sizeof(*tk));
374febea9ecSIan Rogers 		top_val = malloc(sizeof(*top_val));
375febea9ecSIan Rogers 		if (!tk || !top_val) {
376febea9ecSIan Rogers 			err = -ENOMEM;
377febea9ecSIan Rogers 		} else {
378febea9ecSIan Rogers 			*tk = top_addr_key;
379febea9ecSIan Rogers 			top_val->remapped_max = remap_addr + len;
380febea9ecSIan Rogers 			err = hashmap__insert(&aslr->top_addresses, tk, top_val,
381febea9ecSIan Rogers 					      HASHMAP_ADD, NULL, NULL);
382febea9ecSIan Rogers 		}
383febea9ecSIan Rogers 		if (err) {
384febea9ecSIan Rogers 			errno = -err;
385febea9ecSIan Rogers 			pr_err("Failure to add ASLR process top address %m\n");
386febea9ecSIan Rogers 			free(tk);
387febea9ecSIan Rogers 			free(top_val);
388febea9ecSIan Rogers 			addr_location__exit(&al);
389febea9ecSIan Rogers 			return 0;
390febea9ecSIan Rogers 		}
391febea9ecSIan Rogers 	}
392febea9ecSIan Rogers 	/* Create rmeapping entry. */
393febea9ecSIan Rogers 	new_remap_key = malloc(sizeof(*new_remap_key));
394febea9ecSIan Rogers 	new_remap_val = malloc(sizeof(u64));
395febea9ecSIan Rogers 	if (!new_remap_key || !new_remap_val) {
396febea9ecSIan Rogers 		err = -ENOMEM;
397febea9ecSIan Rogers 	} else {
398febea9ecSIan Rogers 		*new_remap_key = remap_key;
399febea9ecSIan Rogers 		new_remap_key->dso = dso__get(remap_key.dso);
400febea9ecSIan Rogers 		if (cpumode == PERF_RECORD_MISC_KERNEL ||
401febea9ecSIan Rogers 		    cpumode == PERF_RECORD_MISC_GUEST_KERNEL) {
402febea9ecSIan Rogers 			if (al.map) {
403febea9ecSIan Rogers 				*new_remap_val = remap_addr -
404febea9ecSIan Rogers 						 (start - map__start(al.map)) -
405febea9ecSIan Rogers 						 map__pgoff(al.map);
406febea9ecSIan Rogers 			} else {
407febea9ecSIan Rogers 				/*
408febea9ecSIan Rogers 				 * Subtract pgoff from the base virtual address so that
409febea9ecSIan Rogers 				 * when the lookup path adds pgoff back, it perfectly
410febea9ecSIan Rogers 				 * cancels out and returns remap_addr.
411febea9ecSIan Rogers 				 */
412febea9ecSIan Rogers 				*new_remap_val = remap_addr - pgoff;
413febea9ecSIan Rogers 			}
414febea9ecSIan Rogers 		} else {
415febea9ecSIan Rogers 			*new_remap_val = remap_addr - (al.map ? (start - map__start(al.map)) +
416febea9ecSIan Rogers 							    map__pgoff(al.map) : pgoff);
417febea9ecSIan Rogers 		}
418febea9ecSIan Rogers 		err = hashmap__add(&aslr->remap_addresses, new_remap_key, new_remap_val);
419febea9ecSIan Rogers 		if (err)
420febea9ecSIan Rogers 			dso__put(new_remap_key->dso);
421febea9ecSIan Rogers 	}
422febea9ecSIan Rogers 	if (err) {
423febea9ecSIan Rogers 		errno = -err;
424febea9ecSIan Rogers 		pr_err("Failure to add ASLR remapping %m\n");
425febea9ecSIan Rogers 		free(new_remap_key);
426febea9ecSIan Rogers 		free(new_remap_val);
427febea9ecSIan Rogers 		addr_location__exit(&al);
428febea9ecSIan Rogers 		return 0;
429febea9ecSIan Rogers 	}
430febea9ecSIan Rogers 	addr_location__exit(&al);
431febea9ecSIan Rogers 	return remap_addr;
432febea9ecSIan Rogers }
433febea9ecSIan Rogers 
434febea9ecSIan Rogers static int aslr_tool__process_mmap(const struct perf_tool *tool,
435febea9ecSIan Rogers 				   union perf_event *event,
436febea9ecSIan Rogers 				   struct perf_sample *sample,
437febea9ecSIan Rogers 				   struct machine *machine)
438febea9ecSIan Rogers {
439febea9ecSIan Rogers 	struct delegate_tool *del_tool;
440febea9ecSIan Rogers 	struct aslr_tool *aslr;
441febea9ecSIan Rogers 	struct perf_tool *delegate;
442febea9ecSIan Rogers 	union perf_event *new_event;
443febea9ecSIan Rogers 	u8 cpumode;
444febea9ecSIan Rogers 	struct thread *thread;
445febea9ecSIan Rogers 	struct machine *aslr_machine;
446febea9ecSIan Rogers 	int err;
447febea9ecSIan Rogers 
448febea9ecSIan Rogers 	del_tool = container_of(tool, struct delegate_tool, tool);
449febea9ecSIan Rogers 	aslr = container_of(del_tool, struct aslr_tool, tool);
450febea9ecSIan Rogers 	delegate = aslr->tool.delegate;
451febea9ecSIan Rogers 	new_event = (union perf_event *)aslr->event_copy;
452febea9ecSIan Rogers 	cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
453febea9ecSIan Rogers 
454febea9ecSIan Rogers 	aslr_machine = machines__findnew(&aslr->machines, machine->pid);
455febea9ecSIan Rogers 	if (!aslr_machine)
456febea9ecSIan Rogers 		return -ENOMEM;
457febea9ecSIan Rogers 	if (aslr_tool__preload_kernel_maps(aslr_machine) < 0)
458febea9ecSIan Rogers 		return -ENOMEM;
459febea9ecSIan Rogers 
460febea9ecSIan Rogers 	/* Create the thread, map, etc. in the ASLR before virtual address space. */
461febea9ecSIan Rogers 	err = perf_event__process_mmap(tool, event, sample, aslr_machine);
462febea9ecSIan Rogers 	if (err)
463febea9ecSIan Rogers 		return err;
464febea9ecSIan Rogers 
465febea9ecSIan Rogers 	thread = machine__findnew_thread(aslr_machine, event->mmap.pid, event->mmap.tid);
466febea9ecSIan Rogers 	if (!thread)
467febea9ecSIan Rogers 		return -ENOMEM;
468febea9ecSIan Rogers 	memcpy(&new_event->mmap, &event->mmap, event->mmap.header.size);
469febea9ecSIan Rogers 	/* Remaps the mmap.start. */
470febea9ecSIan Rogers 	new_event->mmap.start = aslr_tool__findnew_mapping(aslr, machine, thread, cpumode,
471febea9ecSIan Rogers 							   event->mmap.start,
472febea9ecSIan Rogers 							   event->mmap.len,
473febea9ecSIan Rogers 							   event->mmap.pgoff);
474febea9ecSIan Rogers 	/*
475febea9ecSIan Rogers 	 * For anonymous memory (and kernel maps), the kernel populates the
476febea9ecSIan Rogers 	 * event's pgoff field with the original un-obfuscated virtual address
477febea9ecSIan Rogers 	 * in bytes (i.e. (addr >> PAGE_SHIFT) << PAGE_SHIFT).
478febea9ecSIan Rogers 	 * We must overwrite pgoff with the new remapped byte address to prevent
479febea9ecSIan Rogers 	 * leaking the original ASLR layout.
480febea9ecSIan Rogers 	 */
481febea9ecSIan Rogers 	if (is_anon_memory(event->mmap.filename) || is_no_dso_memory(event->mmap.filename) ||
482febea9ecSIan Rogers 	    ((cpumode == PERF_RECORD_MISC_KERNEL || cpumode == PERF_RECORD_MISC_GUEST_KERNEL) &&
483febea9ecSIan Rogers 	     !is_kernel_module(event->mmap.filename, cpumode)))
484febea9ecSIan Rogers 		new_event->mmap.pgoff = new_event->mmap.start;
485febea9ecSIan Rogers 	err = delegate->mmap(delegate, new_event, sample, machine);
486febea9ecSIan Rogers 	thread__put(thread);
487febea9ecSIan Rogers 	return err;
488febea9ecSIan Rogers }
489febea9ecSIan Rogers 
490febea9ecSIan Rogers static int aslr_tool__process_mmap2(const struct perf_tool *tool,
491febea9ecSIan Rogers 				    union perf_event *event,
492febea9ecSIan Rogers 				    struct perf_sample *sample,
493febea9ecSIan Rogers 				    struct machine *machine)
494febea9ecSIan Rogers {
495febea9ecSIan Rogers 	struct delegate_tool *del_tool;
496febea9ecSIan Rogers 	struct aslr_tool *aslr;
497febea9ecSIan Rogers 	struct perf_tool *delegate;
498febea9ecSIan Rogers 	union perf_event *new_event;
499febea9ecSIan Rogers 	u8 cpumode;
500febea9ecSIan Rogers 	struct thread *thread;
501febea9ecSIan Rogers 	struct machine *aslr_machine;
502febea9ecSIan Rogers 	int err;
503febea9ecSIan Rogers 
504febea9ecSIan Rogers 	del_tool = container_of(tool, struct delegate_tool, tool);
505febea9ecSIan Rogers 	aslr = container_of(del_tool, struct aslr_tool, tool);
506febea9ecSIan Rogers 	delegate = aslr->tool.delegate;
507febea9ecSIan Rogers 	new_event = (union perf_event *)aslr->event_copy;
508febea9ecSIan Rogers 	cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
509febea9ecSIan Rogers 
510febea9ecSIan Rogers 	aslr_machine = machines__findnew(&aslr->machines, machine->pid);
511febea9ecSIan Rogers 	if (!aslr_machine)
512febea9ecSIan Rogers 		return -ENOMEM;
513febea9ecSIan Rogers 	if (aslr_tool__preload_kernel_maps(aslr_machine) < 0)
514febea9ecSIan Rogers 		return -ENOMEM;
515febea9ecSIan Rogers 
516febea9ecSIan Rogers 	/* Create the thread, map, etc. in the ASLR before virtual address space. */
517febea9ecSIan Rogers 	err = perf_event__process_mmap2(tool, event, sample, aslr_machine);
518febea9ecSIan Rogers 	if (err)
519febea9ecSIan Rogers 		return err;
520febea9ecSIan Rogers 
521febea9ecSIan Rogers 	thread = machine__findnew_thread(aslr_machine, event->mmap2.pid, event->mmap2.tid);
522febea9ecSIan Rogers 	if (!thread)
523febea9ecSIan Rogers 		return -ENOMEM;
524febea9ecSIan Rogers 	memcpy(&new_event->mmap2, &event->mmap2, event->mmap2.header.size);
525febea9ecSIan Rogers 	/* Remaps the mmap.start. */
526febea9ecSIan Rogers 	new_event->mmap2.start = aslr_tool__findnew_mapping(aslr, machine, thread, cpumode,
527febea9ecSIan Rogers 							    event->mmap2.start,
528febea9ecSIan Rogers 							    event->mmap2.len,
529febea9ecSIan Rogers 							    event->mmap2.pgoff);
530febea9ecSIan Rogers 	/*
531febea9ecSIan Rogers 	 * For anonymous memory (and kernel maps), the kernel populates the
532febea9ecSIan Rogers 	 * event's pgoff field with the original un-obfuscated virtual address
533febea9ecSIan Rogers 	 * in bytes (i.e. (addr >> PAGE_SHIFT) << PAGE_SHIFT).
534febea9ecSIan Rogers 	 * We must overwrite pgoff with the new remapped byte address to prevent
535febea9ecSIan Rogers 	 * leaking the original ASLR layout.
536febea9ecSIan Rogers 	 */
537febea9ecSIan Rogers 	if (is_anon_memory(event->mmap2.filename) || is_no_dso_memory(event->mmap2.filename) ||
538febea9ecSIan Rogers 	    ((cpumode == PERF_RECORD_MISC_KERNEL || cpumode == PERF_RECORD_MISC_GUEST_KERNEL) &&
539febea9ecSIan Rogers 	     !is_kernel_module(event->mmap2.filename, cpumode)))
540febea9ecSIan Rogers 		new_event->mmap2.pgoff = new_event->mmap2.start;
541febea9ecSIan Rogers 	err = delegate->mmap2(delegate, new_event, sample, machine);
542febea9ecSIan Rogers 	thread__put(thread);
543febea9ecSIan Rogers 	return err;
544febea9ecSIan Rogers }
545febea9ecSIan Rogers 
546febea9ecSIan Rogers static int aslr_tool__process_comm(const struct perf_tool *tool,
547febea9ecSIan Rogers 				   union perf_event *event,
548febea9ecSIan Rogers 				   struct perf_sample *sample,
549febea9ecSIan Rogers 				   struct machine *machine)
550febea9ecSIan Rogers {
551febea9ecSIan Rogers 	struct delegate_tool *del_tool;
552febea9ecSIan Rogers 	struct aslr_tool *aslr;
553febea9ecSIan Rogers 	struct perf_tool *delegate;
554febea9ecSIan Rogers 	struct machine *aslr_machine;
555febea9ecSIan Rogers 	int err;
556febea9ecSIan Rogers 
557febea9ecSIan Rogers 	del_tool = container_of(tool, struct delegate_tool, tool);
558febea9ecSIan Rogers 	aslr = container_of(del_tool, struct aslr_tool, tool);
559febea9ecSIan Rogers 	delegate = aslr->tool.delegate;
560febea9ecSIan Rogers 
561febea9ecSIan Rogers 	aslr_machine = machines__findnew(&aslr->machines, machine->pid);
562febea9ecSIan Rogers 	if (!aslr_machine)
563febea9ecSIan Rogers 		return -ENOMEM;
564febea9ecSIan Rogers 	if (aslr_tool__preload_kernel_maps(aslr_machine) < 0)
565febea9ecSIan Rogers 		return -ENOMEM;
566febea9ecSIan Rogers 
567febea9ecSIan Rogers 	/* Create the thread, map, etc. in the ASLR before virtual address space. */
568febea9ecSIan Rogers 	err = perf_event__process_comm(tool, event, sample, aslr_machine);
569febea9ecSIan Rogers 	if (err)
570febea9ecSIan Rogers 		return err;
571febea9ecSIan Rogers 
572febea9ecSIan Rogers 	return delegate->comm(delegate, event, sample, machine);
573febea9ecSIan Rogers }
574febea9ecSIan Rogers 
575febea9ecSIan Rogers static int aslr_tool__process_fork(const struct perf_tool *tool,
576febea9ecSIan Rogers 				   union perf_event *event,
577febea9ecSIan Rogers 				   struct perf_sample *sample,
578febea9ecSIan Rogers 				   struct machine *machine)
579febea9ecSIan Rogers {
580febea9ecSIan Rogers 	struct delegate_tool *del_tool;
581febea9ecSIan Rogers 	struct aslr_tool *aslr;
582febea9ecSIan Rogers 	struct perf_tool *delegate;
583febea9ecSIan Rogers 	struct machine *aslr_machine;
584febea9ecSIan Rogers 	int err;
585febea9ecSIan Rogers 
586febea9ecSIan Rogers 	del_tool = container_of(tool, struct delegate_tool, tool);
587febea9ecSIan Rogers 	aslr = container_of(del_tool, struct aslr_tool, tool);
588febea9ecSIan Rogers 	delegate = aslr->tool.delegate;
589febea9ecSIan Rogers 
590febea9ecSIan Rogers 	aslr_machine = machines__findnew(&aslr->machines, machine->pid);
591febea9ecSIan Rogers 	if (!aslr_machine)
592febea9ecSIan Rogers 		return -ENOMEM;
593febea9ecSIan Rogers 	if (aslr_tool__preload_kernel_maps(aslr_machine) < 0)
594febea9ecSIan Rogers 		return -ENOMEM;
595febea9ecSIan Rogers 
596febea9ecSIan Rogers 	/* Create the thread, map, etc. in the ASLR before virtual address space. */
597febea9ecSIan Rogers 	err = perf_event__process_fork(tool, event, sample, aslr_machine);
598febea9ecSIan Rogers 	if (err)
599febea9ecSIan Rogers 		return err;
600febea9ecSIan Rogers 
601febea9ecSIan Rogers 	return delegate->fork(delegate, event, sample, machine);
602febea9ecSIan Rogers }
603febea9ecSIan Rogers 
604febea9ecSIan Rogers static int aslr_tool__process_exit(const struct perf_tool *tool,
605febea9ecSIan Rogers 				   union perf_event *event,
606febea9ecSIan Rogers 				   struct perf_sample *sample,
607febea9ecSIan Rogers 				   struct machine *machine)
608febea9ecSIan Rogers {
609febea9ecSIan Rogers 	struct delegate_tool *del_tool;
610febea9ecSIan Rogers 	struct aslr_tool *aslr;
611febea9ecSIan Rogers 	struct perf_tool *delegate;
612febea9ecSIan Rogers 	struct machine *aslr_machine;
613febea9ecSIan Rogers 	int err;
614febea9ecSIan Rogers 
615febea9ecSIan Rogers 	del_tool = container_of(tool, struct delegate_tool, tool);
616febea9ecSIan Rogers 	aslr = container_of(del_tool, struct aslr_tool, tool);
617febea9ecSIan Rogers 	delegate = aslr->tool.delegate;
618febea9ecSIan Rogers 
619febea9ecSIan Rogers 	aslr_machine = machines__findnew(&aslr->machines, machine->pid);
620febea9ecSIan Rogers 	if (!aslr_machine)
621febea9ecSIan Rogers 		return -ENOMEM;
622febea9ecSIan Rogers 	if (aslr_tool__preload_kernel_maps(aslr_machine) < 0)
623febea9ecSIan Rogers 		return -ENOMEM;
624febea9ecSIan Rogers 
625febea9ecSIan Rogers 	/* Create the thread, map, etc. in the ASLR before virtual address space. */
626febea9ecSIan Rogers 	err = perf_event__process_exit(tool, event, sample, aslr_machine);
627febea9ecSIan Rogers 	if (err)
628febea9ecSIan Rogers 		return err;
629febea9ecSIan Rogers 
630febea9ecSIan Rogers 	return delegate->exit(delegate, event, sample, machine);
631febea9ecSIan Rogers }
632febea9ecSIan Rogers 
633febea9ecSIan Rogers static int aslr_tool__process_text_poke(const struct perf_tool *tool __maybe_unused,
634febea9ecSIan Rogers 					union perf_event *event __maybe_unused,
635febea9ecSIan Rogers 					struct perf_sample *sample __maybe_unused,
636febea9ecSIan Rogers 					struct machine *machine __maybe_unused)
637febea9ecSIan Rogers {
638febea9ecSIan Rogers 	/* Drop in case the instruction encodes an ASLR revealing address. */
639febea9ecSIan Rogers 	return 0;
640febea9ecSIan Rogers }
641febea9ecSIan Rogers 
642febea9ecSIan Rogers static int aslr_tool__process_ksymbol(const struct perf_tool *tool,
643febea9ecSIan Rogers 				      union perf_event *event,
644febea9ecSIan Rogers 				      struct perf_sample *sample,
645febea9ecSIan Rogers 				      struct machine *machine)
646febea9ecSIan Rogers {
647febea9ecSIan Rogers 	struct delegate_tool *del_tool;
648febea9ecSIan Rogers 	struct aslr_tool *aslr;
649febea9ecSIan Rogers 	struct perf_tool *delegate;
650febea9ecSIan Rogers 	union perf_event *new_event;
651febea9ecSIan Rogers 	struct thread *thread;
652febea9ecSIan Rogers 	struct machine *aslr_machine;
653febea9ecSIan Rogers 	bool is_unregister;
654febea9ecSIan Rogers 	int err;
655febea9ecSIan Rogers 
656febea9ecSIan Rogers 	del_tool = container_of(tool, struct delegate_tool, tool);
657febea9ecSIan Rogers 	aslr = container_of(del_tool, struct aslr_tool, tool);
658febea9ecSIan Rogers 	delegate = aslr->tool.delegate;
659febea9ecSIan Rogers 	new_event = (union perf_event *)aslr->event_copy;
660febea9ecSIan Rogers 
661febea9ecSIan Rogers 	aslr_machine = machines__findnew(&aslr->machines, machine->pid);
662febea9ecSIan Rogers 	if (!aslr_machine)
663febea9ecSIan Rogers 		return -ENOMEM;
664febea9ecSIan Rogers 	if (aslr_tool__preload_kernel_maps(aslr_machine) < 0)
665febea9ecSIan Rogers 		return -ENOMEM;
666febea9ecSIan Rogers 
667febea9ecSIan Rogers 	thread = machine__findnew_thread(aslr_machine, kernel_pid, 0);
668febea9ecSIan Rogers 	if (!thread)
669febea9ecSIan Rogers 		return -ENOMEM;
670febea9ecSIan Rogers 
671febea9ecSIan Rogers 	is_unregister = (event->ksymbol.flags & PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER);
672febea9ecSIan Rogers 
673febea9ecSIan Rogers 	memcpy(&new_event->ksymbol, &event->ksymbol, event->ksymbol.header.size);
674febea9ecSIan Rogers 
675febea9ecSIan Rogers 	if (is_unregister) {
676febea9ecSIan Rogers 		new_event->ksymbol.addr = aslr_tool__findnew_mapping(aslr, machine, thread,
677febea9ecSIan Rogers 								     PERF_RECORD_MISC_KERNEL,
678febea9ecSIan Rogers 								     event->ksymbol.addr,
679febea9ecSIan Rogers 								     event->ksymbol.len,
680febea9ecSIan Rogers 								     /*pgoff=*/0);
681febea9ecSIan Rogers 		err = perf_event__process_ksymbol(tool, event, sample, aslr_machine);
682febea9ecSIan Rogers 	} else {
683febea9ecSIan Rogers 		err = perf_event__process_ksymbol(tool, event, sample, aslr_machine);
684febea9ecSIan Rogers 		new_event->ksymbol.addr = aslr_tool__findnew_mapping(aslr, machine, thread,
685febea9ecSIan Rogers 								     PERF_RECORD_MISC_KERNEL,
686febea9ecSIan Rogers 								     event->ksymbol.addr,
687febea9ecSIan Rogers 								     event->ksymbol.len,
688febea9ecSIan Rogers 								     /*pgoff=*/0);
689febea9ecSIan Rogers 	}
690febea9ecSIan Rogers 	if (err) {
691febea9ecSIan Rogers 		thread__put(thread);
692febea9ecSIan Rogers 		return err;
693febea9ecSIan Rogers 	}
694febea9ecSIan Rogers 
695febea9ecSIan Rogers 	err = delegate->ksymbol(delegate, new_event, sample, machine);
696febea9ecSIan Rogers 	thread__put(thread);
697febea9ecSIan Rogers 	return err;
698febea9ecSIan Rogers }
699febea9ecSIan Rogers 
700febea9ecSIan Rogers static int aslr_tool__process_sample(const struct perf_tool *tool,
701febea9ecSIan Rogers 				     union perf_event *event,
702febea9ecSIan Rogers 				     struct perf_sample *sample,
703febea9ecSIan Rogers 				     struct machine *machine)
704febea9ecSIan Rogers {
705575c6d2bSIan Rogers 	struct evsel *evsel = sample->evsel;
706575c6d2bSIan Rogers 	struct delegate_tool *del_tool;
707575c6d2bSIan Rogers 	struct aslr_tool *aslr;
708575c6d2bSIan Rogers 	struct perf_tool *delegate;
709575c6d2bSIan Rogers 	int ret;
710d6dbf2d4SIan Rogers 	int orig_sample_size;
711575c6d2bSIan Rogers 	u64 sample_type;
712575c6d2bSIan Rogers 	struct thread *thread;
713575c6d2bSIan Rogers 	struct machine *aslr_machine;
714575c6d2bSIan Rogers 	__u64 max_i;
715575c6d2bSIan Rogers 	__u64 max_j;
716575c6d2bSIan Rogers 	union perf_event *new_event;
717575c6d2bSIan Rogers 	struct perf_sample new_sample;
718575c6d2bSIan Rogers 	__u64 *in_array, *out_array;
719575c6d2bSIan Rogers 	u8 cpumode;
720575c6d2bSIan Rogers 	u64 addr;
721575c6d2bSIan Rogers 	size_t i;
722575c6d2bSIan Rogers 	size_t j;
723d6dbf2d4SIan Rogers 	struct aslr_evsel_priv *priv = NULL;
724d6dbf2d4SIan Rogers 	u64 orig_sample_type;
725d6dbf2d4SIan Rogers 	u64 orig_regs_user;
726d6dbf2d4SIan Rogers 	u64 orig_regs_intr;
727febea9ecSIan Rogers 
728575c6d2bSIan Rogers 	del_tool = container_of(tool, struct delegate_tool, tool);
729575c6d2bSIan Rogers 	aslr = container_of(del_tool, struct aslr_tool, tool);
730575c6d2bSIan Rogers 	delegate = aslr->tool.delegate;
731575c6d2bSIan Rogers 
732575c6d2bSIan Rogers 	if (evsel__is_dummy_event(evsel))
733febea9ecSIan Rogers 		return delegate->sample(delegate, event, sample, machine);
734575c6d2bSIan Rogers 
735575c6d2bSIan Rogers 	ret = -EFAULT;
736d6dbf2d4SIan Rogers 
737d6dbf2d4SIan Rogers 	if (hashmap__find(&aslr->evsel_orig_attrs, evsel, &priv)) {
738d6dbf2d4SIan Rogers 		orig_sample_type = priv->orig_sample_type;
739d6dbf2d4SIan Rogers 		orig_regs_user = priv->orig_sample_regs_user;
740d6dbf2d4SIan Rogers 		orig_regs_intr = priv->orig_sample_regs_intr;
741d6dbf2d4SIan Rogers 	} else {
742d6dbf2d4SIan Rogers 		orig_sample_type = evsel->core.attr.sample_type;
743d6dbf2d4SIan Rogers 		orig_regs_user = evsel->core.attr.sample_regs_user;
744d6dbf2d4SIan Rogers 		orig_regs_intr = evsel->core.attr.sample_regs_intr;
745d6dbf2d4SIan Rogers 	}
746d6dbf2d4SIan Rogers 
747d6dbf2d4SIan Rogers 	orig_sample_size = evsel->sample_size;
748d6dbf2d4SIan Rogers 
749d6dbf2d4SIan Rogers 	sample_type = orig_sample_type;
750d6dbf2d4SIan Rogers 	sample_type &= ~PERF_SAMPLE_REGS_USER;
751d6dbf2d4SIan Rogers 	sample_type &= ~PERF_SAMPLE_REGS_INTR;
752d6dbf2d4SIan Rogers 	sample_type &= ASLR_SUPPORTED_SAMPLE_TYPE;
753d6dbf2d4SIan Rogers 
754575c6d2bSIan Rogers 	max_i = (event->header.size - sizeof(struct perf_event_header)) / sizeof(__u64);
755575c6d2bSIan Rogers 	max_j = (PERF_SAMPLE_MAX_SIZE - sizeof(struct perf_event_header)) / sizeof(__u64);
756575c6d2bSIan Rogers 	new_event = (union perf_event *)aslr->event_copy;
757575c6d2bSIan Rogers 	cpumode = sample->cpumode;
758575c6d2bSIan Rogers 	i = 0;
759575c6d2bSIan Rogers 	j = 0;
760575c6d2bSIan Rogers 
761575c6d2bSIan Rogers 	aslr_machine = machines__findnew(&aslr->machines, machine->pid);
762575c6d2bSIan Rogers 	if (!aslr_machine)
763575c6d2bSIan Rogers 		return -ENOMEM;
764575c6d2bSIan Rogers 	if (aslr_tool__preload_kernel_maps(aslr_machine) < 0)
765575c6d2bSIan Rogers 		return -ENOMEM;
766575c6d2bSIan Rogers 
767575c6d2bSIan Rogers 	thread = machine__findnew_thread(aslr_machine, sample->pid, sample->tid);
768575c6d2bSIan Rogers 
769575c6d2bSIan Rogers 	if (!thread)
770575c6d2bSIan Rogers 		return -ENOMEM;
771575c6d2bSIan Rogers 
772575c6d2bSIan Rogers 	if (max_i > PERF_SAMPLE_MAX_SIZE / sizeof(u64))
773575c6d2bSIan Rogers 		goto out_put;
774575c6d2bSIan Rogers 
775575c6d2bSIan Rogers 	new_event->sample.header = event->sample.header;
776575c6d2bSIan Rogers 
777575c6d2bSIan Rogers 	in_array = &event->sample.array[0];
778575c6d2bSIan Rogers 	out_array = &new_event->sample.array[0];
779575c6d2bSIan Rogers 
780575c6d2bSIan Rogers #define CHECK_BOUNDS(required_i, required_j) \
781575c6d2bSIan Rogers 	(i + (required_i) > max_i || j + (required_j) > max_j)
782575c6d2bSIan Rogers 
783575c6d2bSIan Rogers #define COPY_U64() \
784575c6d2bSIan Rogers 	do { \
785575c6d2bSIan Rogers 		if (CHECK_BOUNDS(1, 1)) { \
786575c6d2bSIan Rogers 			ret = -EFAULT; \
787575c6d2bSIan Rogers 			goto out_put; \
788575c6d2bSIan Rogers 		} \
789575c6d2bSIan Rogers 		out_array[j++] = in_array[i++]; \
790575c6d2bSIan Rogers 	} while (0)
791575c6d2bSIan Rogers 
792575c6d2bSIan Rogers #define REMAP_U64(addr_field) \
793575c6d2bSIan Rogers 	do { \
794575c6d2bSIan Rogers 		u64 remapped; \
795575c6d2bSIan Rogers 		if (CHECK_BOUNDS(1, 1)) { \
796575c6d2bSIan Rogers 			ret = -EFAULT; \
797575c6d2bSIan Rogers 			goto out_put; \
798575c6d2bSIan Rogers 		} \
799575c6d2bSIan Rogers 		remapped = aslr_tool__remap_address(aslr, thread, cpumode, addr_field); \
800575c6d2bSIan Rogers 		out_array[j++] = remapped; \
801575c6d2bSIan Rogers 		i++; \
802575c6d2bSIan Rogers 	} while (0)
803575c6d2bSIan Rogers 
804d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_IDENTIFIER)
805575c6d2bSIan Rogers 		COPY_U64(); /* id */
806d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_IP)
807575c6d2bSIan Rogers 		REMAP_U64(sample->ip);
808d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_TID) {
809575c6d2bSIan Rogers 		union {
810575c6d2bSIan Rogers 			u64 val64;
811575c6d2bSIan Rogers 			u32 val32[2];
812575c6d2bSIan Rogers 		} u;
813575c6d2bSIan Rogers 
814575c6d2bSIan Rogers 		if (CHECK_BOUNDS(1, 1)) {
815575c6d2bSIan Rogers 			ret = -EFAULT;
816575c6d2bSIan Rogers 			goto out_put;
817febea9ecSIan Rogers 		}
818575c6d2bSIan Rogers 		u.val32[0] = sample->pid;
819575c6d2bSIan Rogers 		u.val32[1] = sample->tid;
820575c6d2bSIan Rogers 		out_array[j++] = u.val64;
821575c6d2bSIan Rogers 		i++;
822575c6d2bSIan Rogers 	}
823d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_TIME)
824575c6d2bSIan Rogers 		COPY_U64(); /* time */
825d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_ADDR)
826575c6d2bSIan Rogers 		REMAP_U64(sample->addr);
827d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_ID)
828575c6d2bSIan Rogers 		COPY_U64(); /* id */
829d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_STREAM_ID)
830575c6d2bSIan Rogers 		COPY_U64(); /* stream_id */
831d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_CPU)
832575c6d2bSIan Rogers 		COPY_U64(); /* cpu, res */
833d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_PERIOD)
834575c6d2bSIan Rogers 		COPY_U64(); /* period */
835d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_READ) {
836575c6d2bSIan Rogers 		if ((evsel->core.attr.read_format & PERF_FORMAT_GROUP) == 0) {
837575c6d2bSIan Rogers 			COPY_U64(); /* value */
838575c6d2bSIan Rogers 			if (evsel->core.attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
839575c6d2bSIan Rogers 				COPY_U64(); /* time_enabled */
840575c6d2bSIan Rogers 			if (evsel->core.attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
841575c6d2bSIan Rogers 				COPY_U64(); /* time_running */
842575c6d2bSIan Rogers 			if (evsel->core.attr.read_format & PERF_FORMAT_ID)
843575c6d2bSIan Rogers 				COPY_U64(); /* id */
844575c6d2bSIan Rogers 			if (evsel->core.attr.read_format & PERF_FORMAT_LOST)
845575c6d2bSIan Rogers 				COPY_U64(); /* lost */
846575c6d2bSIan Rogers 		} else {
847575c6d2bSIan Rogers 			u64 nr;
848575c6d2bSIan Rogers 
849575c6d2bSIan Rogers 			if (CHECK_BOUNDS(1, 1)) {
850575c6d2bSIan Rogers 				ret = -EFAULT;
851575c6d2bSIan Rogers 				goto out_put;
852575c6d2bSIan Rogers 			}
853575c6d2bSIan Rogers 			nr = in_array[i];
854575c6d2bSIan Rogers 			COPY_U64();
855575c6d2bSIan Rogers 			if (evsel->core.attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
856575c6d2bSIan Rogers 				COPY_U64(); /* time_enabled */
857575c6d2bSIan Rogers 			if (evsel->core.attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
858575c6d2bSIan Rogers 				COPY_U64(); /* time_running */
859575c6d2bSIan Rogers 			for (u64 cntr = 0; cntr < nr; cntr++) {
860575c6d2bSIan Rogers 				COPY_U64(); /* value */
861575c6d2bSIan Rogers 				if (evsel->core.attr.read_format & PERF_FORMAT_ID)
862575c6d2bSIan Rogers 					COPY_U64(); /* id */
863575c6d2bSIan Rogers 				if (evsel->core.attr.read_format & PERF_FORMAT_LOST)
864575c6d2bSIan Rogers 					COPY_U64(); /* lost */
865575c6d2bSIan Rogers 			}
866575c6d2bSIan Rogers 		}
867575c6d2bSIan Rogers 	}
868d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_CALLCHAIN) {
869575c6d2bSIan Rogers 		u64 nr;
870575c6d2bSIan Rogers 
871575c6d2bSIan Rogers 		if (CHECK_BOUNDS(1, 1)) {
872575c6d2bSIan Rogers 			ret = -EFAULT;
873575c6d2bSIan Rogers 			goto out_put;
874575c6d2bSIan Rogers 		}
875575c6d2bSIan Rogers 		nr = in_array[i];
876575c6d2bSIan Rogers 		COPY_U64();
877575c6d2bSIan Rogers 
878575c6d2bSIan Rogers 		for (u64 cntr = 0; cntr < nr; cntr++) {
879575c6d2bSIan Rogers 			if (CHECK_BOUNDS(1, 1)) {
880575c6d2bSIan Rogers 				ret = -EFAULT;
881575c6d2bSIan Rogers 				goto out_put;
882575c6d2bSIan Rogers 			}
883575c6d2bSIan Rogers 			addr = in_array[i++];
884575c6d2bSIan Rogers 			if (addr >= PERF_CONTEXT_MAX) {
885575c6d2bSIan Rogers 				out_array[j++] = addr;
886575c6d2bSIan Rogers 				switch (addr) {
887575c6d2bSIan Rogers 				case PERF_CONTEXT_HV:
888575c6d2bSIan Rogers 					cpumode = PERF_RECORD_MISC_HYPERVISOR;
889575c6d2bSIan Rogers 					break;
890575c6d2bSIan Rogers 				case PERF_CONTEXT_KERNEL:
891575c6d2bSIan Rogers 					cpumode = PERF_RECORD_MISC_KERNEL;
892575c6d2bSIan Rogers 					break;
893575c6d2bSIan Rogers 				case PERF_CONTEXT_USER:
894575c6d2bSIan Rogers 					cpumode = PERF_RECORD_MISC_USER;
895575c6d2bSIan Rogers 					break;
896575c6d2bSIan Rogers 				case PERF_CONTEXT_GUEST:
897575c6d2bSIan Rogers 					cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
898575c6d2bSIan Rogers 					break;
899575c6d2bSIan Rogers 				case PERF_CONTEXT_GUEST_KERNEL:
900575c6d2bSIan Rogers 					cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
901575c6d2bSIan Rogers 					break;
902575c6d2bSIan Rogers 				case PERF_CONTEXT_GUEST_USER:
903575c6d2bSIan Rogers 					cpumode = PERF_RECORD_MISC_GUEST_USER;
904575c6d2bSIan Rogers 					break;
905575c6d2bSIan Rogers 				case PERF_CONTEXT_USER_DEFERRED:
906575c6d2bSIan Rogers 					if (cntr + 1 >= nr) {
907575c6d2bSIan Rogers 						pr_debug("Truncated callchain deferred cookie context\n");
908575c6d2bSIan Rogers 						ret = 0;
909575c6d2bSIan Rogers 						goto out_put;
910575c6d2bSIan Rogers 					}
911575c6d2bSIan Rogers 					/*
912575c6d2bSIan Rogers 					 * Immediately followed by a 64-bit
913575c6d2bSIan Rogers 					 * stitching cookie. Skip/Copy it!
914575c6d2bSIan Rogers 					 */
915575c6d2bSIan Rogers 					if (CHECK_BOUNDS(1, 1)) {
916575c6d2bSIan Rogers 						ret = -EFAULT;
917575c6d2bSIan Rogers 						goto out_put;
918575c6d2bSIan Rogers 					}
919575c6d2bSIan Rogers 					out_array[j++] = in_array[i++];
920575c6d2bSIan Rogers 					cntr++;
921575c6d2bSIan Rogers 					cpumode = PERF_RECORD_MISC_USER;
922575c6d2bSIan Rogers 					break;
923575c6d2bSIan Rogers 				default:
924575c6d2bSIan Rogers 					pr_debug("invalid callchain context: %"PRIx64"\n", addr);
925575c6d2bSIan Rogers 					ret = 0;
926575c6d2bSIan Rogers 					goto out_put;
927575c6d2bSIan Rogers 				}
928575c6d2bSIan Rogers 				continue;
929575c6d2bSIan Rogers 			}
930575c6d2bSIan Rogers 			addr = aslr_tool__remap_address(aslr, thread, cpumode, addr);
931575c6d2bSIan Rogers 			out_array[j++] = addr;
932575c6d2bSIan Rogers 		}
933575c6d2bSIan Rogers 	}
934d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_RAW) {
935575c6d2bSIan Rogers 		size_t bytes = sizeof(u32) + sample->raw_size;
936575c6d2bSIan Rogers 		size_t u64_words = (bytes + 7) / 8;
937575c6d2bSIan Rogers 
938575c6d2bSIan Rogers 		if (i + u64_words > max_i || j + u64_words > max_j) {
939575c6d2bSIan Rogers 			ret = -EFAULT;
940575c6d2bSIan Rogers 			goto out_put;
941575c6d2bSIan Rogers 		}
942575c6d2bSIan Rogers 		memcpy(&out_array[j], &in_array[i], bytes);
943575c6d2bSIan Rogers 		i += u64_words;
944575c6d2bSIan Rogers 		j += u64_words;
945575c6d2bSIan Rogers 		/*
946575c6d2bSIan Rogers 		 * TODO: certain raw samples can be remapped, such as
947575c6d2bSIan Rogers 		 * tracepoints by examining their fields.
948575c6d2bSIan Rogers 		 */
949575c6d2bSIan Rogers 		pr_debug("Dropping raw samples as possible ASLR leak\n");
950575c6d2bSIan Rogers 		ret = 0;
951575c6d2bSIan Rogers 		goto out_put;
952575c6d2bSIan Rogers 	}
953d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_BRANCH_STACK) {
954575c6d2bSIan Rogers 		u64 nr;
955575c6d2bSIan Rogers 
956575c6d2bSIan Rogers 		if (CHECK_BOUNDS(1, 1)) {
957575c6d2bSIan Rogers 			ret = -EFAULT;
958575c6d2bSIan Rogers 			goto out_put;
959575c6d2bSIan Rogers 		}
960575c6d2bSIan Rogers 		nr = in_array[i];
961575c6d2bSIan Rogers 		COPY_U64();
962575c6d2bSIan Rogers 
963575c6d2bSIan Rogers 		if (evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_HW_INDEX)
964575c6d2bSIan Rogers 			COPY_U64(); /* hw_idx */
965575c6d2bSIan Rogers 
966575c6d2bSIan Rogers 		if (nr > (ULLONG_MAX / 3)) {
967575c6d2bSIan Rogers 			ret = -EFAULT;
968575c6d2bSIan Rogers 			goto out_put;
969575c6d2bSIan Rogers 		}
970575c6d2bSIan Rogers 		if (nr * 3 > max_i - i || nr * 3 > max_j - j) {
971575c6d2bSIan Rogers 			ret = -EFAULT;
972575c6d2bSIan Rogers 			goto out_put;
973575c6d2bSIan Rogers 		}
974575c6d2bSIan Rogers 		for (u64 cntr = 0; cntr < nr; cntr++) {
975575c6d2bSIan Rogers 			u64 from = in_array[i++];
976575c6d2bSIan Rogers 			u64 to = in_array[i++];
977575c6d2bSIan Rogers 
978575c6d2bSIan Rogers 			from = aslr_tool__remap_address(aslr, thread, sample->cpumode, from);
979575c6d2bSIan Rogers 			to = aslr_tool__remap_address(aslr, thread, sample->cpumode, to);
980575c6d2bSIan Rogers 
981575c6d2bSIan Rogers 			out_array[j++] = from;
982575c6d2bSIan Rogers 			out_array[j++] = to;
983575c6d2bSIan Rogers 			out_array[j++] = in_array[i++]; /* flags */
984575c6d2bSIan Rogers 		}
985575c6d2bSIan Rogers 		if (evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS) {
986575c6d2bSIan Rogers 			if (nr > max_i - i || nr > max_j - j) {
987575c6d2bSIan Rogers 				ret = -EFAULT;
988575c6d2bSIan Rogers 				goto out_put;
989575c6d2bSIan Rogers 			}
990575c6d2bSIan Rogers 			for (u64 cntr = 0; cntr < nr; cntr++)
991575c6d2bSIan Rogers 				COPY_U64();
992575c6d2bSIan Rogers 		}
993575c6d2bSIan Rogers 	}
994d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_REGS_USER) {
995d6dbf2d4SIan Rogers 		u64 abi;
996d6dbf2d4SIan Rogers 
997575c6d2bSIan Rogers 		if (CHECK_BOUNDS(1, 0)) {
998575c6d2bSIan Rogers 			ret = -EFAULT;
999575c6d2bSIan Rogers 			goto out_put;
1000575c6d2bSIan Rogers 		}
1001d6dbf2d4SIan Rogers 		abi = in_array[i++];
1002d6dbf2d4SIan Rogers 		if (abi != PERF_SAMPLE_REGS_ABI_NONE) {
1003d6dbf2d4SIan Rogers 			u64 nr = hweight64(orig_regs_user);
1004d6dbf2d4SIan Rogers 
1005d6dbf2d4SIan Rogers 			if (nr > max_i - i) {
1006d6dbf2d4SIan Rogers 				ret = -EFAULT;
1007575c6d2bSIan Rogers 				goto out_put;
1008575c6d2bSIan Rogers 			}
1009d6dbf2d4SIan Rogers 			i += nr;
1010d6dbf2d4SIan Rogers 		}
1011d6dbf2d4SIan Rogers 	}
1012d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_STACK_USER) {
1013575c6d2bSIan Rogers 		u64 size;
1014575c6d2bSIan Rogers 
1015575c6d2bSIan Rogers 		if (CHECK_BOUNDS(1, 1)) {
1016575c6d2bSIan Rogers 			ret = -EFAULT;
1017575c6d2bSIan Rogers 			goto out_put;
1018575c6d2bSIan Rogers 		}
1019575c6d2bSIan Rogers 		size = in_array[i];
1020575c6d2bSIan Rogers 		COPY_U64();
1021575c6d2bSIan Rogers 		if (size > 0) {
1022575c6d2bSIan Rogers 			size_t u64_words = size / 8 + (size % 8 ? 1 : 0);
1023575c6d2bSIan Rogers 
1024575c6d2bSIan Rogers 			if (u64_words > max_i - i || u64_words > max_j - j) {
1025575c6d2bSIan Rogers 				ret = -EFAULT;
1026575c6d2bSIan Rogers 				goto out_put;
1027575c6d2bSIan Rogers 			}
1028575c6d2bSIan Rogers 			memcpy(&out_array[j], &in_array[i], size);
1029575c6d2bSIan Rogers 			if (size % 8) {
1030575c6d2bSIan Rogers 				size_t pad = 8 - (size % 8);
1031575c6d2bSIan Rogers 
1032575c6d2bSIan Rogers 				memset(((char *)&out_array[j]) + size, 0, pad);
1033575c6d2bSIan Rogers 			}
1034575c6d2bSIan Rogers 			i += u64_words;
1035575c6d2bSIan Rogers 			j += u64_words;
1036575c6d2bSIan Rogers 		}
1037575c6d2bSIan Rogers 		/* TODO: can this be less conservative? */
1038575c6d2bSIan Rogers 		pr_debug("Dropping stack user sample as possible ASLR leak\n");
1039575c6d2bSIan Rogers 		ret = 0;
1040575c6d2bSIan Rogers 		goto out_put;
1041575c6d2bSIan Rogers 	}
1042d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_WEIGHT_TYPE)
1043575c6d2bSIan Rogers 		COPY_U64(); /* perf_sample_weight */
1044d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_DATA_SRC)
1045575c6d2bSIan Rogers 		COPY_U64(); /* data_src */
1046d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_TRANSACTION)
1047575c6d2bSIan Rogers 		COPY_U64(); /* transaction */
1048d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_REGS_INTR) {
1049d6dbf2d4SIan Rogers 		u64 abi;
1050d6dbf2d4SIan Rogers 
1051575c6d2bSIan Rogers 		if (CHECK_BOUNDS(1, 0)) {
1052575c6d2bSIan Rogers 			ret = -EFAULT;
1053575c6d2bSIan Rogers 			goto out_put;
1054575c6d2bSIan Rogers 		}
1055d6dbf2d4SIan Rogers 		abi = in_array[i++];
1056d6dbf2d4SIan Rogers 		if (abi != PERF_SAMPLE_REGS_ABI_NONE) {
1057d6dbf2d4SIan Rogers 			u64 nr = hweight64(orig_regs_intr);
1058d6dbf2d4SIan Rogers 
1059d6dbf2d4SIan Rogers 			if (nr > max_i - i) {
1060d6dbf2d4SIan Rogers 				ret = -EFAULT;
1061575c6d2bSIan Rogers 				goto out_put;
1062575c6d2bSIan Rogers 			}
1063d6dbf2d4SIan Rogers 			i += nr;
1064d6dbf2d4SIan Rogers 		}
1065d6dbf2d4SIan Rogers 	}
1066d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_PHYS_ADDR) {
1067575c6d2bSIan Rogers 		COPY_U64(); /* phys_addr */
1068575c6d2bSIan Rogers 		/* TODO: can this be less conservative? */
1069575c6d2bSIan Rogers 		pr_debug("Dropping physical address sample as possible ASLR leak\n");
1070575c6d2bSIan Rogers 		ret = 0;
1071575c6d2bSIan Rogers 		goto out_put;
1072575c6d2bSIan Rogers 	}
1073d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_CGROUP)
1074575c6d2bSIan Rogers 		COPY_U64(); /* cgroup */
1075d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_DATA_PAGE_SIZE)
1076575c6d2bSIan Rogers 		COPY_U64(); /* data_page_size */
1077d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_CODE_PAGE_SIZE)
1078575c6d2bSIan Rogers 		COPY_U64(); /* code_page_size */
1079575c6d2bSIan Rogers 
1080d6dbf2d4SIan Rogers 	if (orig_sample_type & PERF_SAMPLE_AUX) {
1081575c6d2bSIan Rogers 		u64 size;
1082575c6d2bSIan Rogers 
1083575c6d2bSIan Rogers 		if (CHECK_BOUNDS(1, 1)) {
1084575c6d2bSIan Rogers 			ret = -EFAULT;
1085575c6d2bSIan Rogers 			goto out_put;
1086575c6d2bSIan Rogers 		}
1087575c6d2bSIan Rogers 		out_array[j] = in_array[i];
1088575c6d2bSIan Rogers 		size = out_array[j++];
1089575c6d2bSIan Rogers 		i++;
1090575c6d2bSIan Rogers 		if (size > 0) {
1091575c6d2bSIan Rogers 			size_t u64_words = size / 8 + (size % 8 ? 1 : 0);
1092575c6d2bSIan Rogers 
1093575c6d2bSIan Rogers 			if (u64_words > max_i - i || u64_words > max_j - j) {
1094575c6d2bSIan Rogers 				ret = -EFAULT;
1095575c6d2bSIan Rogers 				goto out_put;
1096575c6d2bSIan Rogers 			}
1097575c6d2bSIan Rogers 			memcpy(&out_array[j], &in_array[i], size);
1098575c6d2bSIan Rogers 			if (size % 8) {
1099575c6d2bSIan Rogers 				size_t pad = 8 - (size % 8);
1100575c6d2bSIan Rogers 
1101575c6d2bSIan Rogers 				memset(((char *)&out_array[j]) + size, 0, pad);
1102575c6d2bSIan Rogers 			}
1103575c6d2bSIan Rogers 			i += u64_words;
1104575c6d2bSIan Rogers 			j += u64_words;
1105575c6d2bSIan Rogers 		}
1106575c6d2bSIan Rogers 		/* TODO: can this be less conservative? */
1107575c6d2bSIan Rogers 		pr_debug("Dropping aux sample as possible ASLR leak\n");
1108575c6d2bSIan Rogers 		ret = 0;
1109575c6d2bSIan Rogers 		goto out_put;
1110575c6d2bSIan Rogers 	}
1111575c6d2bSIan Rogers 
1112575c6d2bSIan Rogers 	if (evsel__is_offcpu_event(evsel)) {
1113575c6d2bSIan Rogers 		/* TODO: can this be less conservative? */
1114575c6d2bSIan Rogers 		pr_debug("Dropping off-CPU sample as possible ASLR leak\n");
1115575c6d2bSIan Rogers 		ret = 0;
1116575c6d2bSIan Rogers 		goto out_put;
1117575c6d2bSIan Rogers 	}
1118575c6d2bSIan Rogers 
1119575c6d2bSIan Rogers 	new_event->sample.header.size = sizeof(struct perf_event_header) + j * sizeof(u64);
1120d6dbf2d4SIan Rogers 	/* Temporarily override evsel attributes to match the stripped new_event format! */
1121d6dbf2d4SIan Rogers 	evsel->sample_size = __evsel__sample_size(sample_type);
1122d6dbf2d4SIan Rogers 	evsel->core.attr.sample_type = sample_type;
1123d6dbf2d4SIan Rogers 	evsel->core.attr.sample_regs_user = 0;
1124d6dbf2d4SIan Rogers 	evsel->core.attr.sample_regs_intr = 0;
1125575c6d2bSIan Rogers 	perf_sample__init(&new_sample, /*all=*/ true);
1126575c6d2bSIan Rogers 	ret = __evsel__parse_sample(evsel, new_event, &new_sample, /*needs_swap=*/false);
1127575c6d2bSIan Rogers 
1128575c6d2bSIan Rogers 	if (ret) {
1129d6dbf2d4SIan Rogers 		/* Restore original attributes immediately if parsing fails */
1130d6dbf2d4SIan Rogers 		evsel->sample_size = orig_sample_size;
1131d6dbf2d4SIan Rogers 		evsel->core.attr.sample_type = orig_sample_type;
1132d6dbf2d4SIan Rogers 		evsel->core.attr.sample_regs_user = orig_regs_user;
1133d6dbf2d4SIan Rogers 		evsel->core.attr.sample_regs_intr = orig_regs_intr;
1134575c6d2bSIan Rogers 		perf_sample__exit(&new_sample);
1135575c6d2bSIan Rogers 		goto out_put;
1136575c6d2bSIan Rogers 	}
1137575c6d2bSIan Rogers 
1138575c6d2bSIan Rogers 	new_sample.evsel = evsel;
1139575c6d2bSIan Rogers 	ret = delegate->sample(delegate, new_event, &new_sample, machine);
1140575c6d2bSIan Rogers 	perf_sample__exit(&new_sample);
1141575c6d2bSIan Rogers 
1142d6dbf2d4SIan Rogers 	/* Restore original attributes so trace ingestion never desynchronizes! */
1143d6dbf2d4SIan Rogers 	evsel->sample_size = orig_sample_size;
1144d6dbf2d4SIan Rogers 	evsel->core.attr.sample_type = orig_sample_type;
1145d6dbf2d4SIan Rogers 	evsel->core.attr.sample_regs_user = orig_regs_user;
1146d6dbf2d4SIan Rogers 	evsel->core.attr.sample_regs_intr = orig_regs_intr;
1147d6dbf2d4SIan Rogers 
1148575c6d2bSIan Rogers out_put:
1149575c6d2bSIan Rogers 	thread__put(thread);
1150575c6d2bSIan Rogers 	return ret;
1151575c6d2bSIan Rogers }
1152575c6d2bSIan Rogers 
1153575c6d2bSIan Rogers #undef CHECK_BOUNDS
1154575c6d2bSIan Rogers #undef COPY_U64
1155575c6d2bSIan Rogers #undef REMAP_U64
1156febea9ecSIan Rogers 
1157febea9ecSIan Rogers static int skipn(int fd, off_t n)
1158febea9ecSIan Rogers {
1159febea9ecSIan Rogers 	char buf[4096];
1160febea9ecSIan Rogers 	ssize_t ret;
1161febea9ecSIan Rogers 
1162febea9ecSIan Rogers 	while (n > 0) {
1163febea9ecSIan Rogers 		ret = read(fd, buf, min_t(off_t, n, (off_t)sizeof(buf)));
1164febea9ecSIan Rogers 		if (ret <= 0)
1165febea9ecSIan Rogers 			return ret;
1166febea9ecSIan Rogers 		n -= ret;
1167febea9ecSIan Rogers 	}
1168febea9ecSIan Rogers 
1169febea9ecSIan Rogers 	return 0;
1170febea9ecSIan Rogers }
1171febea9ecSIan Rogers 
1172febea9ecSIan Rogers static s64 aslr_tool__process_auxtrace(const struct perf_tool *tool __maybe_unused,
1173febea9ecSIan Rogers 				       struct perf_session *session,
1174febea9ecSIan Rogers 				       union perf_event *event)
1175febea9ecSIan Rogers {
1176febea9ecSIan Rogers 	pr_warning_once("ASLR: Dropping auxtrace data as it cannot be obfuscated.\n");
1177febea9ecSIan Rogers 	if (perf_data__is_pipe(session->data)) {
1178febea9ecSIan Rogers 		/* Copy behavior of the stub by reading all pipe data. */
1179febea9ecSIan Rogers 		int err = skipn(perf_data__fd(session->data), event->auxtrace.size);
1180febea9ecSIan Rogers 
1181febea9ecSIan Rogers 		if (err < 0)
1182febea9ecSIan Rogers 			return err;
1183febea9ecSIan Rogers 	}
1184febea9ecSIan Rogers 	return event->auxtrace.size;
1185febea9ecSIan Rogers }
1186febea9ecSIan Rogers 
1187febea9ecSIan Rogers static int aslr_tool__process_auxtrace_info(const struct perf_tool *tool __maybe_unused,
1188febea9ecSIan Rogers 					    struct perf_session *session __maybe_unused,
1189febea9ecSIan Rogers 					    union perf_event *event __maybe_unused)
1190febea9ecSIan Rogers {
1191febea9ecSIan Rogers 	return 0;
1192febea9ecSIan Rogers }
1193febea9ecSIan Rogers 
1194febea9ecSIan Rogers static int aslr_tool__process_auxtrace_error(const struct perf_tool *tool __maybe_unused,
1195febea9ecSIan Rogers 					     struct perf_session *session __maybe_unused,
1196febea9ecSIan Rogers 					     union perf_event *event __maybe_unused)
1197febea9ecSIan Rogers {
1198febea9ecSIan Rogers 	return 0;
1199febea9ecSIan Rogers }
1200febea9ecSIan Rogers 
1201d6dbf2d4SIan Rogers void aslr_tool__strip_attr_event(union perf_event *event, struct evlist *evlist)
1202febea9ecSIan Rogers {
1203febea9ecSIan Rogers 	u32 attr_size;
1204febea9ecSIan Rogers 
1205d6dbf2d4SIan Rogers 	if (!evlist)
1206d6dbf2d4SIan Rogers 		return;
1207d6dbf2d4SIan Rogers 
1208febea9ecSIan Rogers 	attr_size = event->attr.attr.size ?: PERF_ATTR_SIZE_VER0;
1209febea9ecSIan Rogers 
1210febea9ecSIan Rogers 	if (attr_size >= (offsetof(struct perf_event_attr, sample_type) + sizeof(u64))) {
1211febea9ecSIan Rogers 		event->attr.attr.sample_type &= ASLR_SUPPORTED_SAMPLE_TYPE;
1212d6dbf2d4SIan Rogers 
1213d6dbf2d4SIan Rogers 		if (attr_size >= (offsetof(struct perf_event_attr, sample_regs_user) + sizeof(u64)))
1214d6dbf2d4SIan Rogers 			event->attr.attr.sample_regs_user = 0;
1215d6dbf2d4SIan Rogers 		if (attr_size >= (offsetof(struct perf_event_attr, sample_regs_intr) + sizeof(u64)))
1216d6dbf2d4SIan Rogers 			event->attr.attr.sample_regs_intr = 0;
1217febea9ecSIan Rogers 	}
1218febea9ecSIan Rogers 
1219febea9ecSIan Rogers 	if (attr_size >= (offsetof(struct perf_event_attr, type) + sizeof(u32))) {
1220febea9ecSIan Rogers 		u32 type = event->attr.attr.type;
1221febea9ecSIan Rogers 
1222febea9ecSIan Rogers 		if (type == PERF_TYPE_BREAKPOINT &&
1223febea9ecSIan Rogers 		    attr_size >= (offsetof(struct perf_event_attr, bp_addr) + sizeof(u64))) {
1224febea9ecSIan Rogers 			event->attr.attr.bp_addr = 0;
1225febea9ecSIan Rogers 		} else if (type >= PERF_TYPE_MAX) {
1226febea9ecSIan Rogers 			struct perf_pmu *pmu;
1227febea9ecSIan Rogers 
1228febea9ecSIan Rogers 			pmu = perf_pmus__find_by_type(type);
1229febea9ecSIan Rogers 			if (pmu && (!strcmp(pmu->name, "kprobe") ||
1230febea9ecSIan Rogers 				    !strcmp(pmu->name, "uprobe"))) {
1231febea9ecSIan Rogers 				if (attr_size >= (offsetof(struct perf_event_attr, config1) + sizeof(u64)))
1232febea9ecSIan Rogers 					event->attr.attr.config1 = 0;
1233febea9ecSIan Rogers 				if (attr_size >= (offsetof(struct perf_event_attr, config2) + sizeof(u64)))
1234febea9ecSIan Rogers 					event->attr.attr.config2 = 0;
1235febea9ecSIan Rogers 			}
1236febea9ecSIan Rogers 		}
1237febea9ecSIan Rogers 	}
1238febea9ecSIan Rogers }
1239febea9ecSIan Rogers 
1240*8a450659SArnaldo Carvalho de Melo static int aslr_tool__init(struct aslr_tool *aslr, struct perf_tool *delegate)
1241febea9ecSIan Rogers {
1242febea9ecSIan Rogers 	delegate_tool__init(&aslr->tool, delegate);
1243febea9ecSIan Rogers 	aslr->tool.tool.ordered_events = true;
1244febea9ecSIan Rogers 
1245*8a450659SArnaldo Carvalho de Melo 	if (machines__init(&aslr->machines))
1246*8a450659SArnaldo Carvalho de Melo 		return -ENOMEM;
1247febea9ecSIan Rogers 
1248febea9ecSIan Rogers 	hashmap__init(&aslr->remap_addresses,
1249febea9ecSIan Rogers 		      remap_addresses__hash, remap_addresses__equal,
1250febea9ecSIan Rogers 		      /*ctx=*/NULL);
1251febea9ecSIan Rogers 	hashmap__init(&aslr->top_addresses,
1252febea9ecSIan Rogers 		      top_addresses__hash, top_addresses__equal,
1253febea9ecSIan Rogers 		      /*ctx=*/NULL);
1254d6dbf2d4SIan Rogers 	hashmap__init(&aslr->evsel_orig_attrs,
1255d6dbf2d4SIan Rogers 		      evsel_hash, evsel_equal,
1256d6dbf2d4SIan Rogers 		      /*ctx=*/NULL);
1257febea9ecSIan Rogers 
1258febea9ecSIan Rogers 	aslr->tool.tool.sample	= aslr_tool__process_sample;
1259febea9ecSIan Rogers 	/* read - reads a counter, okay to delegate. */
1260febea9ecSIan Rogers 	aslr->tool.tool.mmap	= aslr_tool__process_mmap;
1261febea9ecSIan Rogers 	aslr->tool.tool.mmap2	= aslr_tool__process_mmap2;
1262febea9ecSIan Rogers 	aslr->tool.tool.comm	= aslr_tool__process_comm;
1263febea9ecSIan Rogers 	aslr->tool.tool.fork	= aslr_tool__process_fork;
1264febea9ecSIan Rogers 	aslr->tool.tool.exit	= aslr_tool__process_exit;
1265febea9ecSIan Rogers 	/* namesspaces, cgroup, lost, lost_sample, aux, */
1266febea9ecSIan Rogers 	/* itrace_start, aux_output_hw_id, context_switch, throttle, unthrottle */
1267febea9ecSIan Rogers 	/* - no virtual addresses. */
1268febea9ecSIan Rogers 	aslr->tool.tool.ksymbol	= aslr_tool__process_ksymbol;
1269febea9ecSIan Rogers 	/* bpf - no virtual address. */
1270febea9ecSIan Rogers 	aslr->tool.tool.text_poke = aslr_tool__process_text_poke;
1271febea9ecSIan Rogers 	/*
1272febea9ecSIan Rogers 	 * event_update, tracing_data, finished_round, build_id, id_index,
1273febea9ecSIan Rogers 	 * auxtrace_info, auxtrace_error, time_conv, thread_map, cpu_map,
1274febea9ecSIan Rogers 	 * stat_config, stat, feature, finished_init, bpf_metadata, compressed,
1275febea9ecSIan Rogers 	 * auxtrace - no virtual addresses.
1276febea9ecSIan Rogers 	 */
1277febea9ecSIan Rogers 	aslr->tool.tool.auxtrace = aslr_tool__process_auxtrace;
1278febea9ecSIan Rogers 	aslr->tool.tool.auxtrace_info = aslr_tool__process_auxtrace_info;
1279febea9ecSIan Rogers 	aslr->tool.tool.auxtrace_error = aslr_tool__process_auxtrace_error;
1280*8a450659SArnaldo Carvalho de Melo 
1281*8a450659SArnaldo Carvalho de Melo 	return 0;
1282febea9ecSIan Rogers }
1283febea9ecSIan Rogers 
1284febea9ecSIan Rogers struct perf_tool *aslr_tool__new(struct perf_tool *delegate)
1285febea9ecSIan Rogers {
1286febea9ecSIan Rogers 	struct aslr_tool *aslr = zalloc(sizeof(*aslr));
1287febea9ecSIan Rogers 
1288febea9ecSIan Rogers 	if (!aslr)
1289febea9ecSIan Rogers 		return NULL;
1290febea9ecSIan Rogers 
1291*8a450659SArnaldo Carvalho de Melo 	if (aslr_tool__init(aslr, delegate)) {
1292*8a450659SArnaldo Carvalho de Melo 		free(aslr);
1293*8a450659SArnaldo Carvalho de Melo 		return NULL;
1294*8a450659SArnaldo Carvalho de Melo 	}
1295febea9ecSIan Rogers 	return &aslr->tool.tool;
1296febea9ecSIan Rogers }
1297febea9ecSIan Rogers 
1298febea9ecSIan Rogers void aslr_tool__delete(struct perf_tool *tool)
1299febea9ecSIan Rogers {
1300febea9ecSIan Rogers 	struct delegate_tool *del_tool;
1301febea9ecSIan Rogers 	struct aslr_tool *aslr;
1302febea9ecSIan Rogers 	struct hashmap_entry *cur;
1303febea9ecSIan Rogers 	size_t bkt;
1304febea9ecSIan Rogers 	struct rb_node *nd;
1305febea9ecSIan Rogers 
1306febea9ecSIan Rogers 	if (!tool)
1307febea9ecSIan Rogers 		return;
1308febea9ecSIan Rogers 
1309febea9ecSIan Rogers 	del_tool = container_of(tool, struct delegate_tool, tool);
1310febea9ecSIan Rogers 	aslr = container_of(del_tool, struct aslr_tool, tool);
1311febea9ecSIan Rogers 
1312febea9ecSIan Rogers 	hashmap__for_each_entry(&aslr->remap_addresses, cur, bkt) {
1313febea9ecSIan Rogers 		struct remap_addresses_key *key = (struct remap_addresses_key *)cur->pkey;
1314febea9ecSIan Rogers 
1315febea9ecSIan Rogers 		if (key)
1316febea9ecSIan Rogers 			dso__put(key->dso);
1317febea9ecSIan Rogers 		zfree(&cur->pkey);
1318febea9ecSIan Rogers 		zfree(&cur->pvalue);
1319febea9ecSIan Rogers 	}
1320febea9ecSIan Rogers 	hashmap__for_each_entry(&aslr->top_addresses, cur, bkt) {
1321febea9ecSIan Rogers 		zfree(&cur->pkey);
1322febea9ecSIan Rogers 		zfree(&cur->pvalue);
1323febea9ecSIan Rogers 	}
1324d6dbf2d4SIan Rogers 	hashmap__for_each_entry(&aslr->evsel_orig_attrs, cur, bkt) {
1325d6dbf2d4SIan Rogers 		zfree(&cur->pvalue);
1326d6dbf2d4SIan Rogers 	}
1327febea9ecSIan Rogers 
1328febea9ecSIan Rogers 	hashmap__clear(&aslr->remap_addresses);
1329febea9ecSIan Rogers 	hashmap__clear(&aslr->top_addresses);
1330d6dbf2d4SIan Rogers 	hashmap__clear(&aslr->evsel_orig_attrs);
1331febea9ecSIan Rogers 	aslr_tool__destroy_machines_priv(&aslr->machines);
1332febea9ecSIan Rogers 	machines__destroy_kernel_maps(&aslr->machines);
1333febea9ecSIan Rogers 
1334febea9ecSIan Rogers 	while ((nd = rb_first_cached(&aslr->machines.guests)) != NULL) {
1335febea9ecSIan Rogers 		struct machine *machine = rb_entry(nd, struct machine, rb_node);
1336febea9ecSIan Rogers 
1337febea9ecSIan Rogers 		rb_erase_cached(nd, &aslr->machines.guests);
1338febea9ecSIan Rogers 		machine__delete(machine);
1339febea9ecSIan Rogers 	}
1340febea9ecSIan Rogers 
1341febea9ecSIan Rogers 	machines__exit(&aslr->machines);
1342febea9ecSIan Rogers 	free(aslr);
1343febea9ecSIan Rogers }
1344d6dbf2d4SIan Rogers 
1345d6dbf2d4SIan Rogers int aslr_tool__cache_orig_attrs(struct perf_tool *tool, struct evsel *evsel)
1346d6dbf2d4SIan Rogers {
1347d6dbf2d4SIan Rogers 	struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool);
1348d6dbf2d4SIan Rogers 	struct aslr_tool *aslr = container_of(del_tool, struct aslr_tool, tool);
1349d6dbf2d4SIan Rogers 	struct aslr_evsel_priv *priv = zalloc(sizeof(*priv));
1350d6dbf2d4SIan Rogers 	int err;
1351d6dbf2d4SIan Rogers 
1352d6dbf2d4SIan Rogers 	if (!priv)
1353d6dbf2d4SIan Rogers 		return -ENOMEM;
1354d6dbf2d4SIan Rogers 
1355d6dbf2d4SIan Rogers 	priv->orig_sample_type = evsel->core.attr.sample_type;
1356d6dbf2d4SIan Rogers 	priv->orig_sample_regs_user = evsel->core.attr.sample_regs_user;
1357d6dbf2d4SIan Rogers 	priv->orig_sample_regs_intr = evsel->core.attr.sample_regs_intr;
1358d6dbf2d4SIan Rogers 	priv->orig_sample_size = evsel->sample_size;
1359d6dbf2d4SIan Rogers 
1360d6dbf2d4SIan Rogers 	err = hashmap__add(&aslr->evsel_orig_attrs, evsel, priv);
1361d6dbf2d4SIan Rogers 	if (err) {
1362d6dbf2d4SIan Rogers 		free(priv);
1363d6dbf2d4SIan Rogers 		return err;
1364d6dbf2d4SIan Rogers 	}
1365d6dbf2d4SIan Rogers 	return 0;
1366d6dbf2d4SIan Rogers }
1367d6dbf2d4SIan Rogers 
1368d6dbf2d4SIan Rogers void aslr_tool__strip_evlist(const struct perf_tool *tool __maybe_unused, struct evlist *evlist)
1369d6dbf2d4SIan Rogers {
1370d6dbf2d4SIan Rogers 	struct evsel *evsel;
1371d6dbf2d4SIan Rogers 
1372d6dbf2d4SIan Rogers 	evlist__for_each_entry(evlist, evsel) {
1373d6dbf2d4SIan Rogers 		evsel->core.attr.sample_type &= ASLR_SUPPORTED_SAMPLE_TYPE;
1374d6dbf2d4SIan Rogers 		evsel->core.attr.sample_regs_user = 0;
1375d6dbf2d4SIan Rogers 		evsel->core.attr.sample_regs_intr = 0;
1376d6dbf2d4SIan Rogers 		evsel->sample_size = __evsel__sample_size(evsel->core.attr.sample_type);
1377d6dbf2d4SIan Rogers 		evsel__calc_id_pos(evsel);
1378d6dbf2d4SIan Rogers 
1379d6dbf2d4SIan Rogers 		if (evsel->core.attr.type == PERF_TYPE_BREAKPOINT) {
1380d6dbf2d4SIan Rogers 			evsel->core.attr.bp_addr = 0;
1381d6dbf2d4SIan Rogers 		} else if (evsel->core.attr.type >= PERF_TYPE_MAX) {
1382d6dbf2d4SIan Rogers 			struct perf_pmu *pmu = perf_pmus__find_by_type(evsel->core.attr.type);
1383d6dbf2d4SIan Rogers 
1384d6dbf2d4SIan Rogers 			if (pmu && (!strcmp(pmu->name, "kprobe") ||
1385d6dbf2d4SIan Rogers 				    !strcmp(pmu->name, "uprobe"))) {
1386d6dbf2d4SIan Rogers 				evsel->core.attr.config1 = 0;
1387d6dbf2d4SIan Rogers 				evsel->core.attr.config2 = 0;
1388d6dbf2d4SIan Rogers 			}
1389d6dbf2d4SIan Rogers 		}
1390d6dbf2d4SIan Rogers 	}
1391d6dbf2d4SIan Rogers }
1392d6dbf2d4SIan Rogers 
1393d6dbf2d4SIan Rogers void aslr_tool__restore_evlist(const struct perf_tool *tool, struct evlist *evlist)
1394d6dbf2d4SIan Rogers {
1395d6dbf2d4SIan Rogers 	const struct delegate_tool *del_tool = container_of(tool, const struct delegate_tool, tool);
1396d6dbf2d4SIan Rogers 	const struct aslr_tool *aslr = container_of(del_tool, const struct aslr_tool, tool);
1397d6dbf2d4SIan Rogers 	struct evsel *evsel;
1398d6dbf2d4SIan Rogers 	struct aslr_evsel_priv *priv;
1399d6dbf2d4SIan Rogers 
1400d6dbf2d4SIan Rogers 	evlist__for_each_entry(evlist, evsel) {
1401d6dbf2d4SIan Rogers 		if (hashmap__find(&aslr->evsel_orig_attrs, evsel, &priv)) {
1402d6dbf2d4SIan Rogers 			evsel->core.attr.sample_type = priv->orig_sample_type;
1403d6dbf2d4SIan Rogers 			evsel->core.attr.sample_regs_user = priv->orig_sample_regs_user;
1404d6dbf2d4SIan Rogers 			evsel->core.attr.sample_regs_intr = priv->orig_sample_regs_intr;
1405d6dbf2d4SIan Rogers 			evsel->sample_size = priv->orig_sample_size;
1406d6dbf2d4SIan Rogers 			evsel__calc_id_pos(evsel);
1407d6dbf2d4SIan Rogers 		}
1408d6dbf2d4SIan Rogers 	}
1409d6dbf2d4SIan Rogers }
1410