lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Date: Thu, 28 Feb 2013 12:00:13 +0100 From: Anton Arapov <anton@...hat.com> To: Anton Arapov <anton@...hat.com>, Oleg Nesterov <oleg@...hat.com>, Srikar Dronamraju <srikar@...ux.vnet.ibm.com> Cc: LKML <linux-kernel@...r.kernel.org>, Josh Stone <jistone@...hat.com>, Frank Eigler <fche@...hat.com>, Peter Zijlstra <peterz@...radead.org>, Ingo Molnar <mingo@...e.hu>, Ananth N Mavinakayanahalli <ananth@...ibm.com> Subject: [RFC PATCH v3 4/6] uretprobes: return probe entry, prepare uretprobe When a uprobe with return consumer is hit, prepare_uretprobe function is invoked. It creates return_instance, hijacks return address and replaces it with the trampoline. N.B. it might be a good idea to introduce get_uprobe() to reflect put_uprobe() later, but it is not a subject of this patchset. v3: - protected uprobe with refcounter. See atomic_inc in prepare_uretprobe() and put_uprobe() in a following patch in handle_uretprobe() v2: - get rid of ->return_consumers member from struct uprobe, introduce rp_handler() in consumer Signed-off-by: Anton Arapov <anton@...hat.com> --- include/linux/uprobes.h | 5 +++++ kernel/events/uprobes.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h index a28bdee..6aaa1ce 100644 --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h @@ -69,6 +69,10 @@ struct uprobe_task { enum uprobe_task_state state; struct arch_uprobe_task autask; + /* + * list for tracking uprobes with return consumers + */ + struct hlist_head return_uprobes; struct uprobe *active_uprobe; unsigned long xol_vaddr; @@ -92,6 +96,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 rp_trampoline_vaddr; /* trampoline address */ }; struct uprobes_state { diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 69bf060..57f70cd 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -75,6 +75,12 @@ struct uprobe { struct arch_uprobe arch; }; +struct return_uprobe_i { + struct uprobe *uprobe; + struct hlist_node hlist; /* node in list */ + unsigned long orig_ret_vaddr; /* original return address */ +}; + /* * valid_vma: Verify if the specified vma is an executable vma * Relax restrictions while unregistering: vm_flags might have @@ -1336,11 +1342,48 @@ void uprobe_copy_process(struct task_struct *t) */ static struct uprobe_task *get_utask(void) { - if (!current->utask) + if (!current->utask) { current->utask = kzalloc(sizeof(struct uprobe_task), GFP_KERNEL); + if (current->utask) + INIT_HLIST_HEAD(¤t->utask->return_uprobes); + } return current->utask; } +static void prepare_uretprobe(struct uprobe *uprobe, struct pt_regs *regs) +{ + struct return_uprobe_i *ri; + struct uprobe_task *utask; + struct xol_area *area; + unsigned long rp_trampoline_vaddr = 0; + uprobe_opcode_t insn = UPROBE_SWBP_INSN; + + area = get_xol_area(); + if (area) + rp_trampoline_vaddr = area->rp_trampoline_vaddr; + if (!rp_trampoline_vaddr) { + rp_trampoline_vaddr = xol_get_insn_slot(&insn); + if (!rp_trampoline_vaddr) + return; + } + area->rp_trampoline_vaddr = rp_trampoline_vaddr; + + ri = kzalloc(sizeof(struct return_uprobe_i), GFP_KERNEL); + if (!ri) + return; + + utask = get_utask(); + ri->orig_ret_vaddr = arch_uretprobe_hijack_return_addr(rp_trampoline_vaddr, regs); + if (likely(ri->orig_ret_vaddr)) { + /* TODO: uretprobe bypass logic */ + atomic_inc(&uprobe->ref); + ri->uprobe = uprobe; + INIT_HLIST_NODE(&ri->hlist); + hlist_add_head(&ri->hlist, &utask->return_uprobes); + } else + kfree(ri); +} + /* Prepare to single-step probed instruction out of line. */ static int pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, unsigned long bp_vaddr) @@ -1494,12 +1537,17 @@ static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp) static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs) { + int rc = 0; struct uprobe_consumer *uc; int remove = UPROBE_HANDLER_REMOVE; down_read(&uprobe->register_rwsem); for (uc = uprobe->consumers; uc; uc = uc->next) { - int rc = uc->handler(uc, regs); + if (uc->handler) + rc = uc->handler(uc, regs); + + if (uc->rp_handler) + prepare_uretprobe(uprobe, regs); /* put bp at return */ WARN(rc & ~UPROBE_HANDLER_MASK, "bad rc=0x%x from %pf()\n", rc, uc->handler); -- 1.8.1.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@...r.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists