Skip to contentSkip to conversation

kprobes: Prohibit probing on BUG() and WARN() address

PATCH In review Masami Hiramatsu 3 participants 3 messages Sep 3, 2019 – Sep 4, 2019 kprobes

lore
Share & tools
lore

Masami Hiramatsu

author maintainer
#0 lore raw

PATCH v2 1/1 kprobes: Prohibit probing on BUG() and WARN() address

Since BUG() and WARN() may use a trap (e.g. UD2 on x86) to get the address where the BUG() has occurred, kprobes can not do single-step out-of-line that instruction. So prohibit probing on such address.

Without this fix, if someone put a kprobe on WARN(), the kernel will crash with invalid opcode error instead of outputing warning message, because kernel can not find correct bug address.

---
Changes in v2:
- Add find_bug() stub function for !CONFIG_GENERIC_BUG
- Cast the p->addr to unsigned long.

---
 include/linux/bug.h |    5 +++++
 kernel/kprobes.c    |    3 ++-
 2 files changed, 7 insertions(+), 1 deletion(-)
include/linux/bug.h +5 -0
index fe5916550da8..f639bd0122f3 100644
@@ -47,6 +47,11 @@ void generic_bug_clear_once(void);
 
 #else	/* !CONFIG_GENERIC_BUG */
 
+static inline void *find_bug(unsigned long bugaddr)
+{
+	return NULL;
+}
+
 static inline enum bug_trap_type report_bug(unsigned long bug_addr,
 					    struct pt_regs *regs)
 {
kernel/kprobes.c +2 -1
index 452151e79535..5bdf47190f09 100644
@@ -1514,7 +1514,8 @@ static int check_kprobe_address_safe(struct kprobe *p,
 	/* Ensure it is not in reserved area nor out of text */
 	if (!kernel_text_address((unsigned long) p->addr) ||
 	    within_kprobe_blacklist((unsigned long) p->addr) ||
-	    jump_label_text_reserved(p->addr, p->addr)) {
+	    jump_label_text_reserved(p->addr, p->addr) ||
+	    find_bug((unsigned long) p->addr)) {
 		ret = -EINVAL;
 		goto out;
 	}
Acked-by on v2 1/1
#1 lore raw
Quoted 11 lines · Masami Hiramatsu

Since BUG() and WARN() may use a trap (e.g. UD2 on x86) to get the address where the BUG() has occurred, kprobes can not do single-step out-of-line that instruction. So prohibit probing on such address.

Without this fix, if someone put a kprobe on WARN(), the kernel will crash with invalid opcode error instead of outputing warning message, because kernel can not find correct bug address.

Quoted 8 lines

---
Changes in v2:
- Add find_bug() stub function for !CONFIG_GENERIC_BUG
- Cast the p->addr to unsigned long.

---
 include/linux/bug.h |    5 +++++
 kernel/kprobes.c    |    3 ++-
 2 files changed, 7 insertions(+), 1 deletion(-)

- Naveen

Acked-by on v2 1/1
#2 lore raw
In reply to Masami Hiramatsu
Quoted 11 lines · On Tue, 3 Sep 2019 20:08:21 +0900 Masami Hiramatsu <[email protected]> wrote:

Since BUG() and WARN() may use a trap (e.g. UD2 on x86) to get the address where the BUG() has occurred, kprobes can not do single-step out-of-line that instruction. So prohibit probing on such address.

Without this fix, if someone put a kprobe on WARN(), the kernel will crash with invalid opcode error instead of outputing warning message, because kernel can not find correct bug address.

-- Steve

Quoted 39 lines

---
Changes in v2:
- Add find_bug() stub function for !CONFIG_GENERIC_BUG
- Cast the p->addr to unsigned long.

---
 include/linux/bug.h |    5 +++++
 kernel/kprobes.c    |    3 ++-
 2 files changed, 7 insertions(+), 1 deletion(-)
include/linux/bug.h +5 -0
index fe5916550da8..f639bd0122f3 100644
@@ -47,6 +47,11 @@ void generic_bug_clear_once(void);
 
 #else	/* !CONFIG_GENERIC_BUG */
 
+static inline void *find_bug(unsigned long bugaddr)
+{
+	return NULL;
+}
+
 static inline enum bug_trap_type report_bug(unsigned long bug_addr,
 					    struct pt_regs *regs)
 {
kernel/kprobes.c +2 -1
index 452151e79535..5bdf47190f09 100644
@@ -1514,7 +1514,8 @@ static int check_kprobe_address_safe(struct kprobe *p,
 	/* Ensure it is not in reserved area nor out of text */
 	if (!kernel_text_address((unsigned long) p->addr) ||
 	    within_kprobe_blacklist((unsigned long) p->addr) ||
-	    jump_label_text_reserved(p->addr, p->addr)) {
+	    jump_label_text_reserved(p->addr, p->addr) ||
+	    find_bug((unsigned long) p->addr)) {
 		ret = -EINVAL;
 		goto out;
 	}