Skip to contentSkip to conversation

x86: kprobes: Prohibit kprobes on Xen/KVM emulate prefixes

PATCH Applied Masami Hiramatsu 3 participants 13 messages Sep 6, 2019 – Oct 18, 2019

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

v4 cover x86: kprobes: Prohibit kprobes on Xen/KVM emulate prefixes

Hi,

Here is the 4th version of patches to handle Xen/KVM emulate prefix by x86 instruction decoder.

These patches allow x86 instruction decoder to decode Xen and KVM emulate prefix correctly, and prohibit kprobes to probe on it.
Previous version is here;

https://lkml.kernel.org/r/156773433821.31441.2905951246664148487.stgit@devnote2

In this version, I added 2 patches, [1/4] fixes __ASM_FORM() to accept macros using __stringify(), [2/4] introduces new asm/emulate_prefix.h to initialize Xen and KVM emulate prefix at one place. [3/4] is updated to use new emulate_prefix.h and fix to add emulate_prefix.h to sync check list.

This series can be applied on -tip master branch which has merged Josh's objtool/perf sharing common x86 insn decoder series.

Thank you,

---

Masami Hiramatsu (4):
x86/asm: Allow to pass macros to __ASM_FORM()
x86: xen: kvm: Gather the definition of emulate prefixes
x86: xen: insn: Decode Xen and KVM emulate-prefix signature
x86: kprobes: Prohibit probing on instruction which has emulate prefix

 arch/x86/include/asm/asm.h                  |    8 ++++--
 arch/x86/include/asm/emulate_prefix.h       |   14 +++++++++++
 arch/x86/include/asm/insn.h                 |    6 +++++
 arch/x86/include/asm/xen/interface.h        |   11 +++------
 arch/x86/kernel/kprobes/core.c              |    4 +++
 arch/x86/kvm/x86.c                          |    4 ++-
 arch/x86/lib/insn.c                         |   34 +++++++++++++++++++++++++++
 tools/arch/x86/include/asm/emulate_prefix.h |   14 +++++++++++
 tools/arch/x86/include/asm/insn.h           |    6 +++++
 tools/arch/x86/lib/insn.c                   |   34 +++++++++++++++++++++++++++
 tools/objtool/sync-check.sh                 |    3 ++
 tools/perf/check-headers.sh                 |    3 ++
 12 files changed, 128 insertions(+), 13 deletions(-)
 create mode 100644 arch/x86/include/asm/emulate_prefix.h
 create mode 100644 tools/arch/x86/include/asm/emulate_prefix.h

--
Masami Hiramatsu (Linaro) <[email protected]>

#1 lore raw

PATCH v4 1/4 x86/asm: Allow to pass macros to __ASM_FORM()

Use __stringify() at __ASM_FORM() so that user can pass code including macros to __ASM_FORM().

---
 arch/x86/include/asm/asm.h |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
arch/x86/include/asm/asm.h +5 -3
index 3ff577c0b102..1b563f9167ea 100644
@@ -7,9 +7,11 @@
 # define __ASM_FORM_RAW(x)     x
 # define __ASM_FORM_COMMA(x) x,
 #else
-# define __ASM_FORM(x)	" " #x " "
-# define __ASM_FORM_RAW(x)     #x
-# define __ASM_FORM_COMMA(x) " " #x ","
+#include <linux/stringify.h>
+
+# define __ASM_FORM(x)	" " __stringify(x) " "
+# define __ASM_FORM_RAW(x)     __stringify(x)
+# define __ASM_FORM_COMMA(x) " " __stringify(x) ","
 #endif
 
 #ifndef __x86_64__
#2 lore raw

[tip: x86/core] x86/asm: Allow to pass macros to __ASM_FORM()

The following commit has been merged into the x86/core branch of tip:

The following commit has been merged into the x86/core branch of tip:

Commit-ID:     f7919fd943abf0c77aed4441ea9897a323d132f5
Gitweb:        https://git.kernel.org/tip/f7919fd943abf0c77aed4441ea9897a323d132f5
Author:        Masami Hiramatsu <[email protected]>
AuthorDate:    Fri, 06 Sep 2019 22:13:48 +09:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Thu, 17 Oct 2019 21:31:57 +02:00

x86/asm: Allow to pass macros to __ASM_FORM()

Use __stringify() at __ASM_FORM() so that user can pass code including macros to __ASM_FORM().

---
 arch/x86/include/asm/asm.h | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
arch/x86/include/asm/asm.h +5 -3
index 3ff577c..1b563f9 100644
@@ -7,9 +7,11 @@
 # define __ASM_FORM_RAW(x)     x
 # define __ASM_FORM_COMMA(x) x,
 #else
-# define __ASM_FORM(x)	" " #x " "
-# define __ASM_FORM_RAW(x)     #x
-# define __ASM_FORM_COMMA(x) " " #x ","
+#include <linux/stringify.h>
+
+# define __ASM_FORM(x)	" " __stringify(x) " "
+# define __ASM_FORM_RAW(x)     __stringify(x)
+# define __ASM_FORM_COMMA(x) " " __stringify(x) ","
 #endif
 
 #ifndef __x86_64__
#3 lore raw

