diff options
-rw-r--r-- | include/linux/uprobes.h | 1 | ||||
-rw-r--r-- | kernel/events/uprobes.c | 42 |
2 files changed, 43 insertions, 0 deletions
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h index 24594571c5a..ffb1984db93 100644 --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h @@ -84,6 +84,7 @@ struct xol_area { * the vma go away, and we must handle that reasonably gracefully. */ unsigned long vaddr; /* Page(s) of instruction slots */ + unsigned long uretprobe_trampoline_addr; /* addr of trampolines */ }; struct uprobes_state { diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index c92651d619c..29c73d7b1c2 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -99,6 +99,7 @@ struct uprobe { }; /* +static struct xol_area *get_xol_area(struct mm_struct *mm); * valid_vma: Verify if the specified vma is an executable vma * Relax restrictions while unregistering: vm_flags might have * changed after breakpoint was inserted. @@ -1238,6 +1239,47 @@ static void xol_free_insn_slot(struct task_struct *tsk) } } +/* xol_get_trampoline_slot - A trampoline slot is obtained the first + * time a uprobe corresponding to a uretprobe is hit for a process. We + * use one trampoline slot for all probes pertaining to a process, i.e + * one per uprobes_xol_area. + */ +static unsigned long xol_get_trampoline_slot(void) +{ + struct mm_struct *mm = current->mm; + struct xol_area *area; + unsigned long xol_trampoline_addr = 0; + unsigned long offset; + void *vaddr; + uprobe_opcode_t bp_insn = UPROBE_SWBP_INSN; + + area = get_xol_area(mm); + if (!area) { + area = xol_alloc_area(); + if (!area) + return 0; + } + + xol_trampoline_addr = area->uretprobe_trampoline_addr; + if (!xol_trampoline_addr) { + xol_trampoline_addr = xol_take_insn_slot(area); + area->uretprobe_trampoline_addr = xol_trampoline_addr; + } + + /* Initialize the slot if trampoline_addr points to valid + * instruction slot. + */ + if (unlikely(!xol_trampoline_addr)) + return 0; + + offset = xol_trampoline_addr & ~PAGE_MASK; + vaddr = kmap_atomic(area->page); + memcpy(vaddr + offset, &bp_insn, UPROBE_SWBP_INSN_SIZE); + kunmap_atomic(vaddr); + + return area->uretprobe_trampoline_addr; +} + /** * uprobe_get_swbp_addr - compute address of swbp given post-swbp regs * @regs: Reflects the saved state of the task after it has hit a breakpoint |