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