PATCH v4 2/4 x86: xen: kvm: Gather the definition of emulate prefixes

In reply to Masami Hiramatsu

Gather the emulate prefixes, which forcibly make the following instruction emulated on virtualization, in one place.

---
 arch/x86/include/asm/emulate_prefix.h |   14 ++++++++++++++
 arch/x86/include/asm/xen/interface.h  |   11 ++++-------
 arch/x86/kvm/x86.c                    |    4 +++-
 3 files changed, 21 insertions(+), 8 deletions(-)
 create mode 100644 arch/x86/include/asm/emulate_prefix.h
arch/x86/include/asm/emulate_prefix.h new file +14 -0
new file mode 100644
index 000000000000..70f5b98a5286
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_EMULATE_PREFIX_H
+#define _ASM_X86_EMULATE_PREFIX_H
+
+/*
+ * Virt escape sequences to trigger instruction emulation;
+ * ideally these would decode to 'whole' instruction and not destroy
+ * the instruction stream; sadly this is not true for the 'kvm' one :/
+ */
+
+#define __XEN_EMULATE_PREFIX  0x0f,0x0b,0x78,0x65,0x6e  /* ud2 ; .ascii "xen" */
+#define __KVM_EMULATE_PREFIX  0x0f,0x0b,0x6b,0x76,0x6d	/* ud2 ; .ascii "kvm" */
+
+#endif
arch/x86/include/asm/xen/interface.h +4 -7
index 62ca03ef5c65..9139b3e86316 100644
@@ -379,12 +379,9 @@ struct xen_pmu_arch {
  * Prefix forces emulation of some non-trapping instructions.
  * Currently only CPUID.
  */
-#ifdef __ASSEMBLY__
-#define XEN_EMULATE_PREFIX .byte 0x0f,0x0b,0x78,0x65,0x6e ;
-#define XEN_CPUID          XEN_EMULATE_PREFIX cpuid
-#else
-#define XEN_EMULATE_PREFIX ".byte 0x0f,0x0b,0x78,0x65,0x6e ; "
-#define XEN_CPUID          XEN_EMULATE_PREFIX "cpuid"
-#endif
+#include <asm/emulate_prefix.h>
+
+#define XEN_EMULATE_PREFIX __ASM_FORM(.byte __XEN_EMULATE_PREFIX ;)
+#define XEN_CPUID          XEN_EMULATE_PREFIX __ASM_FORM(cpuid)
 
 #endif /* _ASM_X86_XEN_INTERFACE_H */
arch/x86/kvm/x86.c +3 -1
index 290c3c3efb87..5f8b0a60f48b 100644
@@ -68,6 +68,7 @@
 #include <asm/mshyperv.h>
 #include <asm/hypervisor.h>
 #include <asm/intel_pt.h>
+#include <asm/emulate_prefix.h>
 #include <clocksource/hyperv_timer.h>
 
 #define CREATE_TRACE_POINTS
@@ -5319,6 +5320,7 @@ EXPORT_SYMBOL_GPL(kvm_write_guest_virt_system);
 
 int handle_ud(struct kvm_vcpu *vcpu)
 {
+	static const char kvm_emulate_prefix[] = { __KVM_EMULATE_PREFIX };
 	int emul_type = EMULTYPE_TRAP_UD;
 	enum emulation_result er;
 	char sig[5]; /* ud2; .ascii "kvm" */
@@ -5327,7 +5329,7 @@ int handle_ud(struct kvm_vcpu *vcpu)
 	if (force_emulation_prefix &&
 	    kvm_read_guest_virt(vcpu, kvm_get_linear_rip(vcpu),
 				sig, sizeof(sig), &e) == 0 &&
-	    memcmp(sig, "\xf\xbkvm", sizeof(sig)) == 0) {
+	    memcmp(sig, kvm_emulate_prefix, sizeof(sig)) == 0) {
 		kvm_rip_write(vcpu, kvm_rip_read(vcpu) + sizeof(sig));
 		emul_type = 0;
 	}
#4 lore raw

[tip: x86/core] x86: xen: kvm: Gather the definition of emulate prefixes

The following commit has been merged into the x86/core branch of tip:

The following commit has been merged into the x86/core branch of tip:

Commit-ID:     b3dc0695fa40c3b280230fb6fb7fb7a94ce28bf4
Gitweb:        https://git.kernel.org/tip/b3dc0695fa40c3b280230fb6fb7fb7a94ce28bf4
Author:        Masami Hiramatsu <[email protected]>
AuthorDate:    Fri, 06 Sep 2019 22:13:59 +09:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Thu, 17 Oct 2019 21:31:57 +02:00

x86: xen: kvm: Gather the definition of emulate prefixes

Gather the emulate prefixes, which forcibly make the following instruction emulated on virtualization, in one place.

---
 arch/x86/include/asm/emulate_prefix.h | 14 ++++++++++++++
 arch/x86/include/asm/xen/interface.h  | 11 ++++-------
 arch/x86/kvm/x86.c                    |  4 +++-
 3 files changed, 21 insertions(+), 8 deletions(-)
 create mode 100644 arch/x86/include/asm/emulate_prefix.h
arch/x86/include/asm/emulate_prefix.h new file +14 -0
new file mode 100644
index 0000000..70f5b98
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_EMULATE_PREFIX_H
+#define _ASM_X86_EMULATE_PREFIX_H
+
+/*
+ * Virt escape sequences to trigger instruction emulation;
+ * ideally these would decode to 'whole' instruction and not destroy
+ * the instruction stream; sadly this is not true for the 'kvm' one :/
+ */
+
+#define __XEN_EMULATE_PREFIX  0x0f,0x0b,0x78,0x65,0x6e  /* ud2 ; .ascii "xen" */
+#define __KVM_EMULATE_PREFIX  0x0f,0x0b,0x6b,0x76,0x6d	/* ud2 ; .ascii "kvm" */
+
+#endif
arch/x86/include/asm/xen/interface.h +4 -7
index 62ca03e..9139b3e 100644
@@ -379,12 +379,9 @@ struct xen_pmu_arch {
  * Prefix forces emulation of some non-trapping instructions.
  * Currently only CPUID.
  */
-#ifdef __ASSEMBLY__
-#define XEN_EMULATE_PREFIX .byte 0x0f,0x0b,0x78,0x65,0x6e ;
-#define XEN_CPUID          XEN_EMULATE_PREFIX cpuid
-#else
-#define XEN_EMULATE_PREFIX ".byte 0x0f,0x0b,0x78,0x65,0x6e ; "
-#define XEN_CPUID          XEN_EMULATE_PREFIX "cpuid"
-#endif
+#include <asm/emulate_prefix.h>
+
+#define XEN_EMULATE_PREFIX __ASM_FORM(.byte __XEN_EMULATE_PREFIX ;)
+#define XEN_CPUID          XEN_EMULATE_PREFIX __ASM_FORM(cpuid)
 
 #endif /* _ASM_X86_XEN_INTERFACE_H */
arch/x86/kvm/x86.c +3 -1
index 661e2bf..777574f 100644
@@ -68,6 +68,7 @@
 #include <asm/mshyperv.h>
 #include <asm/hypervisor.h>
 #include <asm/intel_pt.h>
+#include <asm/emulate_prefix.h>
 #include <clocksource/hyperv_timer.h>
 
 #define CREATE_TRACE_POINTS
@@ -5446,6 +5447,7 @@ EXPORT_SYMBOL_GPL(kvm_write_guest_virt_system);
 
 int handle_ud(struct kvm_vcpu *vcpu)
 {
+	static const char kvm_emulate_prefix[] = { __KVM_EMULATE_PREFIX };
 	int emul_type = EMULTYPE_TRAP_UD;
 	char sig[5]; /* ud2; .ascii "kvm" */
 	struct x86_exception e;
@@ -5453,7 +5455,7 @@ int handle_ud(struct kvm_vcpu *vcpu)
 	if (force_emulation_prefix &&
 	    kvm_read_guest_virt(vcpu, kvm_get_linear_rip(vcpu),
 				sig, sizeof(sig), &e) == 0 &&
-	    memcmp(sig, "\xf\xbkvm", sizeof(sig)) == 0) {
+	    memcmp(sig, kvm_emulate_prefix, sizeof(sig)) == 0) {
 		kvm_rip_write(vcpu, kvm_rip_read(vcpu) + sizeof(sig));
 		emul_type = EMULTYPE_TRAP_UD_FORCED;
 	}
#5 lore raw

PATCH v4 3/4 x86: xen: insn: Decode Xen and KVM emulate-prefix signature

In reply to Masami Hiramatsu

Decode Xen and KVM's emulate-prefix signature by x86 insn decoder. It is called "prefix" but actually not x86 instruction prefix, so this adds insn.emulate_prefix_size field instead of reusing insn.prefixes.

If x86 decoder finds a special sequence of instructions of XEN_EMULATE_PREFIX and 'ud2a; .ascii "kvm"', it just counts the length, set insn.emulate_prefix_size and fold it with the next instruction. In other words, the signature and the next instruction is treated as a single instruction.

---
Changes in v4:
- Use asm/emulate_prefix.h instead of xen/prefix.h
- Fix to add emulate_prefix.h to the checkist of perf.

---
 arch/x86/include/asm/insn.h                 |    6 +++++
 arch/x86/lib/insn.c                         |   34 +++++++++++++++++++++++++++
 tools/arch/x86/include/asm/emulate_prefix.h |   14 +++++++++++
 tools/arch/x86/include/asm/insn.h           |    6 +++++
 tools/arch/x86/lib/insn.c                   |   34 +++++++++++++++++++++++++++
 tools/objtool/sync-check.sh                 |    3 ++
 tools/perf/check-headers.sh                 |    3 ++
 7 files changed, 98 insertions(+), 2 deletions(-)
 create mode 100644 tools/arch/x86/include/asm/emulate_prefix.h
arch/x86/include/asm/insn.h +6 -0
index 154f27be8bfc..5c1ae3eff9d4 100644
@@ -45,6 +45,7 @@ struct insn {
 		struct insn_field immediate2;	/* for 64bit imm or seg16 */
 	};
 
+	int	emulate_prefix_size;
 	insn_attr_t attr;
 	unsigned char opnd_bytes;
 	unsigned char addr_bytes;
@@ -128,6 +129,11 @@ static inline int insn_is_evex(struct insn *insn)
 	return (insn->vex_prefix.nbytes == 4);
 }
 
+static inline int insn_has_emulate_prefix(struct insn *insn)
+{
+	return !!insn->emulate_prefix_size;
+}
+
 /* Ensure this instruction is decoded completely */
 static inline int insn_complete(struct insn *insn)
 {
arch/x86/lib/insn.c +34 -0
index 0b5862ba6a75..404279563891 100644
@@ -13,6 +13,8 @@
 #include <asm/inat.h>
 #include <asm/insn.h>
 
+#include <asm/emulate_prefix.h>
+
 /* Verify next sizeof(t) bytes can be on the same instruction */
 #define validate_next(t, insn, n)	\
 	((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr)
@@ -58,6 +60,36 @@ void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64)
 		insn->addr_bytes = 4;
 }
 
+static const insn_byte_t xen_prefix[] = { __XEN_EMULATE_PREFIX };
+static const insn_byte_t kvm_prefix[] = { __KVM_EMULATE_PREFIX };
+
+static int __insn_get_emulate_prefix(struct insn *insn,
+				     const insn_byte_t *prefix, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++) {
+		if (peek_nbyte_next(insn_byte_t, insn, i) != prefix[i])
+			goto err_out;
+	}
+
+	insn->emulate_prefix_size = len;
+	insn->next_byte += len;
+
+	return 1;
+
+err_out:
+	return 0;
+}
+
+static void insn_get_emulate_prefix(struct insn *insn)
+{
+	if (__insn_get_emulate_prefix(insn, xen_prefix, sizeof(xen_prefix)))
+		return;
+
+	__insn_get_emulate_prefix(insn, kvm_prefix, sizeof(kvm_prefix));
+}
+
 /**
  * insn_get_prefixes - scan x86 instruction prefix bytes
  * @insn:	&struct insn containing instruction
@@ -76,6 +108,8 @@ void insn_get_prefixes(struct insn *insn)
 	if (prefixes->got)
 		return;
 
+	insn_get_emulate_prefix(insn);
+
 	nb = 0;
 	lb = 0;
 	b = peek_next(insn_byte_t, insn);
tools/arch/x86/include/asm/emulate_prefix.h new file +14 -0
new file mode 100644
index 000000000000..70f5b98a5286
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_EMULATE_PREFIX_H
+#define _ASM_X86_EMULATE_PREFIX_H
+
+/*
+ * Virt escape sequences to trigger instruction emulation;
+ * ideally these would decode to 'whole' instruction and not destroy
+ * the instruction stream; sadly this is not true for the 'kvm' one :/
+ */
+
+#define __XEN_EMULATE_PREFIX  0x0f,0x0b,0x78,0x65,0x6e  /* ud2 ; .ascii "xen" */
+#define __KVM_EMULATE_PREFIX  0x0f,0x0b,0x6b,0x76,0x6d	/* ud2 ; .ascii "kvm" */
+
+#endif
tools/arch/x86/include/asm/insn.h +6 -0
index 37a4c390750b..568854b14d0a 100644
@@ -45,6 +45,7 @@ struct insn {
 		struct insn_field immediate2;	/* for 64bit imm or seg16 */
 	};
 
+	int	emulate_prefix_size;
 	insn_attr_t attr;
 	unsigned char opnd_bytes;
 	unsigned char addr_bytes;
@@ -128,6 +129,11 @@ static inline int insn_is_evex(struct insn *insn)
 	return (insn->vex_prefix.nbytes == 4);
 }
 
+static inline int insn_has_emulate_prefix(struct insn *insn)
+{
+	return !!insn->emulate_prefix_size;
+}
+
 /* Ensure this instruction is decoded completely */
 static inline int insn_complete(struct insn *insn)
 {
tools/arch/x86/lib/insn.c +34 -0
index 79e048f1d902..0151dfc6da61 100644
@@ -13,6 +13,8 @@
 #include "../include/asm/inat.h"
 #include "../include/asm/insn.h"
 
+#include "../include/asm/emulate_prefix.h"
+
 /* Verify next sizeof(t) bytes can be on the same instruction */
 #define validate_next(t, insn, n)	\
 	((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr)
@@ -58,6 +60,36 @@ void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64)
 		insn->addr_bytes = 4;
 }
 
+static const insn_byte_t xen_prefix[] = { __XEN_EMULATE_PREFIX };
+static const insn_byte_t kvm_prefix[] = { __KVM_EMULATE_PREFIX };
+
+static int __insn_get_emulate_prefix(struct insn *insn,
+				     const insn_byte_t *prefix, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++) {
+		if (peek_nbyte_next(insn_byte_t, insn, i) != prefix[i])
+			goto err_out;
+	}
+
+	insn->emulate_prefix_size = len;
+	insn->next_byte += len;
+
+	return 1;
+
+err_out:
+	return 0;
+}
+
+static void insn_get_emulate_prefix(struct insn *insn)
+{
+	if (__insn_get_emulate_prefix(insn, xen_prefix, sizeof(xen_prefix)))
+		return;
+
+	__insn_get_emulate_prefix(insn, kvm_prefix, sizeof(kvm_prefix));
+}
+
 /**
  * insn_get_prefixes - scan x86 instruction prefix bytes
  * @insn:	&struct insn containing instruction
@@ -76,6 +108,8 @@ void insn_get_prefixes(struct insn *insn)
 	if (prefixes->got)
 		return;
 
+	insn_get_emulate_prefix(insn);
+
 	nb = 0;
 	lb = 0;
 	b = peek_next(insn_byte_t, insn);
tools/objtool/sync-check.sh +2 -1
index 0a832e265a50..9bd04bbed01e 100755
@@ -4,6 +4,7 @@
 FILES='
 arch/x86/include/asm/inat_types.h
 arch/x86/include/asm/orc_types.h
+arch/x86/include/asm/emulate_prefix.h
 arch/x86/lib/x86-opcode-map.txt
 arch/x86/tools/gen-insn-attr-x86.awk
 '
@@ -46,6 +47,6 @@ done
 check arch/x86/include/asm/inat.h     '-I "^#include [\"<]\(asm/\)*inat_types.h[\">]"'
 check arch/x86/include/asm/insn.h     '-I "^#include [\"<]\(asm/\)*inat.h[\">]"'
 check arch/x86/lib/inat.c             '-I "^#include [\"<]\(../include/\)*asm/insn.h[\">]"'
-check arch/x86/lib/insn.c             '-I "^#include [\"<]\(../include/\)*asm/in\(at\|sn\).h[\">]"'
+check arch/x86/lib/insn.c             '-I "^#include [\"<]\(../include/\)*asm/in\(at\|sn\).h[\">]" -I "^#include [\"<]\(../include/\)*asm/emulate_prefix.h[\">]"'
 
 cd -
tools/perf/check-headers.sh +2 -1
index e2e0f06c97d0..988b1879ec98 100755
@@ -27,6 +27,7 @@ arch/x86/include/asm/disabled-features.h
 arch/x86/include/asm/required-features.h
 arch/x86/include/asm/cpufeatures.h
 arch/x86/include/asm/inat_types.h
+arch/x86/include/asm/emulate_prefix.h
 arch/x86/include/uapi/asm/prctl.h
 arch/x86/lib/x86-opcode-map.txt
 arch/x86/tools/gen-insn-attr-x86.awk
@@ -115,7 +116,7 @@ check lib/ctype.c		      '-I "^EXPORT_SYMBOL" -I "^#include <linux/export.h>" -B
 check arch/x86/include/asm/inat.h     '-I "^#include [\"<]\(asm/\)*inat_types.h[\">]"'
 check arch/x86/include/asm/insn.h     '-I "^#include [\"<]\(asm/\)*inat.h[\">]"'
 check arch/x86/lib/inat.c	      '-I "^#include [\"<]\(../include/\)*asm/insn.h[\">]"'
-check arch/x86/lib/insn.c	      '-I "^#include [\"<]\(../include/\)*asm/in\(at\|sn\).h[\">]"'
+check arch/x86/lib/insn.c             '-I "^#include [\"<]\(../include/\)*asm/in\(at\|sn\).h[\">]" -I "^#include [\"<]\(../include/\)*asm/emulate_prefix.h[\">]"'
 
 # diff non-symmetric files
 check_2 tools/perf/arch/x86/entry/syscalls/syscall_64.tbl arch/x86/entry/syscalls/syscall_64.tbl
#6 lore raw

[tip: x86/core] x86: xen: insn: Decode Xen and KVM emulate-prefix signature

The following commit has been merged into the x86/core branch of tip:

The following commit has been merged into the x86/core branch of tip:

Commit-ID:     4d65adfcd1196818659d3bd9b42dccab291e1751
Gitweb:        https://git.kernel.org/tip/4d65adfcd1196818659d3bd9b42dccab291e1751
Author:        Masami Hiramatsu <[email protected]>
AuthorDate:    Fri, 06 Sep 2019 22:14:10 +09:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Thu, 17 Oct 2019 21:31:57 +02:00

x86: xen: insn: Decode Xen and KVM emulate-prefix signature

Decode Xen and KVM's emulate-prefix signature by x86 insn decoder. It is called "prefix" but actually not x86 instruction prefix, so this adds insn.emulate_prefix_size field instead of reusing insn.prefixes.

If x86 decoder finds a special sequence of instructions of XEN_EMULATE_PREFIX and 'ud2a; .ascii "kvm"', it just counts the length, set insn.emulate_prefix_size and fold it with the next instruction. In other words, the signature and the next instruction is treated as a single instruction.

---
 arch/x86/include/asm/insn.h                 |  6 ++++-
 arch/x86/lib/insn.c                         | 34 ++++++++++++++++++++-
 tools/arch/x86/include/asm/emulate_prefix.h | 14 ++++++++-
 tools/arch/x86/include/asm/insn.h           |  6 ++++-
 tools/arch/x86/lib/insn.c                   | 34 ++++++++++++++++++++-
 tools/objtool/sync-check.sh                 |  3 +-
 tools/perf/check-headers.sh                 |  3 +-
 7 files changed, 98 insertions(+), 2 deletions(-)
 create mode 100644 tools/arch/x86/include/asm/emulate_prefix.h
arch/x86/include/asm/insn.h +6 -0
index 154f27b..5c1ae3e 100644
@@ -45,6 +45,7 @@ struct insn {
 		struct insn_field immediate2;	/* for 64bit imm or seg16 */
 	};
 
