For uprobes 1 and 2, add unmap_u[ret]probe() and define UPROBES_API_VERSION=2.
Adapt tapsets.cxx accordingly.
}
EXPORT_SYMBOL_GPL(register_uprobe);
-/* See Documentation/uprobes.txt. */
-void unregister_uprobe(struct uprobe *u)
+void __unregister_uprobe(struct uprobe *u, bool remove_bkpt)
{
struct task_struct *p;
struct uprobe_process *uproc;
if (!list_empty(&ppt->uprobe_list))
goto done;
- /*
- * The last uprobe at ppt's probepoint is being unregistered.
- * Queue the breakpoint for removal.
- */
+ /* The last uprobe at ppt's probepoint is being unregistered. */
+ if (!remove_bkpt) {
+ uprobe_free_probept(ppt);
+ goto done;
+ }
+
+ /* Queue the breakpoint for removal. */
ppt->state = UPROBE_REMOVING;
list_add_tail(&ppt->pd_node, &uproc->pending_uprobes);
up_write(&uproc->rwsem);
uprobe_put_process(uproc);
}
+
+/* See Documentation/uprobes.txt. */
+void unregister_uprobe(struct uprobe *u)
+{
+ __unregister_uprobe(u, true);
+}
EXPORT_SYMBOL_GPL(unregister_uprobe);
+void unmap_uprobe(struct uprobe *u)
+{
+ __unregister_uprobe(u, false);
+}
+EXPORT_SYMBOL_GPL(unmap_uprobe);
+
/* Find a surviving thread in uproc. Runs with uproc->rwsem locked. */
static struct task_struct *find_surviving_thread(struct uprobe_process *uproc)
{
}
EXPORT_SYMBOL_GPL(unregister_uretprobe);
+void unmap_uretprobe(struct uretprobe *rp)
+{
+ if (!rp)
+ return;
+ unmap_uprobe(&rp->u);
+}
+EXPORT_SYMBOL_GPL(unmap_uretprobe);
+
/*
* uproc->ssol_area has been successfully set up. Establish the
* uretprobe trampoline in slot 0.
#include <linux/types.h>
#include <linux/list.h>
+/* Version 2 includes unmap_u[ret]probe(). */
+#define UPROBES_API_VERSION 2
+
struct pt_regs;
enum uprobe_type {
/* For runtime, assume uprobes support includes uretprobes. */
extern int register_uretprobe(struct uretprobe *rp);
extern void unregister_uretprobe(struct uretprobe *rp);
+/* For PRs 9940, 6852... */
+extern void unmap_uprobe(struct uprobe *u);
+extern void unmap_uretprobe(struct uretprobe *rp);
#ifdef UPROBES_IMPLEMENTATION
*/
static struct pid *uprobe_get_tg_leader(pid_t p)
{
- struct pid *pid;
+ struct pid *pid = NULL;
rcu_read_lock();
- pid = find_vpid(p);
+ /*
+ * We need this check because unmap_u[ret]probe() can be called
+ * from a report_death callback, where current->proxy is NULL.
+ */
+ if (current->nsproxy)
+ pid = find_vpid(p);
if (pid) {
struct task_struct *t = pid_task(pid, PIDTYPE_PID);
if (t)
}
EXPORT_SYMBOL_GPL(register_uprobe);
-/* See Documentation/uprobes.txt. */
-void unregister_uprobe(struct uprobe *u)
+void __unregister_uprobe(struct uprobe *u, bool remove_bkpt)
{
struct pid *p;
struct uprobe_process *uproc;
if (!list_empty(&ppt->uprobe_list))
goto done;
- /*
- * The last uprobe at ppt's probepoint is being unregistered.
- * Queue the breakpoint for removal.
- */
+ /* The last uprobe at ppt's probepoint is being unregistered. */
+ if (!remove_bkpt) {
+ uprobe_free_probept(ppt);
+ goto done;
+ }
+
+ /* Queue the breakpoint for removal. */
ppt->state = UPROBE_REMOVING;
list_add_tail(&ppt->pd_node, &uproc->pending_uprobes);
up_write(&uproc->rwsem);
uprobe_put_process(uproc, false);
}
+
+/* See Documentation/uprobes.txt. */
+void unregister_uprobe(struct uprobe *u)
+{
+ __unregister_uprobe(u, true);
+}
EXPORT_SYMBOL_GPL(unregister_uprobe);
+void unmap_uprobe(struct uprobe *u)
+{
+ __unregister_uprobe(u, false);
+}
+EXPORT_SYMBOL_GPL(unmap_uprobe);
+
/* Find a surviving thread in uproc. Runs with uproc->rwsem locked. */
static struct task_struct *find_surviving_thread(struct uprobe_process *uproc)
{
}
EXPORT_SYMBOL_GPL(unregister_uretprobe);
+void unmap_uretprobe(struct uretprobe *rp)
+{
+ if (!rp)
+ return;
+ unmap_uprobe(&rp->u);
+}
+EXPORT_SYMBOL_GPL(unmap_uretprobe);
+
/*
* uproc->ssol_area has been successfully set up. Establish the
* uretprobe trampoline in the next available slot following the
#define utrace_attached_engine utrace_engine
#endif
+/* Version 2 includes unmap_u[ret]probe(). */
+#define UPROBES_API_VERSION 2
+
struct pt_regs;
enum uprobe_type {
/* For runtime, assume uprobes support includes uretprobes. */
extern int register_uretprobe(struct uretprobe *rp);
extern void unregister_uretprobe(struct uretprobe *rp);
+/* For PRs 9940, 6852... */
+extern void unmap_uprobe(struct uprobe *u);
+extern void unmap_uretprobe(struct uretprobe *rp);
#ifdef UPROBES_IMPLEMENTATION
s.op->newline() << "#else";
s.op->newline() << "#include \"uprobes/uprobes.h\"";
s.op->newline() << "#endif";
+ s.op->newline() << "#ifndef UPROBES_API_VERSION";
+ s.op->newline() << "#define UPROBES_API_VERSION 1";
+ s.op->newline() << "#endif";
s.op->newline() << "#ifndef MULTIPLE_UPROBES";
s.op->newline() << "#define MULTIPLE_UPROBES 256"; // maximum possible armed uprobes per process() probe point
// register new uprobe
s.op->newline() << "if (register_p && sup->spec_index < 0) {";
- // PR6829: we need to check that the sup we're about to reuse is really completely free.
- // See PR6829 notes below.
- s.op->newline(1) << "if (sup->spec_index == -1 && sup->up.kdata != NULL) continue;";
+ s.op->newline(1) << "#if (UPROBES_API_VERSION < 2)";
+ // See PR6829 comment.
+ s.op->newline() << "if (sup->spec_index == -1 && sup->up.kdata != NULL) continue;";
s.op->newline() << "else if (sup->spec_index == -2 && sup->urp.u.kdata != NULL) continue;";
+ s.op->newline() << "#endif";
s.op->newline() << "sup->spec_index = spec_index;";
s.op->newline() << "slotted_p = 1;";
s.op->newline() << "break;";
s.op->newline(-1) << "} else if (!register_p && slotted_p) {";
s.op->newline(1) << "struct stap_uprobe *sup = & stap_uprobes[i];";
- // NB: we need to release this slot, so we need to borrow the mutex temporarily.
+ s.op->newline() << "int unregistered_flag;";
+ // PR6829, PR9940:
+ // Here we're unregistering for one of two reasons:
+ // 1. the process image is going away (or gone) due to exit or exec; or
+ // 2. the vma containing the probepoint has been unmapped.
+ // In case 1, it's sort of a nop, because uprobes will notice the event
+ // and dispose of the probes eventually, if it hasn't already. But by
+ // calling unmap_u[ret]probe() ourselves, we free up sup right away.
+ //
+ // In both cases, we must use unmap_u[ret]probe instead of
+ // unregister_u[ret]probe, so uprobes knows not to try to restore the
+ // original opcode.
+ s.op->newline() << "#if (UPROBES_API_VERSION >= 2)";
+ s.op->newline() << "if (sups->return_p)";
+ s.op->newline(1) << "unmap_uretprobe (& sup->urp);";
+ s.op->newline(-1) << "else";
+ s.op->newline(1) << "unmap_uprobe (& sup->up);";
+ s.op->newline(-1) << "unregistered_flag = -1;";
+ s.op->newline() << "#else";
+ // Uprobes lacks unmap_u[ret]probe. Before reusing sup, we must wait
+ // until uprobes turns loose of the u[ret]probe on its own, as indicated
+ // by uprobe.kdata = NULL.
+ s.op->newline() << "unregistered_flag = (sups->return_p ? -2 : -1);";
+ s.op->newline() << "#endif";
s.op->newline() << "mutex_lock (& stap_uprobes_lock);";
- // NB: We must not actually uregister u[ret]probes when a target process execs or exits;
- // uprobes does that by itself asynchronously. We can reuse the up/urp struct after
- // uprobes clears the sup->{up,urp}->kdata pointer. PR6829. To tell the two
- // cases apart, we use spec_index -2 vs -1.
- s.op->newline() << "sup->spec_index = (sups->return_p ? -2 : -1);";
+ s.op->newline() << "sup->spec_index = unregistered_flag;";
s.op->newline() << "mutex_unlock (& stap_uprobes_lock);";
s.op->newline() << "handled_p = 1;";
s.op->newline(-1) << "}"; // if slotted_p