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
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Fri, 18 Nov 2011 16:42:29 +0530
From:	Srikar Dronamraju <srikar@...ux.vnet.ibm.com>
To:	Peter Zijlstra <peterz@...radead.org>,
	Linus Torvalds <torvalds@...ux-foundation.org>
Cc:	Oleg Nesterov <oleg@...hat.com>,
	Andrew Morton <akpm@...ux-foundation.org>,
	LKML <linux-kernel@...r.kernel.org>,
	Linux-mm <linux-mm@...ck.org>, Ingo Molnar <mingo@...e.hu>,
	Andi Kleen <andi@...stfloor.org>,
	Christoph Hellwig <hch@...radead.org>,
	Steven Rostedt <rostedt@...dmis.org>,
	Roland McGrath <roland@...k.frob.com>,
	Thomas Gleixner <tglx@...utronix.de>,
	Masami Hiramatsu <masami.hiramatsu.pt@...achi.com>,
	Arnaldo Carvalho de Melo <acme@...radead.org>,
	Anton Arapov <anton@...hat.com>,
	Ananth N Mavinakayanahalli <ananth@...ibm.com>,
	Jim Keniston <jkenisto@...ux.vnet.ibm.com>,
	Stephen Wilson <wilsons@...rt.ca>
Subject: [PATCH v7 3.2-rc2 29/30] uprobes: Introduce uprobe flags


While registering a probe, there is a timelag between the time the register
request is given all probes are inserted in different processes. If the probe
register fails after inserting  a probe in couple of processes; the installed
probes are reverted. However the probes could have hit and triggered handler
before the probes are reverted.

Avoids running the handler until the register is complete or as soon as the
last unregister kicks in.

Also this patch
- enables skipping singlestep where possible.
- uses a flag to denote if a copy of instruction is made.

Signed-off-by: Srikar Dronamraju <srikar@...ux.vnet.ibm.com>
---
 include/linux/uprobes.h |   11 ++++++++++-
 kernel/uprobes.c        |   32 ++++++++++++++++++++++++++------
 2 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
index 6a84332..20bdd0a 100644
--- a/include/linux/uprobes.h
+++ b/include/linux/uprobes.h
@@ -46,6 +46,14 @@ struct uprobe_task_arch_info {};	/* arch specific task info */
 /* Adjust the return address of a call insn */
 #define UPROBES_FIX_CALL	0x2
 
+/* flags that denote/change uprobes behaviour */
+/* Have a copy of original instruction */
+#define UPROBES_COPY_INSN	0x1
+/* Dont run handlers when first register/ last unregister in progress*/
+#define UPROBES_RUN_HANDLER	0x2
+/* Can skip singlestep */
+#define UPROBES_SKIP_SSTEP	0x4
+
 struct uprobe_consumer {
 	int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs);
 	/*
@@ -66,7 +74,7 @@ struct uprobe {
 	struct uprobe_consumer	*consumers;
 	struct inode		*inode;		/* Also hold a ref to inode */
 	loff_t			offset;
-	int			copy;
+	int			flags;
 	u16			fixups;
 	u8			insn[MAX_UINSN_BYTES];
 };
@@ -131,6 +139,7 @@ extern int uprobe_post_notifier(struct pt_regs *regs);
 extern int uprobe_bkpt_notifier(struct pt_regs *regs);
 extern void uprobe_notify_resume(struct pt_regs *regs);
 extern bool uprobe_deny_signal(void);
+extern bool __weak can_skip_xol(struct pt_regs *regs, struct uprobe *u);
 #else /* CONFIG_UPROBES is not defined */
 static inline int register_uprobe(struct inode *inode, loff_t offset,
 				struct uprobe_consumer *consumer)
diff --git a/kernel/uprobes.c b/kernel/uprobes.c
index f8c0f7c..2493191 100644
--- a/kernel/uprobes.c
+++ b/kernel/uprobes.c
@@ -436,6 +436,9 @@ static struct uprobe *insert_uprobe(struct uprobe *uprobe)
 	spin_lock_irqsave(&uprobes_treelock, flags);
 	u = __insert_uprobe(uprobe);
 	spin_unlock_irqrestore(&uprobes_treelock, flags);
+
+	/* For now assume that the instruction need not be single-stepped */
+	uprobe->flags |= UPROBES_SKIP_SSTEP;
 	return u;
 }
 
@@ -475,6 +478,9 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
 {
 	struct uprobe_consumer *consumer;
 
+	if (!(uprobe->flags & UPROBES_RUN_HANDLER))
+		return;
+
 	down_read(&uprobe->consumer_rwsem);
 	consumer = uprobe->consumers;
 	for (consumer = uprobe->consumers; consumer;
@@ -594,7 +600,7 @@ static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe,
 		return -EEXIST;
 
 	addr = (unsigned long)vaddr;
-	if (!uprobe->copy) {
+	if (!(uprobe->flags & UPROBES_COPY_INSN)) {
 		ret = copy_insn(uprobe, vma, addr);
 		if (ret)
 			return ret;
@@ -606,7 +612,7 @@ static int install_breakpoint(struct mm_struct *mm, struct uprobe *uprobe,
 		if (ret)
 			return ret;
 
-		uprobe->copy = 1;
+		uprobe->flags |= UPROBES_COPY_INSN;
 	}
 	ret = set_bkpt(mm, uprobe, addr);
 	if (!ret)
@@ -850,7 +856,8 @@ int register_uprobe(struct inode *inode, loff_t offset,
 		if (ret) {
 			uprobe->consumers = NULL;
 			__unregister_uprobe(inode, offset, uprobe);
-		}
+		} else
+			uprobe->flags |= UPROBES_RUN_HANDLER;
 	}
 
 	mutex_unlock(uprobes_hash(inode));
@@ -886,9 +893,10 @@ void unregister_uprobe(struct inode *inode, loff_t offset,
 		goto unreg_out;
 	}
 
-	if (!uprobe->consumers)
+	if (!uprobe->consumers) {
 		__unregister_uprobe(inode, offset, uprobe);
-
+		uprobe->flags &= ~UPROBES_RUN_HANDLER;
+	}
 	mutex_unlock(uprobes_hash(inode));
 
 unreg_out:
@@ -1337,6 +1345,12 @@ bool uprobe_deny_signal(void)
 	return true;
 }
 
+bool __weak can_skip_xol(struct pt_regs *regs, struct uprobe *u)
+{
+	u->flags &= ~UPROBES_SKIP_SSTEP;
+	return false;
+}
+
 /*
  * uprobe_notify_resume gets called in task context just before returning
  * to userspace.
@@ -1378,6 +1392,10 @@ void uprobe_notify_resume(struct pt_regs *regs)
 		}
 		utask->active_uprobe = u;
 		handler_chain(u, regs);
+
+		if (u->flags & UPROBES_SKIP_SSTEP && can_skip_xol(regs, u))
+			goto cleanup_ret;
+
 		utask->state = UTASK_SSTEP;
 		if (!pre_ssout(u, regs, probept))
 			user_enable_single_step(current);
@@ -1411,8 +1429,10 @@ void uprobe_notify_resume(struct pt_regs *regs)
 		utask->state = UTASK_RUNNING;
 	}
 	if (u) {
+		if (!(u->flags & UPROBES_SKIP_SSTEP))
+			set_instruction_pointer(regs, probept);
+
 		put_uprobe(u);
-		set_instruction_pointer(regs, probept);
 	} else
 		send_sig(SIGTRAP, current, 0);
 }

--
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

Powered by Openwall GNU/*/Linux Powered by OpenVZ