+	int	emulate_prefix_size;
 	insn_attr_t attr;
 	unsigned char opnd_bytes;
 	unsigned char addr_bytes;
@@ -128,6 +129,11 @@ static inline int insn_is_evex(struct insn *insn)
 	return (insn->vex_prefix.nbytes == 4);
 }
 
+static inline int insn_has_emulate_prefix(struct insn *insn)
+{
+	return !!insn->emulate_prefix_size;
+}
+
 /* Ensure this instruction is decoded completely */
 static inline int insn_complete(struct insn *insn)
 {
arch/x86/lib/insn.c +34 -0
index 0b5862b..4042795 100644
@@ -13,6 +13,8 @@
 #include <asm/inat.h>
 #include <asm/insn.h>
 
+#include <asm/emulate_prefix.h>
+
 /* Verify next sizeof(t) bytes can be on the same instruction */
 #define validate_next(t, insn, n)	\
 	((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr)
@@ -58,6 +60,36 @@ void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64)
 		insn->addr_bytes = 4;
 }
 
+static const insn_byte_t xen_prefix[] = { __XEN_EMULATE_PREFIX };
+static const insn_byte_t kvm_prefix[] = { __KVM_EMULATE_PREFIX };
+
+static int __insn_get_emulate_prefix(struct insn *insn,
+				     const insn_byte_t *prefix, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++) {
+		if (peek_nbyte_next(insn_byte_t, insn, i) != prefix[i])
+			goto err_out;
+	}
+
+	insn->emulate_prefix_size = len;
+	insn->next_byte += len;
+
+	return 1;
+
+err_out:
+	return 0;
+}
+
+static void insn_get_emulate_prefix(struct insn *insn)
+{
+	if (__insn_get_emulate_prefix(insn, xen_prefix, sizeof(xen_prefix)))
+		return;
+
+	__insn_get_emulate_prefix(insn, kvm_prefix, sizeof(kvm_prefix));
+}
+
 /**
  * insn_get_prefixes - scan x86 instruction prefix bytes
  * @insn:	&struct insn containing instruction
@@ -76,6 +108,8 @@ void insn_get_prefixes(struct insn *insn)
 	if (prefixes->got)
 		return;
 
+	insn_get_emulate_prefix(insn);
+
 	nb = 0;
 	lb = 0;
 	b = peek_next(insn_byte_t, insn);
tools/arch/x86/include/asm/emulate_prefix.h new file +14 -0
new file mode 100644
index 0000000..70f5b98
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_EMULATE_PREFIX_H
+#define _ASM_X86_EMULATE_PREFIX_H
+
+/*
+ * Virt escape sequences to trigger instruction emulation;
+ * ideally these would decode to 'whole' instruction and not destroy
+ * the instruction stream; sadly this is not true for the 'kvm' one :/
+ */
+
+#define __XEN_EMULATE_PREFIX  0x0f,0x0b,0x78,0x65,0x6e  /* ud2 ; .ascii "xen" */
+#define __KVM_EMULATE_PREFIX  0x0f,0x0b,0x6b,0x76,0x6d	/* ud2 ; .ascii "kvm" */
+
+#endif
tools/arch/x86/include/asm/insn.h +6 -0
index 37a4c39..568854b 100644
@@ -45,6 +45,7 @@ struct insn {
 		struct insn_field immediate2;	/* for 64bit imm or seg16 */
 	};
 
+	int	emulate_prefix_size;
 	insn_attr_t attr;
 	unsigned char opnd_bytes;
 	unsigned char addr_bytes;
@@ -128,6 +129,11 @@ static inline int insn_is_evex(struct insn *insn)
 	return (insn->vex_prefix.nbytes == 4);
 }
 
+static inline int insn_has_emulate_prefix(struct insn *insn)
+{
+	return !!insn->emulate_prefix_size;
+}
+
 /* Ensure this instruction is decoded completely */
 static inline int insn_complete(struct insn *insn)
 {
tools/arch/x86/lib/insn.c +34 -0
index 79e048f..0151dfc 100644
@@ -13,6 +13,8 @@
 #include "../include/asm/inat.h"
 #include "../include/asm/insn.h"
 
+#include "../include/asm/emulate_prefix.h"
+
 /* Verify next sizeof(t) bytes can be on the same instruction */
 #define validate_next(t, insn, n)	\
 	((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr)
@@ -58,6 +60,36 @@ void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64)
 		insn->addr_bytes = 4;
 }
 
+static const insn_byte_t xen_prefix[] = { __XEN_EMULATE_PREFIX };
+static const insn_byte_t kvm_prefix[] = { __KVM_EMULATE_PREFIX };
+
+static int __insn_get_emulate_prefix(struct insn *insn,
+				     const insn_byte_t *prefix, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++) {
+		if (peek_nbyte_next(insn_byte_t, insn, i) != prefix[i])
+			goto err_out;
+	}
+
+	insn->emulate_prefix_size = len;
+	insn->next_byte += len;
+
+	return 1;
+
+err_out:
+	return 0;
+}
+
+static void insn_get_emulate_prefix(struct insn *insn)
+{
+	if (__insn_get_emulate_prefix(insn, xen_prefix, sizeof(xen_prefix)))
+		return;
+
+	__insn_get_emulate_prefix(insn, kvm_prefix, sizeof(kvm_prefix));
+}
+
 /**
  * insn_get_prefixes - scan x86 instruction prefix bytes
  * @insn:	&struct insn containing instruction
@@ -76,6 +108,8 @@ void insn_get_prefixes(struct insn *insn)
 	if (prefixes->got)
 		return;
 
+	insn_get_emulate_prefix(insn);
+
 	nb = 0;
 	lb = 0;
 	b = peek_next(insn_byte_t, insn);
tools/objtool/sync-check.sh +2 -1
index 0a832e2..9bd04bb 100755
@@ -4,6 +4,7 @@
 FILES='
 arch/x86/include/asm/inat_types.h
 arch/x86/include/asm/orc_types.h
+arch/x86/include/asm/emulate_prefix.h
 arch/x86/lib/x86-opcode-map.txt
 arch/x86/tools/gen-insn-attr-x86.awk
 '
@@ -46,6 +47,6 @@ done
 check arch/x86/include/asm/inat.h     '-I "^#include [\"<]\(asm/\)*inat_types.h[\">]"'
 check arch/x86/include/asm/insn.h     '-I "^#include [\"<]\(asm/\)*inat.h[\">]"'
 check arch/x86/lib/inat.c             '-I "^#include [\"<]\(../include/\)*asm/insn.h[\">]"'
-check arch/x86/lib/insn.c             '-I "^#include [\"<]\(../include/\)*asm/in\(at\|sn\).h[\">]"'
+check arch/x86/lib/insn.c             '-I "^#include [\"<]\(../include/\)*asm/in\(at\|sn\).h[\">]" -I "^#include [\"<]\(../include/\)*asm/emulate_prefix.h[\">]"'
 
 cd -
tools/perf/check-headers.sh +2 -1
index cea13cb..499235a 100755
@@ -28,6 +28,7 @@ arch/x86/include/asm/disabled-features.h
 arch/x86/include/asm/required-features.h
 arch/x86/include/asm/cpufeatures.h
 arch/x86/include/asm/inat_types.h
+arch/x86/include/asm/emulate_prefix.h
 arch/x86/include/uapi/asm/prctl.h
 arch/x86/lib/x86-opcode-map.txt
 arch/x86/tools/gen-insn-attr-x86.awk
@@ -116,7 +117,7 @@ check lib/ctype.c		      '-I "^EXPORT_SYMBOL" -I "^#include <linux/export.h>" -B
 check arch/x86/include/asm/inat.h     '-I "^#include [\"<]\(asm/\)*inat_types.h[\">]"'
 check arch/x86/include/asm/insn.h     '-I "^#include [\"<]\(asm/\)*inat.h[\">]"'
 check arch/x86/lib/inat.c	      '-I "^#include [\"<]\(../include/\)*asm/insn.h[\">]"'
-check arch/x86/lib/insn.c	      '-I "^#include [\"<]\(../include/\)*asm/in\(at\|sn\).h[\">]"'
+check arch/x86/lib/insn.c             '-I "^#include [\"<]\(../include/\)*asm/in\(at\|sn\).h[\">]" -I "^#include [\"<]\(../include/\)*asm/emulate_prefix.h[\">]"'
 
 # diff non-symmetric files
 check_2 tools/perf/arch/x86/entry/syscalls/syscall_64.tbl arch/x86/entry/syscalls/syscall_64.tbl
#7 lore raw

PATCH v4 4/4 x86: kprobes: Prohibit probing on instruction which has emulate prefix

In reply to Masami Hiramatsu

Prohibit probing on instruction which has XEN_EMULATE_PREFIX or KVM's emulate prefix. Since that prefix is a marker for Xen and KVM, if we modify the marker by kprobe's int3, that doesn't work as expected.

---
 arch/x86/kernel/kprobes/core.c |    4 ++++
 1 file changed, 4 insertions(+)
arch/x86/kernel/kprobes/core.c +4 -0
index 43fc13c831af..4f13af7cbcdb 100644
@@ -351,6 +351,10 @@ int __copy_instruction(u8 *dest, u8 *src, u8 *real, struct insn *insn)
 	kernel_insn_init(insn, dest, MAX_INSN_SIZE);
 	insn_get_length(insn);
 
+	/* We can not probe force emulate prefixed instruction */
+	if (insn_has_emulate_prefix(insn))
+		return 0;
+
 	/* Another subsystem puts a breakpoint, failed to recover */
 	if (insn->opcode.bytes[0] == BREAKPOINT_INSTRUCTION)
 		return 0;
