kprobes/x86: retpoline: Fix kprobes for retpoline
Subsystems (3)
v2 cover kprobes/x86: retpoline: Fix kprobes for retpoline
Hi,
This is the 2nd version of the series to fix kprobes issues on the kernel with CONFIG_RETPOLINE=y.
- [1/3]: This introduces __x86_indirect_thunk_* boundary symbols so that kprobes easily identify those functions.
- [2/3]: Mark __x86_indirect_thunk_* as blacklisted function for kprobes, since it can be called from other blacklisted functions.
- [3/3]: Check jmp instructions in the probe target function whether it jumps into the __x86_indirect_thunk_*, because it is equal to an indirect jump instruction.
In this version, just [1/3] has been changed according to David Woodhouse's comment.
[1/3]: Consolidate .text.__x86.indirect_thunk.* sections
to .text.__x86.indirect_thunk section.
Thank you,
---
Masami Hiramatsu (3):
retpoline: Introduce start/end markers of indirect thunk kprobes/x86: Blacklist indirect thunk functions for kprobes kprobes/x86: Disable optimizing on the function jumps to indirect thunk
arch/x86/include/asm/nospec-branch.h | 3 +++ arch/x86/kernel/kprobes/opt.c | 23 ++++++++++++++++++++++- arch/x86/kernel/vmlinux.lds.S | 6 ++++++ arch/x86/lib/retpoline.S | 5 +++-- 4 files changed, 34 insertions(+), 3 deletions(-)
--
Masami Hiramatsu (Linaro) <[email protected]>
PATCH v2 1/3 retpoline: Introduce start/end markers of indirect thunk
Introduce start/end markers of __x86_indirect_thunk_* functions. To make it easy, consolidate .text.__x86.indirect_thunk.* sections to one .text.__x86.indirect_thunk section and put it in the end of kernel text section and adds __indirect_thunk_start/end so that other subsystem (e.g. kprobes) can identify it.
---
Changes in v2:
- Consolidate .text.__x86.indirect_thunk.* sections to one .text.__x86.indirect_thunk section. (Thanks David!)
--- arch/x86/include/asm/nospec-branch.h | 3 +++ arch/x86/kernel/vmlinux.lds.S | 6 ++++++ arch/x86/lib/retpoline.S | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-)
arch/x86/include/asm/nospec-branch.h +3 -0
@@ -194,6 +194,9 @@ enum spectre_v2_mitigation { SPECTRE_V2_IBRS, }; +extern char __indirect_thunk_start[]; +extern char __indirect_thunk_end[]; +/* * On VMEXIT we must ensure that no RSB predictions learned in the guest * can be followed in the host, by overwriting the RSB completely. Both
arch/x86/kernel/vmlinux.lds.S +6 -0
@@ -124,6 +124,12 @@ SECTIONS ASSERT(. - _entry_trampoline == PAGE_SIZE, "entry trampoline is too big"); #endif +#ifdef CONFIG_RETPOLINE + __indirect_thunk_start = .; + *(.text.__x86.indirect_thunk) + __indirect_thunk_end = .; +#endif + /* End of text section */ _etext = .; } :text = 0x9090
arch/x86/lib/retpoline.S +1 -1
@@ -9,7 +9,7 @@ #include <asm/nospec-branch.h> .macro THUNK reg - .section .text.__x86.indirect_thunk.\reg + .section .text.__x86.indirect_thunk ENTRY(__x86_indirect_thunk_\reg) CFI_STARTPROC
tip-bot for Masami Hiramatsu
merge bot[tip:x86/pti] retpoline: Introduce start/end markers of indirect thunk
retpoline: Introduce start/end markers of indirect thunk
Commit-ID: 736e80a4213e9bbce40a7c050337047128b472ac Gitweb: https://git.kernel.org/tip/736e80a4213e9bbce40a7c050337047128b472ac Author: Masami Hiramatsu <[email protected]> AuthorDate: Fri, 19 Jan 2018 01:14:21 +0900 Committer: Thomas Gleixner <[email protected]> CommitDate: Fri, 19 Jan 2018 16:31:28 +0100
retpoline: Introduce start/end markers of indirect thunk
Introduce start/end markers of __x86_indirect_thunk_* functions. To make it easy, consolidate .text.__x86.indirect_thunk.* sections to one .text.__x86.indirect_thunk section and put it in the end of kernel text section and adds __indirect_thunk_start/end so that other subsystem (e.g. kprobes) can identify it.
--- arch/x86/include/asm/nospec-branch.h | 3 +++ arch/x86/kernel/vmlinux.lds.S | 6 ++++++ arch/x86/lib/retpoline.S | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-)
arch/x86/include/asm/nospec-branch.h +3 -0
@@ -194,6 +194,9 @@ enum spectre_v2_mitigation { SPECTRE_V2_IBRS, }; +extern char __indirect_thunk_start[]; +extern char __indirect_thunk_end[]; +/* * On VMEXIT we must ensure that no RSB predictions learned in the guest * can be followed in the host, by overwriting the RSB completely. Both
arch/x86/kernel/vmlinux.lds.S +6 -0
@@ -124,6 +124,12 @@ SECTIONS ASSERT(. - _entry_trampoline == PAGE_SIZE, "entry trampoline is too big"); #endif +#ifdef CONFIG_RETPOLINE + __indirect_thunk_start = .; + *(.text.__x86.indirect_thunk) + __indirect_thunk_end = .; +#endif + /* End of text section */ _etext = .; } :text = 0x9090
arch/x86/lib/retpoline.S +1 -1
@@ -9,7 +9,7 @@ #include <asm/nospec-branch.h> .macro THUNK reg - .section .text.__x86.indirect_thunk.\reg + .section .text.__x86.indirect_thunk ENTRY(__x86_indirect_thunk_\reg) CFI_STARTPROC
PATCH v2 2/3 kprobes/x86: Blacklist indirect thunk functions for kprobes
In reply to Masami HiramatsuMark __x86_indirect_thunk_* functions as blacklist for kprobes because those functions can be called from anywhere in the kernel including blacklist functions of kprobes.
--- arch/x86/lib/retpoline.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/x86/lib/retpoline.S +2 -1
@@ -25,7 +25,8 @@ ENDPROC(__x86_indirect_thunk_\reg) * than one per register with the correct names. So we do it * the simple and nasty way... */ -#define EXPORT_THUNK(reg) EXPORT_SYMBOL(__x86_indirect_thunk_ ## reg) +#define __EXPORT_THUNK(sym) _ASM_NOKPROBE(sym); EXPORT_SYMBOL(sym) +#define EXPORT_THUNK(reg) __EXPORT_THUNK(__x86_indirect_thunk_ ## reg) #define GENERATE_THUNK(reg) THUNK reg ; EXPORT_THUNK(reg) GENERATE_THUNK(_ASM_AX)
tip-bot for Masami Hiramatsu
merge bot[tip:x86/pti] kprobes/x86: Blacklist indirect thunk functions for kprobes
kprobes/x86: Blacklist indirect thunk functions for kprobes
Commit-ID: c1804a236894ecc942da7dc6c5abe209e56cba93 Gitweb: https://git.kernel.org/tip/c1804a236894ecc942da7dc6c5abe209e56cba93 Author: Masami Hiramatsu <[email protected]> AuthorDate: Fri, 19 Jan 2018 01:14:51 +0900 Committer: Thomas Gleixner <[email protected]> CommitDate: Fri, 19 Jan 2018 16:31:28 +0100
kprobes/x86: Blacklist indirect thunk functions for kprobes
Mark __x86_indirect_thunk_* functions as blacklist for kprobes because those functions can be called from anywhere in the kernel including blacklist functions of kprobes.
--- arch/x86/lib/retpoline.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/x86/lib/retpoline.S +2 -1
@@ -25,7 +25,8 @@ ENDPROC(__x86_indirect_thunk_\reg) * than one per register with the correct names. So we do it * the simple and nasty way... */ -#define EXPORT_THUNK(reg) EXPORT_SYMBOL(__x86_indirect_thunk_ ## reg) +#define __EXPORT_THUNK(sym) _ASM_NOKPROBE(sym); EXPORT_SYMBOL(sym) +#define EXPORT_THUNK(reg) __EXPORT_THUNK(__x86_indirect_thunk_ ## reg) #define GENERATE_THUNK(reg) THUNK reg ; EXPORT_THUNK(reg) GENERATE_THUNK(_ASM_AX)
PATCH v2 3/3 kprobes/x86: Disable optimizing on the function jumps to indirect thunk
In reply to Masami HiramatsuSince indirect jump instructions will be replaced by jump to __x86_indirect_thunk_*, those jmp instruction must be treated as an indirect jump. Since optprobe prohibits to optimize probes in the function which uses an indirect jump, it also needs to find out the function which jump to __x86_indirect_thunk_* and disable optimization.
This adds a check that the jump target address is between the __indirect_thunk_start/end when optimizing kprobe.
--- arch/x86/kernel/kprobes/opt.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
arch/x86/kernel/kprobes/opt.c +22 -1
@@ -40,6 +40,7 @@#include <asm/debugreg.h> #include <asm/set_memory.h> #include <asm/sections.h> +#include <asm/nospec-branch.h> #include "common.h"
@@ -203,7 +204,7 @@ static int copy_optimized_instructions(u8 *dest, u8 *src, u8 *real) }/* Check whether insn is indirect jump */ -static int insn_is_indirect_jump (struct insn *insn) +static int __insn_is_indirect_jump (struct insn *insn) { return ((insn->opcode.bytes[0] == 0xff && (X86_MODRM_REG(insn->modrm.value) & 6) == 4) || /* Jump */
@@ -237,6 +238,26 @@ static int insn_jump_into_range(struct insn *insn, unsigned long start, int len)return (start <= target && target <= start + len); } +static int insn_is_indirect_jump (struct insn *insn) +{ +int ret =__insn_is_indirect_jump (insn); + +#ifdef CONFIG_RETPOLINE +/* +* Jump to x86_indirect_thunk_* is treated as an indirect jump. +* Note that even with CONFIG_RETPOLINE=y, the kernel compiled with +* older gcc may use indirect jump. So we add this check instead of +* replace indirect-jump check. +*/ +if (!ret) + ret =insn_jump_into_range (insn, + (unsigned long )__indirect_thunk_start, + (unsigned long )__indirect_thunk_end - + (unsigned long )__indirect_thunk_start); +#endif +return ret; +} +/* Decode whole function to ensure any instructions don't jump into target */ static int can_optimize (unsigned long paddr) {
tip-bot for Masami Hiramatsu
merge bot[tip:x86/pti] kprobes/x86: Disable optimizing on the function jumps to indirect thunk
kprobes/x86: Disable optimizing on the function jumps to indirect thunk
Commit-ID: c86a32c09f8ced67971a2310e3b0dda4d1749007 Gitweb: https://git.kernel.org/tip/c86a32c09f8ced67971a2310e3b0dda4d1749007 Author: Masami Hiramatsu <[email protected]> AuthorDate: Fri, 19 Jan 2018 01:15:20 +0900 Committer: Thomas Gleixner <[email protected]> CommitDate: Fri, 19 Jan 2018 16:31:29 +0100
kprobes/x86: Disable optimizing on the function jumps to indirect thunk
Since indirect jump instructions will be replaced by jump to __x86_indirect_thunk_*, those jmp instruction must be treated as an indirect jump. Since optprobe prohibits to optimize probes in the function which uses an indirect jump, it also needs to find out the function which jump to __x86_indirect_thunk_* and disable optimization.
Add a check that the jump target address is between the __indirect_thunk_start/end when optimizing kprobe.
--- arch/x86/kernel/kprobes/opt.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
arch/x86/kernel/kprobes/opt.c +22 -1
@@ -40,6 +40,7 @@#include <asm/debugreg.h> #include <asm/set_memory.h> #include <asm/sections.h> +#include <asm/nospec-branch.h> #include "common.h"
@@ -205,7 +206,7 @@ static int copy_optimized_instructions(u8 *dest, u8 *src) }/* Check whether insn is indirect jump */ -static int insn_is_indirect_jump (struct insn *insn) +static int __insn_is_indirect_jump (struct insn *insn) { return ((insn->opcode.bytes[0] == 0xff && (X86_MODRM_REG(insn->modrm.value) & 6) == 4) || /* Jump */
@@ -239,6 +240,26 @@ static int insn_jump_into_range(struct insn *insn, unsigned long start, int len)return (start <= target && target <= start + len); } +static int insn_is_indirect_jump (struct insn *insn) +{ +int ret =__insn_is_indirect_jump (insn); + +#ifdef CONFIG_RETPOLINE +/* +* Jump to x86_indirect_thunk_* is treated as an indirect jump. +* Note that even with CONFIG_RETPOLINE=y, the kernel compiled with +* older gcc may use indirect jump. So we add this check instead of +* replace indirect-jump check. +*/ +if (!ret) + ret =insn_jump_into_range (insn, + (unsigned long )__indirect_thunk_start, + (unsigned long )__indirect_thunk_end - + (unsigned long )__indirect_thunk_start); +#endif +return ret; +} +/* Decode whole function to ensure any instructions don't jump into target */ static int can_optimize (unsigned long paddr) {
Quoted 4 lines · Masami Hiramatsu
Masami Hiramatsu (3):
retpoline: Introduce start/end markers of indirect thunk kprobes/x86: Blacklist indirect thunk functions for kprobes kprobes/x86: Disable optimizing on the function jumps to indirect thunk
For all three:
Thank you.