Skip to content

Commit

Permalink
mcount-dynamic: Use MAP_FIXED_NOREPLACE for trampoline
Browse files Browse the repository at this point in the history
By trying to allocate the extra page for a trampoline with MAP_FIXED,
Uftrace could end up overlapping already mapped pages, which are
discarded.  Typically, if data was there with rw- protection, now the
data is undefined and has rwx protection.

Since Linux 4.17, the flag MAP_FIXED_NOREPLACE can be used to ensure
that the fixed location is mapped atomically, preventing any clobbering.

For earlier kernel, the call to mmap(2) will fall back to a random
address, by not honoring the MAP_FIXED request at all.  So callers
should ensure that the returned address matches the requested one.

Signed-off-by: Olivier Dion <odion@efficios.com>
  • Loading branch information
Olivier Dion authored and namhyung committed Sep 4, 2023
1 parent b2e3503 commit 955b9e9
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 8 deletions.
12 changes: 10 additions & 2 deletions arch/aarch64/mcount-dynamic.c
Expand Up @@ -63,13 +63,21 @@ int mcount_setup_trampoline(struct mcount_dynamic_info *mdi)
mdi->trampoline -= sizeof(trampoline);

if (unlikely(mdi->trampoline < mdi->text_addr + mdi->text_size)) {
void *trampoline_check;

mdi->trampoline += sizeof(trampoline);
mdi->text_size += PAGE_SIZE;

pr_dbg("adding a page for fentry trampoline at %#lx\n", mdi->trampoline);

mmap((void *)mdi->trampoline, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
trampoline_check = mmap((void *)mdi->trampoline, PAGE_SIZE,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

if (trampoline_check != (void *)mdi->trampoline) {
pr_err("could not map trampoline at desired location %#lx, got %#lx: %m\n",
mdi->trampoline, (uintptr_t)trampoline_check);
}
}

page_offset = mdi->text_addr & (PAGE_SIZE - 1);
Expand Down
8 changes: 5 additions & 3 deletions arch/i386/mcount-dynamic.c
Expand Up @@ -30,10 +30,12 @@ int mcount_setup_trampoline(struct mcount_dynamic_info *mdi)
pr_dbg2("adding a page for fentry trampoline at %#lx\n", mdi->trampoline);

trampoline_check = mmap((void *)mdi->trampoline, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

if (trampoline_check == MAP_FAILED)
pr_err("failed to mmap trampoline for setup");
if (trampoline_check != (void *)mdi->trampoline) {
pr_err("could not map trampoline at desired location %#lx, got %#lx: %m\n",
mdi->trampoline, (uintptr_t)trampoline_check);
}
}

if (mprotect((void *)mdi->text_addr, mdi->text_size, PROT_READ | PROT_WRITE)) {
Expand Down
8 changes: 5 additions & 3 deletions arch/x86_64/mcount-dynamic.c
Expand Up @@ -43,10 +43,12 @@ int mcount_setup_trampoline(struct mcount_dynamic_info *mdi)

trampoline_check = mmap((void *)mdi->trampoline, PAGE_SIZE,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

if (trampoline_check == MAP_FAILED)
pr_err("failed to mmap trampoline for setup");
if (trampoline_check != (void *)mdi->trampoline) {
pr_err("could not map trampoline at desired location %#lx, got %#lx: %m\n",
mdi->trampoline, (uintptr_t)trampoline_check);
}
}

if (mprotect(PAGE_ADDR(mdi->text_addr), PAGE_LEN(mdi->text_addr, mdi->text_size),
Expand Down

0 comments on commit 955b9e9

Please sign in to comment.