#8 lore raw

[tip: x86/core] x86: kprobes: Prohibit probing on instruction which has emulate prefix

The following commit has been merged into the x86/core branch of tip:

The following commit has been merged into the x86/core branch of tip:

Commit-ID:     004e8dce9c5595697951f7cd0e9f66b35c92265e
Gitweb:        https://git.kernel.org/tip/004e8dce9c5595697951f7cd0e9f66b35c92265e
Author:        Masami Hiramatsu <[email protected]>
AuthorDate:    Fri, 06 Sep 2019 22:14:20 +09:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Thu, 17 Oct 2019 21:31:57 +02:00

x86: kprobes: Prohibit probing on instruction which has emulate prefix

Prohibit probing on instruction which has XEN_EMULATE_PREFIX or KVM's emulate prefix. Since that prefix is a marker for Xen and KVM, if we modify the marker by kprobe's int3, that doesn't work as expected.

---
 arch/x86/kernel/kprobes/core.c | 4 ++++
 1 file changed, 4 insertions(+)
arch/x86/kernel/kprobes/core.c +4 -0
index 43fc13c..4f13af7 100644
@@ -351,6 +351,10 @@ int __copy_instruction(u8 *dest, u8 *src, u8 *real, struct insn *insn)
 	kernel_insn_init(insn, dest, MAX_INSN_SIZE);
 	insn_get_length(insn);
 
+	/* We can not probe force emulate prefixed instruction */
+	if (insn_has_emulate_prefix(insn))
+		return 0;
+
 	/* Another subsystem puts a breakpoint, failed to recover */
 	if (insn->opcode.bytes[0] == BREAKPOINT_INSTRUCTION)
 		return 0;
#9 lore raw
In reply to Masami Hiramatsu

Hi Peter,

Could you review this version?

Thank you,

Quoted 51 lines · On Fri, 6 Sep 2019 22:13:37 +0900 Masami Hiramatsu <[email protected]> wrote:

Hi,

Here is the 4th version of patches to handle Xen/KVM emulate prefix by x86 instruction decoder.

These patches allow x86 instruction decoder to decode Xen and KVM emulate prefix correctly, and prohibit kprobes to probe on it.
Previous version is here;

https://lkml.kernel.org/r/156773433821.31441.2905951246664148487.stgit@devnote2

In this version, I added 2 patches, [1/4] fixes __ASM_FORM() to accept macros using __stringify(), [2/4] introduces new asm/emulate_prefix.h to initialize Xen and KVM emulate prefix at one place. [3/4] is updated to use new emulate_prefix.h and fix to add emulate_prefix.h to sync check list.

This series can be applied on -tip master branch which has merged Josh's objtool/perf sharing common x86 insn decoder series.

Thank you,

---

Masami Hiramatsu (4):
x86/asm: Allow to pass macros to __ASM_FORM()
x86: xen: kvm: Gather the definition of emulate prefixes
x86: xen: insn: Decode Xen and KVM emulate-prefix signature
x86: kprobes: Prohibit probing on instruction which has emulate prefix

 arch/x86/include/asm/asm.h                  |    8 ++++--
 arch/x86/include/asm/emulate_prefix.h       |   14 +++++++++++
 arch/x86/include/asm/insn.h                 |    6 +++++
 arch/x86/include/asm/xen/interface.h        |   11 +++------
 arch/x86/kernel/kprobes/core.c              |    4 +++
 arch/x86/kvm/x86.c                          |    4 ++-
 arch/x86/lib/insn.c                         |   34 +++++++++++++++++++++++++++
 tools/arch/x86/include/asm/emulate_prefix.h |   14 +++++++++++
 tools/arch/x86/include/asm/insn.h           |    6 +++++
 tools/arch/x86/lib/insn.c                   |   34 +++++++++++++++++++++++++++
 tools/objtool/sync-check.sh                 |    3 ++
 tools/perf/check-headers.sh                 |    3 ++
 12 files changed, 128 insertions(+), 13 deletions(-)
 create mode 100644 arch/x86/include/asm/emulate_prefix.h
 create mode 100644 tools/arch/x86/include/asm/emulate_prefix.h

--
Masami Hiramatsu (Linaro) <[email protected]>

Signature · 1 line
Masami Hiramatsu <[email protected]>
maintainer
#10 lore raw
Quoted 3 lines · Masami Hiramatsu

Hi Peter,

Could you review this version?

These look good to me; shall I merge them or what was the plan?

#11 lore raw

Hi Peter,

Quoted 6 lines · On Wed, 9 Oct 2019 14:31:06 +0200 Peter Zijlstra <[email protected]> wrote:
Quoted 3 lines · Masami Hiramatsu

Hi Peter,

Could you review this version?

These look good to me; shall I merge them or what was the plan?

Thanks for the review, yes, could you merge this series to support emulated prefixes correctly?

Thank you,

Signature · 1 line
Masami Hiramatsu <[email protected]>
maintainer
#12 lore raw
Quoted 5 lines · Masami Hiramatsu

Hi Peter,

On Wed, 9 Oct 2019 14:31:06 +0200
Peter Zijlstra <[email protected]> wrote:

Quoted 8 lines
Quoted 6 lines · Masami Hiramatsu
Quoted 3 lines

Hi Peter,

Could you review this version?

These look good to me; shall I merge them or what was the plan?

Thanks for the review, yes, could you merge this series to support emulated prefixes correctly?

OK, I'll get them merged.