* [PATCH v7 0/4] Compile-time stack validation @ 2015-07-14 17:14 Josh Poimboeuf 2015-07-14 17:14 ` [PATCH v7 1/4] x86/asm: Frame pointer macro cleanup Josh Poimboeuf ` (4 more replies) 0 siblings, 5 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-14 17:14 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel This is v7 of the compile-time stack validation patch set, based on the tip/master branch. v6, which had a lot of major changes, can be found here: https://lkml.kernel.org/r/cover.1436280380.git.jpoimboe@redhat.com For more information about the motivation behind this patch set, and more details about what it does, please see the changelog in patch 2. To reduce churn, I didn't bother posting any patches to fix warnings. If there's agreement on this approach, I can start proposing fixes. Posting a listing of reported warnings in a reply to this email. v7: - sibling call support - document proposed solution for inline asm() frame pointer issues - say "kernel entry/exit" instead of "context switch" - clarify the checking of switch statement jump tables - discard __stackvalidate_ignore_* sections in linker script - use .Ltemp_\@ to get a unique label instead of static 3-digit number - change STACKVALIDATE_IGNORE_FUNC variable to a static - move STACKVALIDATE_IGNORE_INSN to arch-specific .h file v6: - rename asmvalidate -> stackvalidate (again) - gcc-generated object file support - recursive branch state analysis - external jump support - fixup/exception table support - jump label support - switch statement jump table support - added documentation - detection of "noreturn" dead end functions - added a Kbuild mechanism for skipping files and dirs - moved frame pointer macros to arch/x86/include/asm/frame.h - moved ignore macros to include/linux/stackvalidate.h v5: - stackvalidate -> asmvalidate - frame pointers only required for non-leaf functions - check for the use of the FP_SAVE/RESTORE macros instead of manually analyzing code to detect frame pointer usage - additional checks to ensure each function doesn't leave its boundaries - make the macros simpler and more flexible - support for analyzing ALTERNATIVE macros - simplified the arch interfaces in scripts/asmvalidate/arch.h - fixed some asmvalidate warnings - rebased onto latest tip asm cleanups - many more small changes v4: - Changed the default to CONFIG_STACK_VALIDATION=n, until all the asm code can get cleaned up. - Fixed a stackvalidate error path exit code issue found by Michal Marek. v3: - Added a patch to make the push/pop CFI macros arch-independent, as suggested by H. Peter Anvin v2: - Fixed memory leaks reported by Petr Mladek Josh Poimboeuf (4): x86/asm: Frame pointer macro cleanup x86/stackvalidate: Compile-time stack validation x86/stackvalidate: Add file and directory ignores x86/stackvalidate: Add ignore macros Documentation/stack-validation.txt | 193 ++++++++ MAINTAINERS | 8 + arch/Kconfig | 6 + arch/x86/Kconfig | 1 + arch/x86/Makefile | 6 +- arch/x86/boot/Makefile | 3 +- arch/x86/boot/compressed/Makefile | 3 +- arch/x86/entry/vdso/Makefile | 5 +- arch/x86/include/asm/frame.h | 37 +- arch/x86/include/asm/stackvalidate.h | 28 ++ arch/x86/kernel/vmlinux.lds.S | 5 +- arch/x86/purgatory/Makefile | 2 + arch/x86/realmode/Makefile | 4 +- arch/x86/realmode/rm/Makefile | 3 +- drivers/firmware/efi/libstub/Makefile | 1 + include/linux/stackvalidate.h | 21 + lib/Kconfig.debug | 11 + scripts/Makefile | 1 + scripts/Makefile.build | 34 +- scripts/stackvalidate/Makefile | 24 + scripts/stackvalidate/arch-x86.c | 148 ++++++ scripts/stackvalidate/arch.h | 44 ++ scripts/stackvalidate/elf.c | 422 ++++++++++++++++ scripts/stackvalidate/elf.h | 85 ++++ scripts/stackvalidate/list.h | 217 +++++++++ scripts/stackvalidate/special.c | 177 +++++++ scripts/stackvalidate/special.h | 40 ++ scripts/stackvalidate/stackvalidate.c | 881 ++++++++++++++++++++++++++++++++++ 28 files changed, 2382 insertions(+), 28 deletions(-) create mode 100644 Documentation/stack-validation.txt create mode 100644 arch/x86/include/asm/stackvalidate.h create mode 100644 include/linux/stackvalidate.h create mode 100644 scripts/stackvalidate/Makefile create mode 100644 scripts/stackvalidate/arch-x86.c create mode 100644 scripts/stackvalidate/arch.h create mode 100644 scripts/stackvalidate/elf.c create mode 100644 scripts/stackvalidate/elf.h create mode 100644 scripts/stackvalidate/list.h create mode 100644 scripts/stackvalidate/special.c create mode 100644 scripts/stackvalidate/special.h create mode 100644 scripts/stackvalidate/stackvalidate.c -- 2.1.0 ^ permalink raw reply [flat|nested] 89+ messages in thread
* [PATCH v7 1/4] x86/asm: Frame pointer macro cleanup 2015-07-14 17:14 [PATCH v7 0/4] Compile-time stack validation Josh Poimboeuf @ 2015-07-14 17:14 ` Josh Poimboeuf 2015-07-14 17:14 ` [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation Josh Poimboeuf ` (3 subsequent siblings) 4 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-14 17:14 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel The FRAME/ENDFRAME asm macros for setting up and restoring the frame pointer aren't currently being used. However, they will be needed soon to help asm functions to comply with stackvalidate. Make the code more readable and improve the comments. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/include/asm/frame.h | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/arch/x86/include/asm/frame.h b/arch/x86/include/asm/frame.h index 793179c..a9438cd 100644 --- a/arch/x86/include/asm/frame.h +++ b/arch/x86/include/asm/frame.h @@ -1,23 +1,26 @@ +#ifndef _ASM_X86_FRAME_H +#define _ASM_X86_FRAME_H + #ifdef __ASSEMBLY__ #include <asm/asm.h> -/* The annotation hides the frame from the unwinder and makes it look - like a ordinary ebp save/restore. This avoids some special cases for - frame pointer later */ -#ifdef CONFIG_FRAME_POINTER - .macro FRAME - __ASM_SIZE(push,) %__ASM_REG(bp) - __ASM_SIZE(mov) %__ASM_REG(sp), %__ASM_REG(bp) - .endm - .macro ENDFRAME - __ASM_SIZE(pop,) %__ASM_REG(bp) - .endm -#else - .macro FRAME - .endm - .macro ENDFRAME - .endm -#endif +/* + * These are stack frame creation macros. They should be used by every + * callable non-leaf asm function to make kernel stack traces more reliable. + */ +.macro FRAME + .if CONFIG_FRAME_POINTER + push %_ASM_BP + _ASM_MOV %_ASM_SP, %_ASM_BP + .endif +.endm + +.macro ENDFRAME + .if CONFIG_FRAME_POINTER + pop %_ASM_BP + .endif +.endm #endif /* __ASSEMBLY__ */ +#endif /* _ASM_X86_FRAME_H */ -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation 2015-07-14 17:14 [PATCH v7 0/4] Compile-time stack validation Josh Poimboeuf 2015-07-14 17:14 ` [PATCH v7 1/4] x86/asm: Frame pointer macro cleanup Josh Poimboeuf @ 2015-07-14 17:14 ` Josh Poimboeuf 2015-07-14 20:57 ` Peter Zijlstra ` (2 more replies) 2015-07-14 17:14 ` [PATCH v7 3/4] x86/stackvalidate: Add file and directory ignores Josh Poimboeuf ` (2 subsequent siblings) 4 siblings, 3 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-14 17:14 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel This adds a CONFIG_STACK_VALIDATION option which enables a host tool named stackvalidate which runs at compile time. It analyzes every .o file and ensures the validity of its stack metadata. It enforces a set of rules on asm code and C inline assembly code so that stack traces can be reliable. Currently it checks frame pointer usage. I plan to add DWARF CFI validation as well. For each function, it recursively follows all possible code paths and validates the correct frame pointer state at each instruction. It also follows code paths involving special sections, like .altinstructions, __jump_table, and __ex_table, which can add alternative execution paths to a given instruction (or set of instructions). Similarly, it knows how to follow switch statements, for which gcc sometimes uses jump tables. To achieve the validation, stackvalidate enforces the following rules: 1. Each callable function must be annotated as such with the ELF function type. In asm code, this is typically done using the ENTRY/ENDPROC macros. If stackvalidate finds a return instruction outside of a function, it flags an error since that usually indicates callable code which should be annotated accordingly. 2. Conversely, each section of code which is *not* callable should *not* be annotated as an ELF function. The ENDPROC macro shouldn't be used in this case. 3. Each callable function which calls another function must have the correct frame pointer logic, if required by CONFIG_FRAME_POINTER or the architecture's back chain rules. This can by done in asm code with the FRAME/ENDFRAME macros. 4. Dynamic jumps and jumps to undefined symbols are only allowed if: a) the jump is part of a switch statement; or b) the jump matches sibling call semantics and the frame pointer has the same value it had on function entry. 5. A callable function may not execute kernel entry/exit instructions. The only code which needs such instructions is kernel entry code, which shouldn't be in callable functions anyway. It currently only supports x86_64. I tried to make the code generic so that support for other architectures can hopefully be plugged in relatively easily. As a first step, CONFIG_STACK_VALIDATION is disabled by default, and all reported non-compliances result in warnings. Once we get them all cleaned up, we can change the default to CONFIG_STACK_VALIDATION=y and change the warnings to errors to keep the stack metadata clean. On my Lenovo T430s 4-core laptop, building the kernel with it enabled adds about 3.6 seconds (14.4 seconds of total CPU). It hasn't been optimized for performance yet, so there are probably some opportunities for better build performance. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- Documentation/stack-validation.txt | 193 ++++++++ MAINTAINERS | 8 + arch/Kconfig | 6 + arch/x86/Kconfig | 1 + arch/x86/Makefile | 6 +- lib/Kconfig.debug | 11 + scripts/Makefile | 1 + scripts/Makefile.build | 34 +- scripts/stackvalidate/Makefile | 24 + scripts/stackvalidate/arch-x86.c | 148 ++++++ scripts/stackvalidate/arch.h | 44 ++ scripts/stackvalidate/elf.c | 422 ++++++++++++++++ scripts/stackvalidate/elf.h | 85 ++++ scripts/stackvalidate/list.h | 217 +++++++++ scripts/stackvalidate/special.c | 177 +++++++ scripts/stackvalidate/special.h | 40 ++ scripts/stackvalidate/stackvalidate.c | 881 ++++++++++++++++++++++++++++++++++ 17 files changed, 2293 insertions(+), 5 deletions(-) create mode 100644 Documentation/stack-validation.txt create mode 100644 scripts/stackvalidate/Makefile create mode 100644 scripts/stackvalidate/arch-x86.c create mode 100644 scripts/stackvalidate/arch.h create mode 100644 scripts/stackvalidate/elf.c create mode 100644 scripts/stackvalidate/elf.h create mode 100644 scripts/stackvalidate/list.h create mode 100644 scripts/stackvalidate/special.c create mode 100644 scripts/stackvalidate/special.h create mode 100644 scripts/stackvalidate/stackvalidate.c diff --git a/Documentation/stack-validation.txt b/Documentation/stack-validation.txt new file mode 100644 index 0000000..23a427b --- /dev/null +++ b/Documentation/stack-validation.txt @@ -0,0 +1,193 @@ +Compile-time stack validation +============================= + + +Overview +-------- + +The CONFIG_STACK_VALIDATION option enables a host tool named +stackvalidate which runs at compile time. It analyzes every .o file and +ensures the validity of its stack metadata. It enforces a set of rules +on asm code and C inline assembly code so that stack traces can be +reliable. + +Currently it only checks frame pointer usage, but there are plans to add +DWARF CFI validation as well. + +For each function, it recursively follows all possible code paths and +validates the correct frame pointer state at each instruction. + +It also follows code paths involving special sections, like +.altinstructions, __jump_table, and __ex_table, which can add +alternative execution paths to a given instruction (or set of +instructions). Similarly, it knows how to follow switch statements, for +which gcc sometimes uses jump tables. + + +Rules +----- + +To achieve the validation, stackvalidate enforces the following rules: + +1. Each callable function must be annotated as such with the ELF + function type. In asm code, this is typically done using the + ENTRY/ENDPROC macros. If stackvalidate finds a return instruction + outside of a function, it flags an error since that usually indicates + callable code which should be annotated accordingly. + +2. Conversely, each section of code which is *not* callable should *not* + be annotated as an ELF function. The ENDPROC macro shouldn't be used + in this case. + +3. Each callable function which calls another function must have the + correct frame pointer logic, if required by CONFIG_FRAME_POINTER or + the architecture's back chain rules. This can by done in asm code + with the FRAME/ENDFRAME macros. + +4. Dynamic jumps and jumps to undefined symbols are only allowed if: + + a) the jump is part of a switch statement; or + + b) the jump matches sibling call semantics and the frame pointer has + the same value it had on function entry. + +5. A callable function may not execute kernel entry/exit instructions. + The only code which needs such instructions is kernel entry code, + which shouldn't be be in callable functions anyway. + + +Errors in .S files +------------------ + +If you're getting an error in a compiled .S file which you don't +understand, first make sure that the affected code follows the above +rules. + +Here are some examples of common problems and suggestions for how to fix +them. + + +1. stackvalidate: asm_file.o: func()+0x128: call without frame pointer save/setup + + The func() function made a function call without first saving and/or + updating the frame pointer. + + If func() is indeed a callable function, add proper frame pointer + logic using the FP_SAVE and FP_RESTORE macros. Otherwise, remove its + ELF function annotation by changing ENDPROC to END. + + If you're getting this error in a .c file, see the "Errors in .c + files" section. + + +2. stackvalidate: asm_file.o: .text+0x53: return instruction outside of a callable function + + A return instruction was detected, but stackvalidate couldn't find a + way for a callable function to reach the instruction. + + If the return instruction is inside (or reachable from) a callable + function, the function needs to be annotated with the PROC/ENDPROC + macros. + + If you _really_ need a return instruction outside of a function, and + are 100% sure that it won't affect stack traces, you can tell + stackvalidate to ignore it. See the "Adding exceptions" section + below. + + +3. stackvalidate: asm_file.o: func()+0x9: function has unreachable instruction + + The instruction lives inside of a callable function, but there's no + possible control flow path from the beginning of the function to the + instruction. + + If the instruction is actually needed, and it's actually in a + callable function, ensure that its function is properly annotated + with PROC/ENDPROC. + + If it's not actually in a callable function (e.g. kernel entry code), + change ENDPROC to END. + + +4. stackvalidate: asm_file.o: func(): can't find starting instruction + or + stackvalidate: asm_file.o: func()+0x11dd: can't decode instruction + + Did you put data in a text section? If so, that can confuse + stackvalidate's instruction decoder. Move the data to a more + appropriate section like .data or .rodata. + + +5. stackvalidate: asm_file.o: func()+0x6: kernel entry/exit from callable instruction + + This is a kernel entry/exit instruction like sysenter or sysret. + Such instructions aren't allowed in a callable function, and are most + likely part of the kernel entry code. + + If the instruction isn't actually in a callable function, change + ENDPROC to END. + + +6. stackvalidate: asm_file.o: func()+0x26: sibling call from callable instruction with changed frame pointer + + This is a dynamic jump or a jump to an undefined symbol. + Stackvalidate assumed it's a sibling call and detected that the frame + pointer wasn't first restored to its original state. + + If it's not really a sibling call, you may need to move the + destination code to the local file. + + If the instruction is not actually in a callable function (e.g. + kernel entry code), change ENDPROC to END. + + +7. stackvalidate: asm_file: func()+0x5c: frame pointer state mismatch + + The instruction's frame pointer state is inconsistent, depending on + which execution path was taken to reach the instruction. + + Make sure the function pushes and sets up the frame pointer (for + x86_64, this means rbp) at the beginning of the function and pops it + at the end of the function. Also make sure that no other code in the + function touches the frame pointer. + + +Errors in .c files +------------------ + +If you're getting a stackvalidate error in a compiled .c file, chances +are the file uses an asm() statement which has a "call" instruction. An +asm() statement with a call instruction must declare the use of the +stack pointer in its output operand. For example, on x86_64: + + register void *__sp asm("rsp"); + asm volatile("call func" : "+r" (__sp)); + +Otherwise the stack frame may not get created before the call. + +Another possible cause for errors in C code is if the Makefile removes +-fno-omit-frame-pointer or adds -fomit-frame-pointer to the gcc options. + +Also see the above section for .S file errors for more information what +the individual error messages mean. + + + +Adding exceptions +----------------- + +If you _really_ need stackvalidate to ignore something, and are 100% +sure that it won't affect kernel stack traces, you can tell +stackvalidate to ignore it: + +- To skip validation of an instruction, use the + STACKVALIDATE_IGNORE_INSN macro immediately before the instruction. + +- To skip validation of a function, use the STACKVALIDATE_IGNORE_FUNC + macro. + +- To skip validation of a file, add "STACKVALIDATE_filename.o := n" to + the Makefile. + +- To skip validation of a directory, add "STACKVALIDATE := n" to the + Makefile. diff --git a/MAINTAINERS b/MAINTAINERS index 46e4f1d..f7b3b0f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9666,6 +9666,14 @@ L: stable@vger.kernel.org S: Supported F: Documentation/stable_kernel_rules.txt +STACK VALIDATION +M: Josh Poimboeuf <jpoimboe@redhat.com> +S: Supported +F: scripts/stackvalidate/ +F: include/linux/stackvalidate.h +F: arch/x86/include/asm/stackvalidate.h +F: Documentation/stack-validation.txt + STAGING SUBSYSTEM M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git diff --git a/arch/Kconfig b/arch/Kconfig index 150a01b..8a921d5 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -515,6 +515,12 @@ config HAVE_COPY_THREAD_TLS normal C parameter passing, rather than extracting the syscall argument from pt_regs. +config HAVE_STACK_VALIDATION + bool + help + Architecture supports the stackvalidate host tool, which adds + compile-time stack metadata validation. + # # ABI hall of shame # diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 925bc92..1985d02 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -150,6 +150,7 @@ config X86 select VIRT_TO_BUS select X86_DEV_DMA_OPS if X86_64 select X86_FEATURE_NAMES if PROC_FS + select HAVE_STACK_VALIDATION if X86_64 config INSTRUCTION_DECODER def_bool y diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 118e6de..438c153 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -174,9 +174,13 @@ KBUILD_CFLAGS += $(call cc-option,-mno-avx,) KBUILD_CFLAGS += $(mflags-y) KBUILD_AFLAGS += $(mflags-y) -archscripts: scripts_basic +archscripts: scripts_basic $(objtree)/arch/x86/lib/inat-tables.c $(Q)$(MAKE) $(build)=arch/x86/tools relocs +# this file is needed early by scripts/stackvalidate +$(objtree)/arch/x86/lib/inat-tables.c: + $(Q)$(MAKE) $(build)=arch/x86/lib $@ + ### # Syscall table generation diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index e2894b2..6c96f36 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -332,6 +332,17 @@ config FRAME_POINTER larger and slower, but it gives very useful debugging information in case of kernel bugs. (precise oopses/stacktraces/warnings) +config STACK_VALIDATION + bool "Enable compile-time stack metadata validation" + depends on HAVE_STACK_VALIDATION + default n + help + Add compile-time checks to validate stack metadata, including frame + pointers and back chain pointers. This helps ensure that runtime + stack traces are more reliable. + + For more information, see Documentation/stack-validation.txt. + config DEBUG_FORCE_WEAK_PER_CPU bool "Force weak per-cpu definitions" depends on DEBUG_KERNEL diff --git a/scripts/Makefile b/scripts/Makefile index 2016a64..c882a91 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -37,6 +37,7 @@ subdir-y += mod subdir-$(CONFIG_SECURITY_SELINUX) += selinux subdir-$(CONFIG_DTC) += dtc subdir-$(CONFIG_GDB_SCRIPTS) += gdb +subdir-$(CONFIG_STACK_VALIDATION) += stackvalidate # Let clean descend into subdirs subdir- += basic kconfig package diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 01df30a..a1270d3 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -241,9 +241,26 @@ cmd_record_mcount = \ fi; endif +ifdef CONFIG_STACK_VALIDATION + +stackvalidate = $(objtree)/scripts/stackvalidate/stackvalidate + +ifndef CONFIG_FRAME_POINTER +nofp = --no-frame-pointer +endif + +# Set STACKVALIDATE_foo.o=n to skip stack validation for a file. +# Set STACKVALIDATE=n to skip stack validation for a directory. +cmd_stackvalidate = $(if $(patsubst n%,, \ + $(STACKVALIDATE_$(basetarget).o)$(STACKVALIDATE)y), \ + $(stackvalidate) $(nofp) "$(@)";) + +endif # CONFIG_STACK_VALIDATION + define rule_cc_o_c $(call echo-cmd,checksrc) $(cmd_checksrc) \ $(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \ + $(cmd_stackvalidate) \ $(cmd_modversions) \ $(call echo-cmd,record_mcount) \ $(cmd_record_mcount) \ @@ -253,14 +270,23 @@ define rule_cc_o_c mv -f $(dot-target).tmp $(dot-target).cmd endef +define rule_as_o_S + $(call echo-cmd,as_o_S) $(cmd_as_o_S); \ + $(cmd_stackvalidate) \ + scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,as_o_S)' > \ + $(dot-target).tmp; \ + rm -f $(depfile); \ + mv -f $(dot-target).tmp $(dot-target).cmd +endef + # Built-in and composite module parts -$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE +$(obj)/%.o: $(src)/%.c $(recordmcount_source) $(stackvalidate) FORCE $(call cmd,force_checksrc) $(call if_changed_rule,cc_o_c) # Single-part modules are special since we need to mark them in $(MODVERDIR) -$(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE +$(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_source) $(stackvalidate) FORCE $(call cmd,force_checksrc) $(call if_changed_rule,cc_o_c) @{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod) @@ -290,8 +316,8 @@ $(obj)/%.s: $(src)/%.S FORCE quiet_cmd_as_o_S = AS $(quiet_modtag) $@ cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< -$(obj)/%.o: $(src)/%.S FORCE - $(call if_changed_dep,as_o_S) +$(obj)/%.o: $(src)/%.S $(stackvalidate) FORCE + $(call if_changed_rule,as_o_S) targets += $(real-objs-y) $(real-objs-m) $(lib-y) targets += $(extra-y) $(MAKECMDGOALS) $(always) diff --git a/scripts/stackvalidate/Makefile b/scripts/stackvalidate/Makefile new file mode 100644 index 0000000..468c075 --- /dev/null +++ b/scripts/stackvalidate/Makefile @@ -0,0 +1,24 @@ +hostprogs-y := stackvalidate +always := $(hostprogs-y) + +stackvalidate-objs := stackvalidate.o elf.o special.o + +HOSTCFLAGS += -Werror +HOSTLOADLIBES_stackvalidate := -lelf + +ifdef CONFIG_X86 + +stackvalidate-objs += arch-x86.o + +HOSTCFLAGS_arch-x86.o := -I$(objtree)/arch/x86/lib/ \ + -I$(srctree)/arch/x86/include/ \ + -I$(srctree)/arch/x86/lib/ + +$(obj)/arch-x86.o: $(srctree)/arch/x86/lib/insn.c \ + $(srctree)/arch/x86/lib/inat.c \ + $(srctree)/arch/x86/include/asm/inat_types.h \ + $(srctree)/arch/x86/include/asm/inat.h \ + $(srctree)/arch/x86/include/asm/insn.h \ + $(objtree)/arch/x86/lib/inat-tables.c + +endif diff --git a/scripts/stackvalidate/arch-x86.c b/scripts/stackvalidate/arch-x86.c new file mode 100644 index 0000000..7e977e9 --- /dev/null +++ b/scripts/stackvalidate/arch-x86.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> + +#define unlikely(cond) (cond) +#include <asm/insn.h> +#include <inat.c> +#include <insn.c> +#include <stdlib.h> + +#include "elf.h" +#include "arch.h" + +static int is_x86_64(struct elf *elf) +{ + switch (elf->ehdr.e_machine) { + case EM_X86_64: + return 1; + case EM_386: + return 0; + default: + WARN("unexpected ELF machine type %d", elf->ehdr.e_machine); + return -1; + } +} + +int arch_decode_instruction(struct elf *elf, struct section *sec, + unsigned long offset, unsigned int maxlen, + unsigned int *len, unsigned char *type, + unsigned long *immediate) +{ + struct insn insn; + int x86_64; + unsigned char op1, op2, ext; + + x86_64 = is_x86_64(elf); + if (x86_64 == -1) + return -1; + + insn_init(&insn, (void *)(sec->data + offset), maxlen, x86_64); + insn_get_length(&insn); + insn_get_opcode(&insn); + insn_get_modrm(&insn); + insn_get_immediate(&insn); + + if (!insn.opcode.got || !insn.modrm.got || !insn.immediate.got) { + WARN("%s: can't decode instruction", + offstr(sec, offset)); + return -1; + } + + *len = insn.length; + *type = INSN_OTHER; + + if (insn.vex_prefix.nbytes) + return 0; + + op1 = insn.opcode.bytes[0]; + op2 = insn.opcode.bytes[1]; + + switch (op1) { + case 0x55: + if (!insn.rex_prefix.nbytes) + /* push rbp */ + *type = INSN_FP_SAVE; + break; + case 0x5d: + if (!insn.rex_prefix.nbytes) + /* pop rbp */ + *type = INSN_FP_RESTORE; + break; + case 0x70 ... 0x7f: + *type = INSN_JUMP_CONDITIONAL; + break; + case 0x89: + if (insn.rex_prefix.nbytes == 1 && + insn.rex_prefix.bytes[0] == 0x48 && + insn.modrm.nbytes && insn.modrm.bytes[0] == 0xe5) + /* mov rsp, rbp */ + *type = INSN_FP_SETUP; + break; + case 0x90: + *type = INSN_NOP; + case 0x0f: + if (op2 >= 0x80 && op2 <= 0x8f) + *type = INSN_JUMP_CONDITIONAL; + else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || + op2 == 0x35) + /* sysenter, sysret */ + *type = INSN_CONTEXT_SWITCH; + else if (op2 == 0x0b || op2 == 0xb9) + /* ud2 */ + *type = INSN_BUG; + else if (op2 == 0x0d || op2 == 0x1f) + /* nopl/nopw */ + *type = INSN_NOP; + break; + case 0xc9: /* leave */ + *type = INSN_FP_RESTORE; + break; + case 0xe3: /* jecxz/jrcxz */ + *type = INSN_JUMP_CONDITIONAL; + break; + case 0xe9: + case 0xeb: + *type = INSN_JUMP_UNCONDITIONAL; + break; + + case 0xc2: + case 0xc3: + *type = INSN_RETURN; + break; + case 0xc5: /* iret */ + case 0xca: /* retf */ + case 0xcb: /* retf */ + *type = INSN_CONTEXT_SWITCH; + break; + case 0xe8: + *type = INSN_CALL; + break; + case 0xff: + ext = X86_MODRM_REG(insn.modrm.bytes[0]); + if (ext == 2 || ext == 3) + *type = INSN_CALL_DYNAMIC; + else if (ext == 4 || ext == 5) + *type = INSN_JUMP_DYNAMIC; + break; + } + + *immediate = insn.immediate.nbytes ? insn.immediate.value : 0; + + return 0; +} diff --git a/scripts/stackvalidate/arch.h b/scripts/stackvalidate/arch.h new file mode 100644 index 0000000..f7350fc --- /dev/null +++ b/scripts/stackvalidate/arch.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _ARCH_H +#define _ARCH_H + +#include <stdbool.h> +#include "elf.h" + +#define INSN_FP_SAVE 1 +#define INSN_FP_SETUP 2 +#define INSN_FP_RESTORE 3 +#define INSN_JUMP_CONDITIONAL 4 +#define INSN_JUMP_UNCONDITIONAL 5 +#define INSN_JUMP_DYNAMIC 6 +#define INSN_CALL 7 +#define INSN_CALL_DYNAMIC 8 +#define INSN_RETURN 9 +#define INSN_CONTEXT_SWITCH 10 +#define INSN_BUG 11 +#define INSN_NOP 12 +#define INSN_OTHER 13 +#define INSN_LAST INSN_OTHER + +int arch_decode_instruction(struct elf *elf, struct section *sec, + unsigned long offset, unsigned int maxlen, + unsigned int *len, unsigned char *type, + unsigned long *displacement); + +#endif /* _ARCH_H */ diff --git a/scripts/stackvalidate/elf.c b/scripts/stackvalidate/elf.c new file mode 100644 index 0000000..3d269c7 --- /dev/null +++ b/scripts/stackvalidate/elf.c @@ -0,0 +1,422 @@ +/* + * elf.c - ELF access library + * + * Adapted from kpatch (https://github.com/dynup/kpatch): + * Copyright (C) 2013-2015 Josh Poimboeuf <jpoimboe@redhat.com> + * Copyright (C) 2014 Seth Jennings <sjenning@redhat.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "elf.h" + +char *offstr(struct section *sec, unsigned long offset) +{ + struct symbol *func; + char *name, *str; + unsigned long name_off; + + func = find_containing_func(sec, offset); + if (func) { + name = func->name; + name_off = offset - func->offset; + } else { + name = sec->name; + name_off = offset; + } + + str = malloc(strlen(name) + 20); + + if (func) + sprintf(str, "%s()+0x%lx", name, name_off); + else + sprintf(str, "%s+0x%lx", name, name_off); + + return str; +} + +struct section *find_section_by_name(struct elf *elf, const char *name) +{ + struct section *sec; + + list_for_each_entry(sec, &elf->sections, list) + if (!strcmp(sec->name, name)) + return sec; + + return NULL; +} + +static struct section *find_section_by_index(struct elf *elf, + unsigned int index) +{ + struct section *sec; + + list_for_each_entry(sec, &elf->sections, list) + if (sec->index == index) + return sec; + + return NULL; +} + +static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int index) +{ + struct section *sec; + struct symbol *sym; + + list_for_each_entry(sec, &elf->sections, list) + list_for_each_entry(sym, &sec->symbols, list) + if (sym->index == index) + return sym; + + return NULL; +} + +struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset) +{ + struct symbol *sym; + + list_for_each_entry(sym, &sec->symbols, list) + if (sym->type != STT_SECTION && + sym->offset == offset) + return sym; + + return NULL; +} + +struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, + unsigned int len) +{ + struct rela *rela; + + if (!sec->rela) + return NULL; + + list_for_each_entry(rela, &sec->rela->relas, list) + if (rela->offset >= offset && rela->offset < offset + len) + return rela; + + return NULL; +} + +struct rela *find_rela_by_dest(struct section *sec, unsigned long offset) +{ + return find_rela_by_dest_range(sec, offset, 1); +} + +struct symbol *find_containing_func(struct section *sec, unsigned long offset) +{ + struct symbol *func; + + list_for_each_entry(func, &sec->symbols, list) + if (func->type == STT_FUNC && offset >= func->offset && + offset < func->offset + func->len) + return func; + + return NULL; +} + +static int read_sections(struct elf *elf) +{ + Elf_Scn *s = NULL; + struct section *sec; + size_t shstrndx, sections_nr; + int i; + + if (elf_getshdrnum(elf->elf, §ions_nr)) { + perror("elf_getshdrnum"); + return -1; + } + + if (elf_getshdrstrndx(elf->elf, &shstrndx)) { + perror("elf_getshdrstrndx"); + return -1; + } + + for (i = 0; i < sections_nr; i++) { + sec = malloc(sizeof(*sec)); + if (!sec) { + perror("malloc"); + return -1; + } + memset(sec, 0, sizeof(*sec)); + + INIT_LIST_HEAD(&sec->symbols); + INIT_LIST_HEAD(&sec->relas); + + list_add_tail(&sec->list, &elf->sections); + + s = elf_getscn(elf->elf, i); + if (!s) { + perror("elf_getscn"); + return -1; + } + + sec->index = elf_ndxscn(s); + + if (!gelf_getshdr(s, &sec->sh)) { + perror("gelf_getshdr"); + return -1; + } + + sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name); + if (!sec->name) { + perror("elf_strptr"); + return -1; + } + + sec->elf_data = elf_getdata(s, NULL); + if (!sec->elf_data) { + perror("elf_getdata"); + return -1; + } + + if (sec->elf_data->d_off != 0 || + sec->elf_data->d_size != sec->sh.sh_size) { + WARN("unexpected data attributes for %s", sec->name); + return -1; + } + + sec->data = (unsigned long)sec->elf_data->d_buf; + sec->len = sec->elf_data->d_size; + } + + /* sanity check, one more call to elf_nextscn() should return NULL */ + if (elf_nextscn(elf->elf, s)) { + WARN("section entry mismatch"); + return -1; + } + + return 0; +} + +static int read_symbols(struct elf *elf) +{ + struct section *symtab; + struct symbol *sym; + struct list_head *entry, *tmp; + int symbols_nr, i; + + symtab = find_section_by_name(elf, ".symtab"); + if (!symtab) { + WARN("missing symbol table"); + return -1; + } + + symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize; + + for (i = 0; i < symbols_nr; i++) { + sym = malloc(sizeof(*sym)); + if (!sym) { + perror("malloc"); + return -1; + } + memset(sym, 0, sizeof(*sym)); + + sym->index = i; + + if (!gelf_getsym(symtab->elf_data, i, &sym->sym)) { + perror("gelf_getsym"); + goto err; + } + + sym->name = elf_strptr(elf->elf, symtab->sh.sh_link, + sym->sym.st_name); + if (!sym->name) { + perror("elf_strptr"); + goto err; + } + + sym->type = GELF_ST_TYPE(sym->sym.st_info); + sym->bind = GELF_ST_BIND(sym->sym.st_info); + + if (sym->sym.st_shndx > SHN_UNDEF && + sym->sym.st_shndx < SHN_LORESERVE) { + sym->sec = find_section_by_index(elf, + sym->sym.st_shndx); + if (!sym->sec) { + WARN("couldn't find section for symbol %s", + sym->name); + goto err; + } + if (sym->type == STT_SECTION) { + sym->name = sym->sec->name; + sym->sec->sym = sym; + } + } else + sym->sec = find_section_by_index(elf, 0); + + sym->offset = sym->sym.st_value; + sym->len = sym->sym.st_size; + + /* sorted insert into a per-section list */ + entry = &sym->sec->symbols; + list_for_each_prev(tmp, &sym->sec->symbols) { + struct symbol *s; + + s = list_entry(tmp, struct symbol, list); + + if (sym->offset > s->offset) { + entry = tmp; + break; + } + + if (sym->offset == s->offset && sym->len >= s->len) { + entry = tmp; + break; + } + } + list_add(&sym->list, entry); + } + + return 0; + +err: + free(sym); + return -1; +} + +static int read_relas(struct elf *elf) +{ + struct section *sec; + struct rela *rela; + int i; + unsigned int symndx; + + list_for_each_entry(sec, &elf->sections, list) { + if (sec->sh.sh_type != SHT_RELA) + continue; + + sec->base = find_section_by_name(elf, sec->name + 5); + if (!sec->base) { + WARN("can't find base section for rela section %s", + sec->name); + return -1; + } + + sec->base->rela = sec; + + for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) { + rela = malloc(sizeof(*rela)); + if (!rela) { + perror("malloc"); + return -1; + } + memset(rela, 0, sizeof(*rela)); + + list_add_tail(&rela->list, &sec->relas); + + if (!gelf_getrela(sec->elf_data, i, &rela->rela)) { + perror("gelf_getrela"); + return -1; + } + + rela->type = GELF_R_TYPE(rela->rela.r_info); + rela->addend = rela->rela.r_addend; + rela->offset = rela->rela.r_offset; + symndx = GELF_R_SYM(rela->rela.r_info); + rela->sym = find_symbol_by_index(elf, symndx); + if (!rela->sym) { + WARN("can't find rela entry symbol %d for %s", + symndx, sec->name); + return -1; + } + } + } + + return 0; +} + +struct elf *elf_open(const char *name) +{ + struct elf *elf; + + elf_version(EV_CURRENT); + + elf = malloc(sizeof(*elf)); + if (!elf) { + perror("malloc"); + return NULL; + } + memset(elf, 0, sizeof(*elf)); + + INIT_LIST_HEAD(&elf->sections); + + elf->name = strdup(name); + if (!elf->name) { + perror("strdup"); + goto err; + } + + elf->fd = open(name, O_RDONLY); + if (elf->fd == -1) { + perror("open"); + goto err; + } + + elf->elf = elf_begin(elf->fd, ELF_C_READ_MMAP, NULL); + if (!elf->elf) { + perror("elf_begin"); + goto err; + } + + if (!gelf_getehdr(elf->elf, &elf->ehdr)) { + perror("gelf_getehdr"); + goto err; + } + + if (read_sections(elf)) + goto err; + + if (read_symbols(elf)) + goto err; + + if (read_relas(elf)) + goto err; + + return elf; + +err: + elf_close(elf); + return NULL; +} + +void elf_close(struct elf *elf) +{ + struct section *sec, *tmpsec; + struct symbol *sym, *tmpsym; + + list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) { + list_for_each_entry_safe(sym, tmpsym, &sec->symbols, list) { + list_del(&sym->list); + free(sym); + } + list_del(&sec->list); + free(sec); + } + if (elf->name) + free(elf->name); + if (elf->fd > 0) + close(elf->fd); + if (elf->elf) + elf_end(elf->elf); + free(elf); +} diff --git a/scripts/stackvalidate/elf.h b/scripts/stackvalidate/elf.h new file mode 100644 index 0000000..65a27cb --- /dev/null +++ b/scripts/stackvalidate/elf.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _STACKVALIDATE_ELF_H +#define _STACKVALIDATE_ELF_H + +#include <stdio.h> +#include <gelf.h> +#include "list.h" + +#define WARN(format, ...) \ + fprintf(stderr, \ + "stackvalidate: %s: " format "\n", \ + elf->name, ##__VA_ARGS__) + +struct section { + struct list_head list; + GElf_Shdr sh; + struct list_head symbols; + struct list_head relas; + struct section *base, *rela; + struct symbol *sym; + Elf_Data *elf_data; + char *name; + int index; + unsigned long data; + unsigned int len; +}; + +struct symbol { + struct list_head list; + GElf_Sym sym; + struct section *sec; + char *name; + int index; + unsigned char bind, type; + unsigned long offset; + unsigned int len; +}; + +struct rela { + struct list_head list; + GElf_Rela rela; + struct symbol *sym; + unsigned int type; + int offset; + int addend; +}; + +struct elf { + Elf *elf; + GElf_Ehdr ehdr; + int fd; + char *name; + struct list_head sections; +}; + + +struct elf *elf_open(const char *name); +struct section *find_section_by_name(struct elf *elf, const char *name); +struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); +struct rela *find_rela_by_dest(struct section *sec, unsigned long offset); +struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, + unsigned int len); +struct symbol *find_containing_func(struct section *sec, unsigned long offset); +char *offstr(struct section *sec, unsigned long offset); +void elf_close(struct elf *elf); + + + +#endif /* _STACKVALIDATE_ELF_H */ diff --git a/scripts/stackvalidate/list.h b/scripts/stackvalidate/list.h new file mode 100644 index 0000000..25716b5 --- /dev/null +++ b/scripts/stackvalidate/list.h @@ -0,0 +1,217 @@ +#ifndef _LIST_H +#define _LIST_H + +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#define container_of(ptr, type, member) ({ \ + const typeof(((type *)0)->member) *__mptr = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); }) + +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +static inline void __list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +static inline void list_del_init(struct list_head *entry) +{ + __list_del_entry(entry); + INIT_LIST_HEAD(entry); +} + +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del_entry(list); + list_add(list, head); +} + +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del_entry(list); + list_add_tail(list, head); +} + +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + + return (next == head) && (next == head->prev); +} + +static inline void list_rotate_left(struct list_head *head) +{ + struct list_head *first; + + if (!list_empty(head)) { + first = head->next; + list_move_tail(first, head); + } +} + +static inline int list_is_singular(const struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} + +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member) + +#define list_first_entry_or_null(ptr, type, member) \ + (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) + +#define list_next_entry(pos, member) \ + list_entry((pos)->member.next, typeof(*(pos)), member) + +#define list_prev_entry(pos, member) \ + list_entry((pos)->member.prev, typeof(*(pos)), member) + +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) + +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +#define list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; \ + pos != (head); \ + pos = n, n = pos->prev) + +#define list_for_each_entry(pos, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_next_entry(pos, member)) + +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_last_entry(head, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_prev_entry(pos, member)) + +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = list_next_entry(pos, member)) + +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_prev_entry(pos, member); \ + &pos->member != (head); \ + pos = list_prev_entry(pos, member)) + +#define list_for_each_entry_from(pos, head, member) \ + for (; &pos->member != (head); \ + pos = list_next_entry(pos, member)) + +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member), \ + n = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_next_entry(n, member)) + +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_next_entry(pos, member), \ + n = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_next_entry(n, member)) + +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_next_entry(n, member)) + +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_last_entry(head, typeof(*pos), member), \ + n = list_prev_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_prev_entry(n, member)) + +#endif /* _LIST_H */ diff --git a/scripts/stackvalidate/special.c b/scripts/stackvalidate/special.c new file mode 100644 index 0000000..bb5fccb --- /dev/null +++ b/scripts/stackvalidate/special.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* + * This file reads all the special sections which have alternate instructions + * which can be patched in or redirected to at runtime. + */ + +#include <stdlib.h> +#include <string.h> +#include "special.h" + +#define EX_ENTRY_SIZE 8 +#define EX_ORIG_OFFSET 0 +#define EX_NEW_OFFSET 4 + +#define ALT_ENTRY_SIZE 13 +#define ALT_ORIG_OFFSET 0 +#define ALT_NEW_OFFSET 4 +#define ALT_ORIG_LEN_OFFSET 10 +#define ALT_NEW_LEN_OFFSET 11 + +#define JUMP_ENTRY_SIZE 24 +#define JUMP_ORIG_OFFSET 0 +#define JUMP_NEW_OFFSET 8 + +struct special_entry { + char *sec; + bool group; + unsigned char size, orig, new; + unsigned char orig_len, new_len; /* group only */ +}; + +struct special_entry entries[] = { + { + .sec = ".altinstructions", + .group = true, + .size = ALT_ENTRY_SIZE, + .orig = ALT_ORIG_OFFSET, + .orig_len = ALT_ORIG_LEN_OFFSET, + .new = ALT_NEW_OFFSET, + .new_len = ALT_NEW_LEN_OFFSET, + }, + { + .sec = "__jump_table", + .size = JUMP_ENTRY_SIZE, + .orig = JUMP_ORIG_OFFSET, + .new = JUMP_NEW_OFFSET, + }, + { + .sec = "__ex_table", + .size = EX_ENTRY_SIZE, + .orig = EX_ORIG_OFFSET, + .new = EX_NEW_OFFSET, + }, + {}, +}; + +static int get_alt_entry(struct elf *elf, struct special_entry *entry, + struct section *sec, int index, + struct special_alt *alt) +{ + struct rela *orig_rela, *new_rela; + unsigned long offset; + + offset = index * entry->size; + + alt->group = entry->group; + + if (alt->group) { + alt->orig_len = *(unsigned char *)(sec->data + offset + \ + entry->orig_len); + alt->new_len = *(unsigned char *)(sec->data + offset + \ + entry->new_len); + } + + orig_rela = find_rela_by_dest(sec, offset + entry->orig); + if (!orig_rela) { + WARN("%s: can't find orig rela", + offstr(sec, offset + entry->orig)); + return -1; + } + if (orig_rela->sym->type != STT_SECTION) { + WARN("%s: don't know how to handle non-section rela symbol %s", + offstr(sec, offset + entry->orig), + orig_rela->sym->name); + return -1; + } + + alt->orig_sec = orig_rela->sym->sec; + alt->orig_off = orig_rela->addend; + + if (!entry->group || alt->new_len) { + new_rela = find_rela_by_dest(sec, offset + entry->new); + if (!new_rela) { + WARN("%s: can't find new rela", + offstr(sec, offset + entry->new)); + return -1; + } + if (new_rela->sym->type != STT_SECTION) { + WARN("%s: don't know how to handle non-section rela symbol %s", + offstr(sec, offset + entry->new), + new_rela->sym->name); + return -1; + } + + alt->new_sec = new_rela->sym->sec; + alt->new_off = (unsigned int)new_rela->addend; + + /* _ASM_EXTABLE_EX hack */ + if (alt->new_off >= 0x7ffffff0) + alt->new_off -= 0x7ffffff0; + } + + return 0; +} + +/* + * Read all the special sections and create a list of special_alt structs which + * describe all the alternate instructions which can be patched in or + * redirected to at runtime. + */ +int special_get_alts(struct elf *elf, struct list_head *alts) +{ + struct special_entry *entry; + struct section *sec; + unsigned int nr_entries; + struct special_alt *alt; + int index, ret; + + INIT_LIST_HEAD(alts); + + for (entry = entries; entry->sec; entry++) { + sec = find_section_by_name(elf, entry->sec); + if (!sec) + continue; + + if (sec->len % entry->size != 0) { + WARN("%s size not a multiple of %d", + sec->name, JUMP_ENTRY_SIZE); + return -1; + } + + nr_entries = sec->len / entry->size; + + for (index = 0; index < nr_entries; index++) { + alt = malloc(sizeof(*alt)); + if (!alt) { + WARN("malloc failed"); + return -1; + } + memset(alt, 0, sizeof(*alt)); + + ret = get_alt_entry(elf, entry, sec, index, alt); + if (ret) + return ret; + + list_add_tail(&alt->list, alts); + } + } + + return 0; +} diff --git a/scripts/stackvalidate/special.h b/scripts/stackvalidate/special.h new file mode 100644 index 0000000..fc7ea8e --- /dev/null +++ b/scripts/stackvalidate/special.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _SPECIAL_H +#define _SPECIAL_H + +#include <stdbool.h> +#include "elf.h" + +struct special_alt { + struct list_head list; + + bool group; + + struct section *orig_sec; + unsigned long orig_off; + + struct section *new_sec; + unsigned long new_off; + + unsigned int orig_len, new_len; /* group only */ +}; + +int special_get_alts(struct elf *elf, struct list_head *alts); + +#endif /* _SPECIAL_H */ diff --git a/scripts/stackvalidate/stackvalidate.c b/scripts/stackvalidate/stackvalidate.c new file mode 100644 index 0000000..a817130 --- /dev/null +++ b/scripts/stackvalidate/stackvalidate.c @@ -0,0 +1,881 @@ +/* + * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* + * stackvalidate: + * + * This tool analyzes every .o file and ensures the validity of its stack trace + * metadata. It enforces a set of rules on asm code and C inline assembly code + * so that stack traces can be reliable. + * + * NOTE: This program has a lot of memory leaks. That's ok. It's faster and + * easier that way. + * + * For more information, see Documentation/stack-validation.txt. + */ + +#include <argp.h> +#include <stdbool.h> +#include <string.h> +#include <stdlib.h> + +#include "elf.h" +#include "arch.h" +#include "special.h" + +#define STATE_FP_SAVED 0x1 +#define STATE_FP_SETUP 0x2 + +int warnings; + +struct instruction { + struct list_head list; + struct section *sec; + unsigned long offset; + unsigned int len, state; + unsigned char type; + unsigned long immediate; + bool alt_group, visited; + struct symbol *call_dest; + struct instruction *jump_dest; + struct list_head alts; +}; + +struct list_head insns; + +struct alternative { + struct list_head list; + struct instruction *insn; +}; + +struct args { + char *args[1]; + bool nofp; +}; +struct args args; +static const char args_doc[] = "file.o"; +static struct argp_option options[] = { + {"no-frame-pointer", 1, 0, 0, "Don't check frame pointers" }, + {0}, +}; +static error_t parse_opt(int key, char *arg, struct argp_state *state) +{ + /* Get the input argument from argp_parse, which we + know is a pointer to our args structure. */ + struct args *args = state->input; + + switch (key) { + case 1: /* --no-frame-pointer */ + args->nofp = true; + break; + + case ARGP_KEY_ARG: + if (state->arg_num >= 1) + /* Too many arguments. */ + argp_usage(state); + args->args[state->arg_num] = arg; + break; + + case ARGP_KEY_END: + if (state->arg_num < 1) + /* Not enough arguments. */ + argp_usage(state); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} +static struct argp argp = { options, parse_opt, args_doc, 0 }; + +/* + * Check for the STACKVALIDATE_IGNORE_INSN macro. + */ +static bool ignore_insn(struct elf *elf, struct section *sec, + unsigned long offset) +{ + struct section *macro_sec; + struct rela *rela; + + macro_sec = find_section_by_name(elf, "__stackvalidate_ignore_insn"); + if (!macro_sec || !macro_sec->rela) + return false; + + list_for_each_entry(rela, ¯o_sec->rela->relas, list) + if (rela->sym->type == STT_SECTION && + rela->sym == sec->sym && + rela->addend == offset) + return true; + + return false; +} + +/* + * Check for the STACKVALIDATE_IGNORE_FUNC macro. + */ +static bool ignore_func(struct elf *elf, struct symbol *func) +{ + struct section *macro_sec; + struct rela *rela; + + macro_sec = find_section_by_name(elf, "__stackvalidate_ignore_func"); + if (!macro_sec || !macro_sec->rela) + return false; + + list_for_each_entry(rela, ¯o_sec->rela->relas, list) + if (rela->sym == func) + return true; + + return false; +} + +static struct instruction *find_instruction(struct section *sec, + unsigned long offset) +{ + struct instruction *insn; + + list_for_each_entry(insn, &insns, list) + if (insn->sec == sec && insn->offset == offset) + return insn; + + return NULL; +} + +/* + * This checks to see if the given function is a "noreturn" function. + * + * For global functions which are outside the scope of this object file, we + * have to keep a manual list of them. + * + * For local functions, we have to detect them manually by simply looking for + * the lack of a return instruction. + */ +static bool dead_end_function(struct symbol *func) +{ + struct instruction *insn; + + if (func->bind == STB_GLOBAL && + (!strcmp(func->name, "__stack_chk_fail") || + !strcmp(func->name, "panic") || + !strcmp(func->name, "do_exit"))) + return true; + + if (!func->sec) + return false; + + insn = find_instruction(func->sec, func->offset); + if (!insn) + return false; + + list_for_each_entry_from(insn, &insns, list) { + if (insn->sec != func->sec || + insn->offset >= func->offset + func->len) + break; + + if (insn->type == INSN_RETURN) + return false; + + if (insn->type == INSN_JUMP_UNCONDITIONAL) { + struct instruction *dest = insn->jump_dest; + struct symbol *dest_func; + + if (!dest) + /* sibling call to another file */ + return false; + + if (dest->sec != func->sec || + dest->offset < func->offset || + dest->offset >= func->offset + func->len) { + /* local sibling call */ + dest_func = find_symbol_by_offset(dest->sec, + dest->offset); + if (!dest_func) + continue; + + return dead_end_function(dest_func); + } + } + + if (insn->type == INSN_JUMP_DYNAMIC) + /* sibling call */ + return false; + } + + return true; +} + +/* + * Call the arch-specific instruction decoder for all the instructions and add + * them to the global insns list. + */ +static int decode_instructions(struct elf *elf) +{ + struct section *sec; + unsigned long offset; + struct instruction *insn; + int ret; + + INIT_LIST_HEAD(&insns); + + list_for_each_entry(sec, &elf->sections, list) { + + if (!(sec->sh.sh_flags & SHF_EXECINSTR)) + continue; + + for (offset = 0; offset < sec->len; offset += insn->len) { + insn = malloc(sizeof(*insn)); + memset(insn, 0, sizeof(*insn)); + + INIT_LIST_HEAD(&insn->alts); + insn->sec = sec; + insn->offset = offset; + + ret = arch_decode_instruction(elf, sec, offset, + sec->len - offset, + &insn->len, &insn->type, + &insn->immediate); + if (ret) + return ret; + + if (!insn->type || insn->type > INSN_LAST) { + WARN("%s: invalid instruction type %d", + offstr(sec, insn->offset), insn->type); + return -1; + } + + list_add_tail(&insn->list, &insns); + } + } + + return 0; +} + +/* + * Find the destination instructions for all jumps. + */ +static int get_jump_destinations(struct elf *elf) +{ + struct instruction *insn; + struct rela *rela; + struct section *dest_sec; + unsigned long dest_off; + + list_for_each_entry(insn, &insns, list) { + if (insn->type != INSN_JUMP_CONDITIONAL && + insn->type != INSN_JUMP_UNCONDITIONAL) + continue; + + rela = find_rela_by_dest_range(insn->sec, insn->offset, + insn->len); + if (!rela) { + dest_sec = insn->sec; + dest_off = insn->offset + insn->len + insn->immediate; + } else if (rela->sym->type == STT_SECTION) { + dest_sec = rela->sym->sec; + dest_off = rela->addend + 4; + } else if (rela->sym->sec->index) { + dest_sec = rela->sym->sec; + dest_off = rela->sym->sym.st_value + rela->addend + 4; + } else { + /* + * This error (jump to another file) will be handled + * later in validate_functions(). + */ + continue; + } + + insn->jump_dest = find_instruction(dest_sec, dest_off); + if (!insn->jump_dest) { + + /* + * This is a special case where an alt instruction + * jumps past the end of the section. These are + * handled later. + */ + if (!strcmp(insn->sec->name, ".altinstr_replacement")) + continue; + + WARN("%s: can't find jump dest instruction at %s+0x%lx", + offstr(insn->sec, insn->offset), dest_sec->name, + dest_off); + return -1; + } + } + + return 0; +} + +/* + * Find the destination instructions for all calls. + */ +static int get_call_destinations(struct elf *elf) +{ + struct instruction *insn; + unsigned long dest_off; + struct rela *rela; + + list_for_each_entry(insn, &insns, list) { + if (insn->type != INSN_CALL) + continue; + + rela = find_rela_by_dest_range(insn->sec, insn->offset, + insn->len); + if (!rela) { + dest_off = insn->offset + insn->len + insn->immediate; + insn->call_dest = find_symbol_by_offset(insn->sec, + dest_off); + if (!insn->call_dest) { + WARN("%s: can't find call dest symbol at offset 0x%lx", + offstr(insn->sec, insn->offset), dest_off); + return -1; + } + } else if (rela->sym->type == STT_SECTION) { + insn->call_dest = find_symbol_by_offset(rela->sym->sec, + rela->addend+4); + if (!insn->call_dest || + insn->call_dest->type != STT_FUNC) { + WARN("%s: can't find call dest symbol at %s+0x%x", + offstr(insn->sec, insn->offset), + rela->sym->sec->name, rela->addend + 4); + return -1; + } + } else + insn->call_dest = rela->sym; + } + + return 0; +} + +/* + * The .alternatives section requires some extra special care, over and above + * what other special sections require: + * + * 1. Because alternatives are patched in-place, we need to insert a fake jump + * instruction at the end so that validate_branch() skips all the original + * replaced instructions when validating the new instruction path. + * + * 2. An added wrinkle is that the new instruction length might be zero. In + * that case the old instructions are replaced with noops. We simulate that + * by creating a fake jump as the only new instruction. + * + * 3. In some cases, the alternative section includes an instruction which + * conditionally jumps to the _end_ of the entry. We have to modify these + * jumps' destinations to point back to .text rather than the end of the + * entry in .altinstr_replacement. + */ +static int handle_group_alt(struct elf *elf, struct special_alt *special_alt, + struct instruction *orig_insn, + struct instruction **new_insn) +{ + struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump; + unsigned long dest_off; + + last_orig_insn = NULL; + insn = orig_insn; + list_for_each_entry_from(insn, &insns, list) { + if (insn->sec != special_alt->orig_sec || + insn->offset >= special_alt->orig_off + special_alt->orig_len) + break; + + insn->alt_group = true; + last_orig_insn = insn; + } + + if (list_is_last(&last_orig_insn->list, &insns) || + list_next_entry(last_orig_insn, list)->sec != special_alt->orig_sec) { + WARN("%s: don't know how to handle alternatives at end of section", + special_alt->orig_sec->name); + return -1; + } + + fake_jump = malloc(sizeof(*fake_jump)); + if (!fake_jump) { + WARN("malloc failed"); + return -1; + } + memset(fake_jump, 0, sizeof(*fake_jump)); + INIT_LIST_HEAD(&fake_jump->alts); + fake_jump->sec = special_alt->new_sec; + fake_jump->offset = -1; + fake_jump->type = INSN_JUMP_UNCONDITIONAL; + fake_jump->jump_dest = list_next_entry(last_orig_insn, list); + + if (!special_alt->new_len) { + *new_insn = fake_jump; + return 0; + } + + last_new_insn = NULL; + insn = *new_insn; + list_for_each_entry_from(insn, &insns, list) { + if (insn->sec != special_alt->new_sec || + insn->offset >= special_alt->new_off + special_alt->new_len) + break; + + last_new_insn = insn; + + if (insn->type != INSN_JUMP_CONDITIONAL && + insn->type != INSN_JUMP_UNCONDITIONAL) + continue; + + if (!insn->immediate) + continue; + + dest_off = insn->offset + insn->len + insn->immediate; + if (dest_off == special_alt->new_off + special_alt->new_len) + insn->jump_dest = fake_jump; + + if (!insn->jump_dest) { + WARN("%s: can't find alternative jump destination", + offstr(insn->sec, insn->offset)); + return -1; + } + } + + if (!last_new_insn) { + WARN("%s: can't find last new alternative instruction", + offstr(special_alt->new_sec, special_alt->new_off)); + return -1; + } + + list_add(&fake_jump->list, &last_new_insn->list); + + return 0; +} + +/* + * Read all the special sections which have alternate instructions which can be + * patched in or redirected to at runtime. Each instruction having alternate + * instruction(s) has them added to its insn->alts list, which will be + * traversed in validate_branch(). + */ +static int get_special_section_alts(struct elf *elf) +{ + struct list_head special_alts; + struct instruction *orig_insn, *new_insn; + struct special_alt *special_alt, *tmp; + struct alternative *alt; + int ret; + + ret = special_get_alts(elf, &special_alts); + if (ret) + return ret; + + list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { + alt = malloc(sizeof(*alt)); + if (!alt) { + WARN("malloc failed"); + return -1; + } + + orig_insn = find_instruction(special_alt->orig_sec, + special_alt->orig_off); + if (!orig_insn) { + WARN("%s: special: can't find orig instruction", + offstr(special_alt->orig_sec, + special_alt->orig_off)); + return -1; + } + + new_insn = NULL; + if (!special_alt->group || special_alt->new_len) { + new_insn = find_instruction(special_alt->new_sec, + special_alt->new_off); + if (!new_insn) { + WARN("%s: special: can't find new instruction", + offstr(special_alt->new_sec, + special_alt->new_off)); + return -1; + } + } + + if (special_alt->group) { + ret = handle_group_alt(elf, special_alt, orig_insn, + &new_insn); + if (ret) + return ret; + } + + alt->insn = new_insn; + list_add_tail(&alt->list, &orig_insn->alts); + } + + return 0; +} + +/* + * For some switch statements, gcc generates a jump table in the .rodata + * section which contains a list of addresses within the function to jump to. + * This finds these jump tables and adds them to the insn->alts lists. + */ +static int get_switch_alts(struct elf *elf) +{ + struct instruction *insn, *alt_insn; + struct rela *rodata_rela, *rela; + struct section *rodata; + struct symbol *func; + struct alternative *alt; + + list_for_each_entry(insn, &insns, list) { + if (insn->type != INSN_JUMP_DYNAMIC) + continue; + + rodata_rela = find_rela_by_dest_range(insn->sec, insn->offset, + insn->len); + if (!rodata_rela || strcmp(rodata_rela->sym->name, ".rodata")) + continue; + + rodata = find_section_by_name(elf, ".rodata"); + if (!rodata || !rodata->rela) + continue; + + rela = find_rela_by_dest(rodata, rodata_rela->addend); + if (!rela) + continue; + + func = find_containing_func(insn->sec, insn->offset); + if (!func) { + WARN("%s: can't find containing func", + offstr(insn->sec, insn->offset)); + return -1; + } + + list_for_each_entry_from(rela, &rodata->rela->relas, list) { + if (rela->sym->sec != insn->sec || + rela->addend <= func->offset || + rela->addend >= func->offset + func->len) + break; + + alt_insn = find_instruction(insn->sec, rela->addend); + if (!alt_insn) { + WARN("%s: can't find instruction at %s+0x%x", + rodata->rela->name, insn->sec->name, + rela->addend); + return -1; + } + + alt = malloc(sizeof(*alt)); + if (!alt) { + WARN("malloc failed"); + return -1; + } + + alt->insn = alt_insn; + list_add_tail(&alt->list, &insn->alts); + } + } + + return 0; +} + +static int decode_sections(struct elf *elf) +{ + int ret; + + ret = decode_instructions(elf); + if (ret) + return ret; + + ret = get_jump_destinations(elf); + if (ret) + return ret; + + ret = get_call_destinations(elf); + if (ret) + return ret; + + ret = get_special_section_alts(elf); + if (ret) + return ret; + + ret = get_switch_alts(elf); + if (ret) + return ret; + + return 0; +} + +/* + * Follow the branch starting at the given instruction, and recursively follow + * any other branches (jumps). Meanwhile, track the frame pointer state at + * each instruction and validate all the rules described in + * Documentation/stack-validation.txt. + */ +static int validate_branch(struct elf *elf, struct instruction *first, + unsigned char first_state) +{ + struct alternative *alt; + struct instruction *insn; + struct section *sec; + unsigned char state; + int ret, warnings = 0; + + insn = first; + sec = insn->sec; + state = first_state; + + if (insn->alt_group && list_empty(&insn->alts)) { + WARN("%s: don't know how to handle branch to middle of alternative instruction group", + offstr(sec, insn->offset)); + warnings++; + } + + while (1) { + if (insn->visited) { + if (insn->state != state) { + WARN("%s: frame pointer state mismatch", + offstr(sec, insn->offset)); + warnings++; + } + + return warnings; + } + + insn->visited = true; + insn->state = state; + + list_for_each_entry(alt, &insn->alts, list) { + ret = validate_branch(elf, alt->insn, state); + warnings += ret; + } + + switch (insn->type) { + + case INSN_FP_SAVE: + if (!args.nofp) { + if (insn->state & STATE_FP_SAVED) { + WARN("%s: duplicate frame pointer save", + offstr(sec, insn->offset)); + warnings++; + } + state |= STATE_FP_SAVED; + } + break; + + case INSN_FP_SETUP: + if (!args.nofp) { + if (insn->state & STATE_FP_SETUP) { + WARN("%s: duplicate frame pointer setup", + offstr(sec, insn->offset)); + warnings++; + } + state |= STATE_FP_SETUP; + } + break; + + case INSN_FP_RESTORE: + if (!args.nofp) { + if (!insn->state) { + WARN("%s: frame pointer restore without save/setup", + offstr(sec, insn->offset)); + warnings++; + } + state &= ~STATE_FP_SAVED; + state &= ~STATE_FP_SETUP; + } + break; + + case INSN_RETURN: + if (!args.nofp && insn->state) { + WARN("%s: return without frame pointer restore", + offstr(sec, insn->offset)); + warnings++; + } + return warnings; + + case INSN_CALL: + if (insn->call_dest->type == STT_NOTYPE && + !strcmp(insn->call_dest->name, "__fentry__")) + break; + + if (dead_end_function(insn->call_dest)) + return warnings; + + /* fallthrough */ + + case INSN_CALL_DYNAMIC: + if (!args.nofp && !insn->state) { + WARN("%s: call without frame pointer save/setup", + offstr(sec, insn->offset)); + warnings++; + } + break; + + case INSN_JUMP_CONDITIONAL: + case INSN_JUMP_UNCONDITIONAL: + if (insn->jump_dest) { + ret = validate_branch(elf, insn->jump_dest, + state); + warnings += ret; + } else if (insn->state) { + WARN("%s: sibling call from callable instruction with changed frame pointer", + offstr(sec, insn->offset)); + warnings++; + } /* else it's a sibling call */ + + if (insn->type == INSN_JUMP_UNCONDITIONAL) + return warnings; + + break; + + case INSN_JUMP_DYNAMIC: + if (list_empty(&insn->alts) && insn->state) { + WARN("%s: sibling call from callable instruction with changed frame pointer", + offstr(sec, insn->offset)); + warnings++; + } + + return warnings; + + case INSN_CONTEXT_SWITCH: + WARN("%s: kernel entry/exit from callable instruction", + offstr(sec, insn->offset)); + warnings++; + + return warnings; + + case INSN_BUG: + return warnings; + + } + + insn = list_next_entry(insn, list); + + if (&insn->list == &insns || insn->sec != sec) { + WARN("%s: unexpected end of section", sec->name); + warnings++; + return warnings; + } + } + + return warnings; +} + +static int validate_functions(struct elf *elf) +{ + struct section *sec; + struct symbol *func; + struct instruction *insn; + int ret, warnings = 0; + + list_for_each_entry(sec, &elf->sections, list) { + list_for_each_entry(func, &sec->symbols, list) { + if (func->type != STT_FUNC) + continue; + + insn = find_instruction(sec, func->offset); + if (!insn) { + WARN("%s(): can't find starting instruction", + func->name); + warnings++; + continue; + } + + if (ignore_func(elf, func)) { + list_for_each_entry_from(insn, &insns, list) { + if (insn->sec != func->sec || + insn->offset >= func->offset + func->len) + break; + insn->visited = true; + } + } + + ret = validate_branch(elf, insn, 0); + warnings += ret; + } + } + + list_for_each_entry(sec, &elf->sections, list) { + list_for_each_entry(func, &sec->symbols, list) { + if (func->type != STT_FUNC) + continue; + + insn = find_instruction(sec, func->offset); + if (!insn) + continue; + + list_for_each_entry_from(insn, &insns, list) { + if (insn->sec != func->sec || + insn->offset >= func->offset + func->len) + break; + + if (!insn->visited && insn->type != INSN_NOP) { + WARN("%s: function has unreachable instruction", + offstr(insn->sec, insn->offset)); + warnings++; + } + + insn->visited = true; + } + } + } + + return warnings; +} + +static int validate_uncallable_instructions(struct elf *elf) +{ + struct instruction *insn; + int warnings = 0; + + list_for_each_entry(insn, &insns, list) { + if (!insn->visited && insn->type == INSN_RETURN && + !ignore_insn(elf, insn->sec, insn->offset)) { + WARN("%s: return instruction outside of a callable function", + offstr(insn->sec, insn->offset)); + warnings++; + } + } + + return warnings; +} + +int main(int argc, char *argv[]) +{ + struct elf *elf; + int ret = 0, warnings = 0; + + argp_parse(&argp, argc, argv, 0, 0, &args); + + elf = elf_open(args.args[0]); + if (!elf) { + fprintf(stderr, "error reading elf file %s\n", args.args[0]); + return 1; + } + + ret = decode_sections(elf); + if (ret < 0) + goto out; + warnings += ret; + + ret = validate_functions(elf); + if (ret < 0) + goto out; + warnings += ret; + + ret = validate_uncallable_instructions(elf); + if (ret < 0) + goto out; + warnings += ret; + +out: + /* ignore warnings for now until we get all the code cleaned up */ + if (ret || warnings) + return 0; + return 0; +} -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* Re: [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation 2015-07-14 17:14 ` [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation Josh Poimboeuf @ 2015-07-14 20:57 ` Peter Zijlstra 2015-07-14 21:11 ` Josh Poimboeuf 2015-07-14 21:08 ` Peter Zijlstra 2015-07-20 16:53 ` Namhyung Kim 2 siblings, 1 reply; 89+ messages in thread From: Peter Zijlstra @ 2015-07-14 20:57 UTC (permalink / raw) To: Josh Poimboeuf Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel On Tue, Jul 14, 2015 at 12:14:08PM -0500, Josh Poimboeuf wrote: > This adds a CONFIG_STACK_VALIDATION option which enables a host tool > named stackvalidate which runs at compile time. It analyzes every .o > file and ensures the validity of its stack metadata. It enforces a set > of rules on asm code and C inline assembly code so that stack traces can > be reliable. > > Currently it checks frame pointer usage. I plan to add DWARF CFI > validation as well. Validation or Annotation, as in the generation of DWARF CFI info? ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation 2015-07-14 20:57 ` Peter Zijlstra @ 2015-07-14 21:11 ` Josh Poimboeuf 0 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-14 21:11 UTC (permalink / raw) To: Peter Zijlstra Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel On Tue, Jul 14, 2015 at 10:57:38PM +0200, Peter Zijlstra wrote: > On Tue, Jul 14, 2015 at 12:14:08PM -0500, Josh Poimboeuf wrote: > > This adds a CONFIG_STACK_VALIDATION option which enables a host tool > > named stackvalidate which runs at compile time. It analyzes every .o > > file and ensures the validity of its stack metadata. It enforces a set > > of rules on asm code and C inline assembly code so that stack traces can > > be reliable. > > > > Currently it checks frame pointer usage. I plan to add DWARF CFI > > validation as well. > > Validation or Annotation, as in the generation of DWARF CFI info? My current thinking is I'll do both: - CFI generation for asm code - CFI validation of C code (and possibly asm code too) It's TBD whether the generation will be done by this tool or by a separate tool. -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation 2015-07-14 17:14 ` [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation Josh Poimboeuf 2015-07-14 20:57 ` Peter Zijlstra @ 2015-07-14 21:08 ` Peter Zijlstra 2015-07-14 21:30 ` Josh Poimboeuf 2015-07-20 16:53 ` Namhyung Kim 2 siblings, 1 reply; 89+ messages in thread From: Peter Zijlstra @ 2015-07-14 21:08 UTC (permalink / raw) To: Josh Poimboeuf Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel On Tue, Jul 14, 2015 at 12:14:08PM -0500, Josh Poimboeuf wrote: > This adds a CONFIG_STACK_VALIDATION option which enables a host tool > named stackvalidate which runs at compile time. It analyzes every .o > file and ensures the validity of its stack metadata. It enforces a set > of rules on asm code and C inline assembly code so that stack traces can > be reliable. > > Currently it checks frame pointer usage. I plan to add DWARF CFI > validation as well. > > For each function, it recursively follows all possible code paths and > validates the correct frame pointer state at each instruction. > > It also follows code paths involving special sections, like > .altinstructions, __jump_table, and __ex_table, which can add > alternative execution paths to a given instruction (or set of > instructions). Similarly, it knows how to follow switch statements, for > which gcc sometimes uses jump tables. > > To achieve the validation, stackvalidate enforces the following rules: > > 1. Each callable function must be annotated as such with the ELF > function type. In asm code, this is typically done using the > ENTRY/ENDPROC macros. If stackvalidate finds a return instruction > outside of a function, it flags an error since that usually indicates > callable code which should be annotated accordingly. > > 2. Conversely, each section of code which is *not* callable should *not* > be annotated as an ELF function. The ENDPROC macro shouldn't be used > in this case. > > 3. Each callable function which calls another function must have the > correct frame pointer logic, if required by CONFIG_FRAME_POINTER or > the architecture's back chain rules. This can by done in asm code > with the FRAME/ENDFRAME macros. > > 4. Dynamic jumps and jumps to undefined symbols are only allowed if: > > a) the jump is part of a switch statement; or > > b) the jump matches sibling call semantics and the frame pointer has > the same value it had on function entry. > > 5. A callable function may not execute kernel entry/exit instructions. > The only code which needs such instructions is kernel entry code, > which shouldn't be in callable functions anyway. How (if it does at all) deal with function-trace / -pg -fprofile-arcs things? Does it silently ignore the __mcount calls and assumes ftrace knows wtf its doing? ;-) ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation 2015-07-14 21:08 ` Peter Zijlstra @ 2015-07-14 21:30 ` Josh Poimboeuf 2015-07-14 21:56 ` Peter Zijlstra 0 siblings, 1 reply; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-14 21:30 UTC (permalink / raw) To: Peter Zijlstra Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel, Steven Rostedt On Tue, Jul 14, 2015 at 11:08:58PM +0200, Peter Zijlstra wrote: > On Tue, Jul 14, 2015 at 12:14:08PM -0500, Josh Poimboeuf wrote: > > This adds a CONFIG_STACK_VALIDATION option which enables a host tool > > named stackvalidate which runs at compile time. It analyzes every .o > > file and ensures the validity of its stack metadata. It enforces a set > > of rules on asm code and C inline assembly code so that stack traces can > > be reliable. > > > > Currently it checks frame pointer usage. I plan to add DWARF CFI > > validation as well. > > > > For each function, it recursively follows all possible code paths and > > validates the correct frame pointer state at each instruction. > > > > It also follows code paths involving special sections, like > > .altinstructions, __jump_table, and __ex_table, which can add > > alternative execution paths to a given instruction (or set of > > instructions). Similarly, it knows how to follow switch statements, for > > which gcc sometimes uses jump tables. > > > > To achieve the validation, stackvalidate enforces the following rules: > > > > 1. Each callable function must be annotated as such with the ELF > > function type. In asm code, this is typically done using the > > ENTRY/ENDPROC macros. If stackvalidate finds a return instruction > > outside of a function, it flags an error since that usually indicates > > callable code which should be annotated accordingly. > > > > 2. Conversely, each section of code which is *not* callable should *not* > > be annotated as an ELF function. The ENDPROC macro shouldn't be used > > in this case. > > > > 3. Each callable function which calls another function must have the > > correct frame pointer logic, if required by CONFIG_FRAME_POINTER or > > the architecture's back chain rules. This can by done in asm code > > with the FRAME/ENDFRAME macros. > > > > 4. Dynamic jumps and jumps to undefined symbols are only allowed if: > > > > a) the jump is part of a switch statement; or > > > > b) the jump matches sibling call semantics and the frame pointer has > > the same value it had on function entry. > > > > 5. A callable function may not execute kernel entry/exit instructions. > > The only code which needs such instructions is kernel entry code, > > which shouldn't be in callable functions anyway. > > > How (if it does at all) deal with function-trace / -pg -fprofile-arcs > things? Does it silently ignore the __mcount calls and assumes ftrace > knows wtf its doing? ;-) Adding Steven to CC to keep me honest. In the case of "-pg -mfentry", which is what ftrace has relied on for the past few years for newer versions of gcc, stackvalidate silently ignores __fentry__ calls and assumes that ftrace indeed knows wtf it's doing. I don't see a problem there as long as the ftrace handler doesn't sleep. I haven't run stackvalidate on the old "-pg" mcount non-fentry stuff, but I think it creates a stack frame before calling mcount, so it should be fine. I don't know much about -fprofile-arcs, but as far as I can tell, it's only used for gcov. -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation 2015-07-14 21:30 ` Josh Poimboeuf @ 2015-07-14 21:56 ` Peter Zijlstra 2015-07-14 22:32 ` Josh Poimboeuf 0 siblings, 1 reply; 89+ messages in thread From: Peter Zijlstra @ 2015-07-14 21:56 UTC (permalink / raw) To: Josh Poimboeuf Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel, Steven Rostedt On Tue, Jul 14, 2015 at 04:30:34PM -0500, Josh Poimboeuf wrote: > > How (if it does at all) deal with function-trace / -pg -fprofile-arcs > > things? Does it silently ignore the __mcount calls and assumes ftrace > > knows wtf its doing? ;-) > > Adding Steven to CC to keep me honest. > > In the case of "-pg -mfentry", which is what ftrace has relied on for Ah -mfentry is the magic word, I couldn't find it and a grep led me astray. > the past few years for newer versions of gcc, stackvalidate silently > ignores __fentry__ calls and assumes that ftrace indeed knows wtf it's > doing. I don't see a problem there as long as the ftrace handler > doesn't sleep. They should not indeed, however it would be very nice if backtraces would still be 'good'. > I haven't run stackvalidate on the old "-pg" mcount non-fentry stuff, > but I think it creates a stack frame before calling mcount, so it should > be fine. Ok. > I don't know much about -fprofile-arcs, but as far as I can tell, it's > only used for gcov. Right, nobody much uses that I think. ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation 2015-07-14 21:56 ` Peter Zijlstra @ 2015-07-14 22:32 ` Josh Poimboeuf 0 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-14 22:32 UTC (permalink / raw) To: Peter Zijlstra Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel, Steven Rostedt On Tue, Jul 14, 2015 at 11:56:49PM +0200, Peter Zijlstra wrote: > On Tue, Jul 14, 2015 at 04:30:34PM -0500, Josh Poimboeuf wrote: > > the past few years for newer versions of gcc, stackvalidate silently > > ignores __fentry__ calls and assumes that ftrace indeed knows wtf it's > > doing. I don't see a problem there as long as the ftrace handler > > doesn't sleep. > > They should not indeed, however it would be very nice if backtraces > would still be 'good'. Agreed, though I don't know if it's possible for stackvalidate to reasonably understand what ftrace is doing. I tend to doubt it, since ftrace does some code modification at runtime. It does spit out some warnings for mcount_64.S. I'll need to look at that code in more detail to figure out if the warnings should be whitelisted as false positives, or if there's some way to annotate the code to help stackvalidate understand it and validate it. -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation 2015-07-14 17:14 ` [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation Josh Poimboeuf 2015-07-14 20:57 ` Peter Zijlstra 2015-07-14 21:08 ` Peter Zijlstra @ 2015-07-20 16:53 ` Namhyung Kim 2015-07-20 17:50 ` Josh Poimboeuf 2 siblings, 1 reply; 89+ messages in thread From: Namhyung Kim @ 2015-07-20 16:53 UTC (permalink / raw) To: Josh Poimboeuf Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, LKML Hi, Just nitpicks below.. On Wed, Jul 15, 2015 at 2:14 AM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > +struct elf *elf_open(const char *name) > +{ > + struct elf *elf; > + > + elf_version(EV_CURRENT); > + > + elf = malloc(sizeof(*elf)); > + if (!elf) { > + perror("malloc"); > + return NULL; > + } > + memset(elf, 0, sizeof(*elf)); > + > + INIT_LIST_HEAD(&elf->sections); > + > + elf->name = strdup(name); > + if (!elf->name) { > + perror("strdup"); > + goto err; > + } > + > + elf->fd = open(name, O_RDONLY); > + if (elf->fd == -1) { > + perror("open"); > + goto err; > + } > + > + elf->elf = elf_begin(elf->fd, ELF_C_READ_MMAP, NULL); > + if (!elf->elf) { > + perror("elf_begin"); > + goto err; > + } > + > + if (!gelf_getehdr(elf->elf, &elf->ehdr)) { > + perror("gelf_getehdr"); > + goto err; > + } > + > + if (read_sections(elf)) > + goto err; > + > + if (read_symbols(elf)) > + goto err; > + > + if (read_relas(elf)) > + goto err; > + > + return elf; > + > +err: > + elf_close(elf); > + return NULL; > +} > + > +void elf_close(struct elf *elf) > +{ > + struct section *sec, *tmpsec; > + struct symbol *sym, *tmpsym; > + > + list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) { > + list_for_each_entry_safe(sym, tmpsym, &sec->symbols, list) { > + list_del(&sym->list); > + free(sym); > + } It seems that it needs to free entries in sec->relas too here. > + list_del(&sec->list); > + free(sec); > + } > + if (elf->name) > + free(elf->name); > + if (elf->fd > 0) > + close(elf->fd); > + if (elf->elf) > + elf_end(elf->elf); > + free(elf); > +} [SNIP] > +int main(int argc, char *argv[]) > +{ > + struct elf *elf; > + int ret = 0, warnings = 0; > + > + argp_parse(&argp, argc, argv, 0, 0, &args); > + > + elf = elf_open(args.args[0]); > + if (!elf) { > + fprintf(stderr, "error reading elf file %s\n", args.args[0]); > + return 1; > + } > + > + ret = decode_sections(elf); > + if (ret < 0) > + goto out; > + warnings += ret; > + > + ret = validate_functions(elf); > + if (ret < 0) > + goto out; > + warnings += ret; > + > + ret = validate_uncallable_instructions(elf); > + if (ret < 0) > + goto out; > + warnings += ret; > + > +out: elf_close(elf); ?? Thanks, Namhyung > + /* ignore warnings for now until we get all the code cleaned up */ > + if (ret || warnings) > + return 0; > + return 0; > +} > -- > 2.1.0 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > Please read the FAQ at http://www.tux.org/lkml/ ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation 2015-07-20 16:53 ` Namhyung Kim @ 2015-07-20 17:50 ` Josh Poimboeuf 2015-07-21 8:02 ` Ingo Molnar 2015-07-21 8:42 ` Bernd Petrovitsch 0 siblings, 2 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-20 17:50 UTC (permalink / raw) To: Namhyung Kim Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, LKML On Tue, Jul 21, 2015 at 01:53:25AM +0900, Namhyung Kim wrote: > Hi, > > Just nitpicks below.. Hi Namhyung, thanks for the review! > On Wed, Jul 15, 2015 at 2:14 AM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > > +void elf_close(struct elf *elf) > > +{ > > + struct section *sec, *tmpsec; > > + struct symbol *sym, *tmpsym; > > + > > + list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) { > > + list_for_each_entry_safe(sym, tmpsym, &sec->symbols, list) { > > + list_del(&sym->list); > > + free(sym); > > + } > > It seems that it needs to free entries in sec->relas too here. I must confess that this program has some known memory leaks. I actually have a comment at the top of the file attempting to explain why, but I'll try to improve the comment a little bit. Many of the leaks are actually intentional, since it's a short running program that needs to run fast (though I haven't yet optimized it for speed). And most of the data structures are needed until it exits anyway. It's perhaps distasteful, but it improves performance. And I'm a pragmatist at heart ;-) That said, I will make your suggested change here, since maybe the elf.c code might someday be reused elsewhere, and freeing memory is actually the goal of this function. > > +int main(int argc, char *argv[]) > > +{ > > + struct elf *elf; > > + int ret = 0, warnings = 0; > > + > > + argp_parse(&argp, argc, argv, 0, 0, &args); > > + > > + elf = elf_open(args.args[0]); > > + if (!elf) { > > + fprintf(stderr, "error reading elf file %s\n", args.args[0]); > > + return 1; > > + } > > + > > + ret = decode_sections(elf); > > + if (ret < 0) > > + goto out; > > + warnings += ret; > > + > > + ret = validate_functions(elf); > > + if (ret < 0) > > + goto out; > > + warnings += ret; > > + > > + ret = validate_uncallable_instructions(elf); > > + if (ret < 0) > > + goto out; > > + warnings += ret; > > + > > +out: > > elf_close(elf); ?? I intentionally left out the call to elf_close() here, since this is the exit path and the kernel will free the memory anyway. -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation 2015-07-20 17:50 ` Josh Poimboeuf @ 2015-07-21 8:02 ` Ingo Molnar 2015-07-21 12:04 ` Josh Poimboeuf 2015-07-21 8:42 ` Bernd Petrovitsch 1 sibling, 1 reply; 89+ messages in thread From: Ingo Molnar @ 2015-07-21 8:02 UTC (permalink / raw) To: Josh Poimboeuf Cc: Namhyung Kim, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, LKML * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > > > +int main(int argc, char *argv[]) > > > +{ > > > + struct elf *elf; > > > + int ret = 0, warnings = 0; > > > + > > > + argp_parse(&argp, argc, argv, 0, 0, &args); > > > + > > > + elf = elf_open(args.args[0]); > > > + if (!elf) { > > > + fprintf(stderr, "error reading elf file %s\n", args.args[0]); > > > + return 1; > > > + } > > > + > > > + ret = decode_sections(elf); > > > + if (ret < 0) > > > + goto out; > > > + warnings += ret; > > > + > > > + ret = validate_functions(elf); > > > + if (ret < 0) > > > + goto out; > > > + warnings += ret; > > > + > > > + ret = validate_uncallable_instructions(elf); > > > + if (ret < 0) > > > + goto out; > > > + warnings += ret; > > > + > > > +out: > > > > elf_close(elf); ?? > > I intentionally left out the call to elf_close() here, since this is the > exit path and the kernel will free the memory anyway. OTOH it makes Valgrind runs harder to interpret, as real leaks won't be visible. So I'd only do intentional leaks only if it's truly, measurably improves performance. Thanks, Ingo ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation 2015-07-21 8:02 ` Ingo Molnar @ 2015-07-21 12:04 ` Josh Poimboeuf 0 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-21 12:04 UTC (permalink / raw) To: Ingo Molnar Cc: Namhyung Kim, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, LKML On Tue, Jul 21, 2015 at 10:02:03AM +0200, Ingo Molnar wrote: > > * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > > > > > +int main(int argc, char *argv[]) > > > > +{ > > > > + struct elf *elf; > > > > + int ret = 0, warnings = 0; > > > > + > > > > + argp_parse(&argp, argc, argv, 0, 0, &args); > > > > + > > > > + elf = elf_open(args.args[0]); > > > > + if (!elf) { > > > > + fprintf(stderr, "error reading elf file %s\n", args.args[0]); > > > > + return 1; > > > > + } > > > > + > > > > + ret = decode_sections(elf); > > > > + if (ret < 0) > > > > + goto out; > > > > + warnings += ret; > > > > + > > > > + ret = validate_functions(elf); > > > > + if (ret < 0) > > > > + goto out; > > > > + warnings += ret; > > > > + > > > > + ret = validate_uncallable_instructions(elf); > > > > + if (ret < 0) > > > > + goto out; > > > > + warnings += ret; > > > > + > > > > +out: > > > > > > elf_close(elf); ?? > > > > I intentionally left out the call to elf_close() here, since this is the > > exit path and the kernel will free the memory anyway. > > OTOH it makes Valgrind runs harder to interpret, as real leaks won't be visible. > > So I'd only do intentional leaks only if it's truly, measurably improves > performance. Ok. I'll fix the leaks. -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation 2015-07-20 17:50 ` Josh Poimboeuf 2015-07-21 8:02 ` Ingo Molnar @ 2015-07-21 8:42 ` Bernd Petrovitsch 2015-07-21 12:06 ` Josh Poimboeuf 1 sibling, 1 reply; 89+ messages in thread From: Bernd Petrovitsch @ 2015-07-21 8:42 UTC (permalink / raw) To: Josh Poimboeuf Cc: Namhyung Kim, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, LKML On Mon, 2015-07-20 at 12:50 -0500, Josh Poimboeuf wrote: [...] > It's perhaps distasteful, but it improves performance. And I'm a > pragmatist at heart ;-) And you measured the time gain guaranteeing that it actually saves that much time. Usually that isn't actually measurable .... And the usual solution is to have a preprocessor symbol to allow people with lots of time and/or "valgrind" and similar tools to clean up cleanly and the speed gang can compile that code out. Kind regards, Bernd -- "I dislike type abstraction if it has no real reason. And saving on typing is not a good reason - if your typing speed is the main issue when you're coding, you're doing something seriously wrong." - Linus Torvalds ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation 2015-07-21 8:42 ` Bernd Petrovitsch @ 2015-07-21 12:06 ` Josh Poimboeuf 0 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-21 12:06 UTC (permalink / raw) To: Bernd Petrovitsch Cc: Namhyung Kim, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, LKML On Tue, Jul 21, 2015 at 10:42:32AM +0200, Bernd Petrovitsch wrote: > On Mon, 2015-07-20 at 12:50 -0500, Josh Poimboeuf wrote: > [...] > > It's perhaps distasteful, but it improves performance. And I'm a > > pragmatist at heart ;-) > > And you measured the time gain guaranteeing that it actually saves that > much time. Usually that isn't actually measurable .... You're probably right. s/pragmatist/lazy/ ;-) I'll fix the leaks. -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* [PATCH v7 3/4] x86/stackvalidate: Add file and directory ignores 2015-07-14 17:14 [PATCH v7 0/4] Compile-time stack validation Josh Poimboeuf 2015-07-14 17:14 ` [PATCH v7 1/4] x86/asm: Frame pointer macro cleanup Josh Poimboeuf 2015-07-14 17:14 ` [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation Josh Poimboeuf @ 2015-07-14 17:14 ` Josh Poimboeuf 2015-07-14 17:14 ` [PATCH v7 4/4] x86/stackvalidate: Add ignore macros Josh Poimboeuf 2015-07-14 17:25 ` [PATCH v7 0/4] Compile-time stack validation Josh Poimboeuf 4 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-14 17:14 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel Tell stackvalidate to skip validation of the following code: - boot image - vdso image - kexec purgatory - realmode - efi libstub They all run outside the kernel's normal mode of operation and they don't affect runtime kernel stack traces, so they're free to skirt the stackvalidate rules. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/boot/Makefile | 3 ++- arch/x86/boot/compressed/Makefile | 3 ++- arch/x86/entry/vdso/Makefile | 5 ++++- arch/x86/purgatory/Makefile | 2 ++ arch/x86/realmode/Makefile | 4 +++- arch/x86/realmode/rm/Makefile | 3 ++- drivers/firmware/efi/libstub/Makefile | 1 + 7 files changed, 16 insertions(+), 5 deletions(-) diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index 57bbf2f..f3f0c35 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile @@ -14,7 +14,8 @@ # Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode. # The number is the same as you would ordinarily press at bootup. -KASAN_SANITIZE := n +KASAN_SANITIZE := n +STACKVALIDATE := n SVGA_MODE := -DSVGA_MODE=NORMAL_VGA diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 0a291cd..530a46f 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -16,7 +16,8 @@ # (see scripts/Makefile.lib size_append) # compressed vmlinux.bin.all + u32 size of vmlinux.bin.all -KASAN_SANITIZE := n +KASAN_SANITIZE := n +STACKVALIDATE := n targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \ vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4 diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile index 96c0617..ccaf812 100644 --- a/arch/x86/entry/vdso/Makefile +++ b/arch/x86/entry/vdso/Makefile @@ -3,7 +3,9 @@ # KBUILD_CFLAGS += $(DISABLE_LTO) -KASAN_SANITIZE := n + +KASAN_SANITIZE := n +STACKVALIDATE := n VDSO64-$(CONFIG_X86_64) := y VDSOX32-$(CONFIG_X86_X32_ABI) := y @@ -15,6 +17,7 @@ vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o # files to link into kernel obj-y += vma.o +STACKVALIDATE_vma.o := y # vDSO images to build vdso_img-$(VDSO64-y) += 64 diff --git a/arch/x86/purgatory/Makefile b/arch/x86/purgatory/Makefile index 2c835e3..a736c19 100644 --- a/arch/x86/purgatory/Makefile +++ b/arch/x86/purgatory/Makefile @@ -1,3 +1,5 @@ +STACKVALIDATE := n + purgatory-y := purgatory.o stack.o setup-x86_$(BITS).o sha256.o entry64.o string.o targets += $(purgatory-y) diff --git a/arch/x86/realmode/Makefile b/arch/x86/realmode/Makefile index e02c2c6..7a2d4df 100644 --- a/arch/x86/realmode/Makefile +++ b/arch/x86/realmode/Makefile @@ -6,7 +6,9 @@ # for more details. # # -KASAN_SANITIZE := n +KASAN_SANITIZE := n +STACKVALIDATE := n + subdir- := rm obj-y += init.o diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile index 2730d77..d462a57 100644 --- a/arch/x86/realmode/rm/Makefile +++ b/arch/x86/realmode/rm/Makefile @@ -6,7 +6,8 @@ # for more details. # # -KASAN_SANITIZE := n +KASAN_SANITIZE := n +STACKVALIDATE := n always := realmode.bin realmode.relocs diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 816dbe9..b392f3f 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -20,6 +20,7 @@ KBUILD_CFLAGS := $(cflags-y) \ GCOV_PROFILE := n KASAN_SANITIZE := n +STACKVALIDATE := n lib-y := efi-stub-helper.o lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [PATCH v7 4/4] x86/stackvalidate: Add ignore macros 2015-07-14 17:14 [PATCH v7 0/4] Compile-time stack validation Josh Poimboeuf ` (2 preceding siblings ...) 2015-07-14 17:14 ` [PATCH v7 3/4] x86/stackvalidate: Add file and directory ignores Josh Poimboeuf @ 2015-07-14 17:14 ` Josh Poimboeuf 2015-07-14 17:25 ` [PATCH v7 0/4] Compile-time stack validation Josh Poimboeuf 4 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-14 17:14 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel Add new stackvalidate ignore macros: STACKVALIDATE_IGNORE_INSN and STACKVALIDATE_IGNORE_FUNC. These can be used to tell stackvalidate to skip validation of an instruction or a function, respectively. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/include/asm/stackvalidate.h | 28 ++++++++++++++++++++++++++++ arch/x86/kernel/vmlinux.lds.S | 5 ++++- include/linux/stackvalidate.h | 21 +++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 arch/x86/include/asm/stackvalidate.h create mode 100644 include/linux/stackvalidate.h diff --git a/arch/x86/include/asm/stackvalidate.h b/arch/x86/include/asm/stackvalidate.h new file mode 100644 index 0000000..2d23c23 --- /dev/null +++ b/arch/x86/include/asm/stackvalidate.h @@ -0,0 +1,28 @@ +#ifndef _ASM_X86_STACKVALIDATE_H +#define _ASM_X86_STACKVALIDATE_H + +#include <asm/asm.h> + +#ifdef __ASSEMBLY__ + +/* + * This asm macro tells the stack validation script to ignore the instruction + * immediately after the macro. It should only be used in special cases where + * you're 100% sure it won't affect the reliability of frame pointers and + * kernel stack traces. + * + * For more information, see Documentation/stack-validation.txt. + */ +.macro STACKVALIDATE_IGNORE_INSN + .if CONFIG_STACK_VALIDATION + .Ltemp_\@: + .pushsection __stackvalidate_ignore_insn, "a" + _ASM_ALIGN + .long .Ltemp_\@ - . + .popsection + .endif +.endm + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_X86_STACKVALIDATE_H */ diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 00bf300..f2f8d7a 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -332,7 +332,10 @@ SECTIONS /* Sections to be discarded */ DISCARDS - /DISCARD/ : { *(.eh_frame) } + /DISCARD/ : { + *(.eh_frame) + *(__stackvalidate_ignore_*) + } } diff --git a/include/linux/stackvalidate.h b/include/linux/stackvalidate.h new file mode 100644 index 0000000..5cc5c97 --- /dev/null +++ b/include/linux/stackvalidate.h @@ -0,0 +1,21 @@ +#ifndef _LINUX_STACKVALIDATE_H +#define _LINUX_STACKVALIDATE_H + +#include <asm/stackvalidate.h> + +#ifndef __ASSEMBLY__ + +/* + * This C macro tells the stack validation script to ignore the function. It + * should only be used in special cases where you're 100% sure it won't affect + * the reliability of frame pointers and kernel stack traces. + * + * For more information, see Documentation/stack-validation.txt. + */ +#define STACKVALIDATE_IGNORE_FUNC(_func) \ + static void __used __section(__stackvalidate_ignore_func) \ + *__stackvalidate_ignore_func_##_func = _func + +#endif /* !__ASSEMBLY__ */ + +#endif /* _LINUX_STACKVALIDATE_H */ -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* Re: [PATCH v7 0/4] Compile-time stack validation 2015-07-14 17:14 [PATCH v7 0/4] Compile-time stack validation Josh Poimboeuf ` (3 preceding siblings ...) 2015-07-14 17:14 ` [PATCH v7 4/4] x86/stackvalidate: Add ignore macros Josh Poimboeuf @ 2015-07-14 17:25 ` Josh Poimboeuf 2015-07-15 10:16 ` Ingo Molnar 4 siblings, 1 reply; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-14 17:25 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel On Tue, Jul 14, 2015 at 12:14:06PM -0500, Josh Poimboeuf wrote: > Posting a listing of reported warnings in a reply to this email. These are the reported stackvalidate warnings on tip/master with my Fedora-based config. There were 1399 warnings in 26 .c files and 16 .S files. It was mostly repeat warnings so I removed a lot of the repeats to keep it short. stackvalidate: arch/x86/crypto/aesni-intel_asm.o: aesni_set_key()+0x128: call without frame pointer save/setup ...removed 29 lines... stackvalidate: arch/x86/crypto/aesni-intel_asm.o: aesni_set_key()+0xb9: call without frame pointer save/setup stackvalidate: arch/x86/crypto/aesni-intel_asm.o: aesni_enc()+0xa: call without frame pointer save/setup stackvalidate: arch/x86/crypto/aesni-intel_asm.o: aesni_dec()+0x11: call without frame pointer save/setup stackvalidate: arch/x86/crypto/aesni-intel_asm.o: aesni_ecb_enc()+0x57: call without frame pointer save/setup ...removed 5 lines... stackvalidate: arch/x86/crypto/aesni-intel_asm.o: aesni_cbc_dec()+0x43: call without frame pointer save/setup stackvalidate: arch/x86/crypto/aesni-intel_asm.o: _aesni_inc_init(): can't find starting instruction stackvalidate: arch/x86/crypto/aesni-intel_asm.o: aesni_ctr_enc()+0x15: call without frame pointer save/setup ...removed 6 lines... stackvalidate: arch/x86/crypto/aesni-intel_asm.o: aesni_ctr_enc()+0x51: call without frame pointer save/setup stackvalidate: arch/x86/crypto/aesni-intel_asm.o: aesni_xts_crypt8()+0xda: call without frame pointer save/setup stackvalidate: arch/x86/crypto/aesni-intel_asm.o: aesni_xts_crypt8()+0x1f1: call without frame pointer save/setup stackvalidate: arch/x86/crypto/aesni-intel_asm.o: _aesni_inc_init()+0x24: return instruction outside of a callable function stackvalidate: arch/x86/crypto/ghash-clmulni-intel_asm.o: clmul_ghash_mul()+0x13: call without frame pointer save/setup stackvalidate: arch/x86/crypto/ghash-clmulni-intel_asm.o: clmul_ghash_update()+0x28: call without frame pointer save/setup stackvalidate: arch/x86/crypto/crc32c-pcl-intel-asm_64.o: crc_pcl()+0x11dd: can't decode instruction stackvalidate: arch/x86/entry/entry_64.o: native_usergs_sysret64()+0x3: kernel entry/exit from callable instruction stackvalidate: arch/x86/entry/entry_64.o: .entry.text+0x329: return instruction outside of a callable function stackvalidate: arch/x86/entry/entry_64.o: .entry.text+0x1fe9: return instruction outside of a callable function stackvalidate: arch/x86/entry/entry_64.o: .entry.text+0x2015: return instruction outside of a callable function stackvalidate: arch/x86/entry/entry_64.o: .entry.text+0x2514: return instruction outside of a callable function stackvalidate: arch/x86/entry/entry_64.o: .entry.text+0x2628: return instruction outside of a callable function stackvalidate: arch/x86/entry/thunk_64.o: .text+0x53: return instruction outside of a callable function stackvalidate: arch/x86/entry/entry_64_compat.o: native_usergs_sysret32()+0x3: kernel entry/exit from callable instruction stackvalidate: arch/x86/entry/entry_64_compat.o: entry_SYSENTER_compat()+0xd: call without frame pointer save/setup stackvalidate: arch/x86/entry/entry_64_compat.o: .entry.text+0x45f: sibling call from callable instruction with changed frame pointer stackvalidate: arch/x86/entry/entry_64_compat.o: .entry.text+0x487: sibling call from callable instruction with changed frame pointer stackvalidate: arch/x86/entry/entry_64_compat.o: entry_SYSENTER_compat()+0xd7: sibling call from callable instruction with changed frame pointer stackvalidate: arch/x86/entry/entry_64_compat.o: entry_SYSENTER_compat()+0x179: sibling call from callable instruction with changed frame pointer stackvalidate: arch/x86/entry/entry_64_compat.o: .entry.text+0x5de: return instruction outside of a callable function stackvalidate: arch/x86/kernel/mcount_64.o: .entry.text+0x0: return instruction outside of a callable function stackvalidate: arch/x86/kernel/mcount_64.o: .entry.text+0xbb: return instruction outside of a callable function stackvalidate: arch/x86/kernel/mcount_64.o: .entry.text+0x2b7: return instruction outside of a callable function stackvalidate: arch/x86/kernel/tsc.o: unsynchronized_tsc()+0x5f: call without frame pointer save/setup stackvalidate: arch/x86/kernel/process.o: set_tsc_mode()+0x55: call without frame pointer save/setup stackvalidate: arch/x86/kernel/acpi/wakeup_64.o: do_suspend_lowlevel()+0x6: call without frame pointer save/setup stackvalidate: arch/x86/kernel/acpi/wakeup_64.o: do_suspend_lowlevel()+0x95: call without frame pointer save/setup stackvalidate: arch/x86/kernel/cpu/common.o: debug_stack_reset()+0x70: call without frame pointer save/setup stackvalidate: arch/x86/kernel/cpu/common.o: debug_stack_reset()+0x61: call without frame pointer save/setup stackvalidate: arch/x86/kernel/cpu/common.o: debug_stack_reset()+0x31: call without frame pointer save/setup stackvalidate: arch/x86/kernel/cpu/amd.o: .text+0x0: return instruction outside of a callable function stackvalidate: arch/x86/kernel/cpu/mcheck/mce.o: mce_wrmsrl.constprop.30()+0x3f: call without frame pointer save/setup stackvalidate: arch/x86/kernel/kprobes/core.o: kretprobe_trampoline_holder()+0x1d: duplicate frame pointer save stackvalidate: arch/x86/kernel/kprobes/core.o: kprobe_exceptions_notify()+0x2d: call without frame pointer save/setup stackvalidate: arch/x86/kernel/kprobes/core.o: kretprobe_trampoline_holder()+0x53: function has unreachable instruction stackvalidate: arch/x86/kernel/kprobes/core.o: kretprobe_trampoline_holder()+0x54: function has unreachable instruction stackvalidate: arch/x86/kernel/reboot.o: machine_real_restart()+0x5d: sibling call from callable instruction with changed frame pointer stackvalidate: arch/x86/kernel/relocate_kernel_64.o: .text+0xd6: can't find call dest symbol at offset 0xdb stackvalidate: arch/x86/kernel/paravirt.o: paravirt_end_context_switch()+0x3f: call without frame pointer save/setup stackvalidate: arch/x86/kernel/paravirt.o: paravirt_end_context_switch()+0x37: call without frame pointer save/setup stackvalidate: arch/x86/kernel/vsmp_64.o: .text+0x1d: return instruction outside of a callable function stackvalidate: arch/x86/kernel/vsmp_64.o: .text+0x3b: return instruction outside of a callable function stackvalidate: arch/x86/kernel/vsmp_64.o: .text+0x59: return instruction outside of a callable function stackvalidate: arch/x86/kernel/vsmp_64.o: .text+0x77: return instruction outside of a callable function stackvalidate: arch/x86/kernel/head_64.o: .text: unexpected end of section stackvalidate: arch/x86/kernel/head_64.o: start_cpu0()+0x13: kernel entry/exit from callable instruction stackvalidate: arch/x86/kernel/head_64.o: early_idt_handler_common()+0x59: call without frame pointer save/setup ...removed 5 lines... stackvalidate: arch/x86/kernel/head_64.o: early_idt_handler_common()+0x42: call without frame pointer save/setup stackvalidate: arch/x86/kernel/head_64.o: early_idt_handler_array()+0x9: function has unreachable instruction ...removed 140 lines... stackvalidate: arch/x86/kernel/head_64.o: early_idt_handler_array()+0x11f: function has unreachable instruction stackvalidate: arch/x86/mm/tlb.o: leave_mm()+0x5c: call without frame pointer save/setup stackvalidate: arch/x86/mm/tlb.o: do_flush_tlb_all()+0x25: call without frame pointer save/setup stackvalidate: arch/x86/mm/tlb.o: do_flush_tlb_all()+0x11: call without frame pointer save/setup stackvalidate: arch/x86/net/bpf_jit.o: .text+0x18: return instruction outside of a callable function ...removed 8 lines... stackvalidate: arch/x86/net/bpf_jit.o: .text+0x16d: return instruction outside of a callable function stackvalidate: arch/x86/platform/efi/efi_stub_64.o: efi_call()+0x7c: call without frame pointer save/setup stackvalidate: arch/x86/platform/uv/tlb_uv.o: ptc_seq_next()+0x1e: call without frame pointer save/setup stackvalidate: arch/x86/xen/enlighten.o: xen_cpuid()+0x41: can't find jump dest instruction at .text+0x108 stackvalidate: arch/x86/xen/mmu.o: .text+0x1d: return instruction outside of a callable function ...removed 6 lines... stackvalidate: arch/x86/xen/mmu.o: .text+0xef: return instruction outside of a callable function stackvalidate: arch/x86/xen/irq.o: xen_halt()+0x0: call without frame pointer save/setup stackvalidate: arch/x86/xen/irq.o: xen_halt()+0x1d: call without frame pointer save/setup stackvalidate: arch/x86/xen/irq.o: .text+0x1d: return instruction outside of a callable function stackvalidate: arch/x86/xen/irq.o: .text+0x3b: return instruction outside of a callable function stackvalidate: arch/x86/xen/irq.o: .text+0x59: return instruction outside of a callable function stackvalidate: arch/x86/xen/irq.o: .text+0x77: return instruction outside of a callable function stackvalidate: arch/x86/xen/time.o: xen_vcpuop_set_mode()+0x36: call without frame pointer save/setup stackvalidate: arch/x86/xen/time.o: xen_vcpuop_set_mode()+0x49: call without frame pointer save/setup stackvalidate: arch/x86/xen/time.o: xen_vcpuop_set_mode()+0x1d: call without frame pointer save/setup stackvalidate: arch/x86/xen/time.o: xen_timerop_set_mode()+0x26: call without frame pointer save/setup stackvalidate: arch/x86/xen/xen-asm.o: .text+0x7f: return instruction outside of a callable function stackvalidate: arch/x86/xen/xen-asm_64.o: .text+0xa: return instruction outside of a callable function stackvalidate: kernel/softirq.o: __tasklet_hi_schedule_first()+0x5: call without frame pointer save/setup stackvalidate: kernel/bpf/core.o: __bpf_prog_run()+0x5c: sibling call from callable instruction with changed frame pointer stackvalidate: kernel/bpf/core.o: __bpf_prog_run()+0x60: function has unreachable instruction ...removed 1092 lines... stackvalidate: kernel/bpf/core.o: __bpf_prog_run()+0x12dc: function has unreachable instruction stackvalidate: kernel/locking/lockdep.o: trace_hardirqs_off_caller()+0x31: call without frame pointer save/setup stackvalidate: kernel/sched/core.o: __schedule()+0x3e7: duplicate frame pointer save stackvalidate: kernel/sched/core.o: __schedule()+0x424: sibling call from callable instruction with changed frame pointer stackvalidate: kernel/sched/core.o: __schedule()+0x431: call without frame pointer save/setup stackvalidate: kernel/sched/core.o: __schedule()+0x8b8: frame pointer state mismatch stackvalidate: kernel/sched/core.o: __schedule()+0x447: frame pointer state mismatch stackvalidate: kernel/sched/core.o: preempt_schedule_irq()+0x17: call without frame pointer save/setup stackvalidate: kernel/sched/rt.o: set_cpus_allowed_rt()+0x1b: call without frame pointer save/setup stackvalidate: kernel/irq_work.o: irq_work_run_list()+0x0: call without frame pointer save/setup stackvalidate: mm/slub.o: check_slab()+0x5: call without frame pointer save/setup stackvalidate: mm/huge_memory.o: split_huge_page_address()+0x30: call without frame pointer save/setup stackvalidate: mm/huge_memory.o: split_huge_page_address()+0x6d: call without frame pointer save/setup stackvalidate: fs/buffer.o: __find_get_block()+0x5: call without frame pointer save/setup stackvalidate: drivers/xen/sys-hypervisor.o: pagesize_show()+0xf: call without frame pointer save/setup stackvalidate: drivers/xen/sys-hypervisor.o: minor_show()+0xc: call without frame pointer save/setup stackvalidate: drivers/xen/sys-hypervisor.o: major_show()+0xc: call without frame pointer save/setup stackvalidate: arch/x86/power/hibernate_asm_64.o: .text+0x69: return instruction outside of a callable function stackvalidate: arch/x86/power/hibernate_asm_64.o: .text+0x16d: return instruction outside of a callable function stackvalidate: lib/percpu_counter.o: __percpu_counter_compare()+0x1e: call without frame pointer save/setup stackvalidate: arch/x86/lib/rwsem.o: call_rwsem_down_read_failed()+0xf: call without frame pointer save/setup stackvalidate: arch/x86/lib/rwsem.o: call_rwsem_down_write_failed()+0xe: call without frame pointer save/setup stackvalidate: arch/x86/lib/rwsem.o: call_rwsem_wake()+0x12: call without frame pointer save/setup stackvalidate: arch/x86/lib/rwsem.o: call_rwsem_downgrade_wake()+0xf: call without frame pointer save/setup -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [PATCH v7 0/4] Compile-time stack validation 2015-07-14 17:25 ` [PATCH v7 0/4] Compile-time stack validation Josh Poimboeuf @ 2015-07-15 10:16 ` Ingo Molnar 2015-07-15 16:05 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf 0 siblings, 2 replies; 89+ messages in thread From: Ingo Molnar @ 2015-07-15 10:16 UTC (permalink / raw) To: Josh Poimboeuf Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > On Tue, Jul 14, 2015 at 12:14:06PM -0500, Josh Poimboeuf wrote: > > Posting a listing of reported warnings in a reply to this email. > > These are the reported stackvalidate warnings on tip/master with my Fedora-based > config. There were 1399 warnings in 26 .c files and 16 .S files. It was mostly > repeat warnings so I removed a lot of the repeats to keep it short. Are most of these warnings legit, what's the false positive rate in your impression? You might want to start fixing a few typical types, just to see what it involves exactly and whether we want to fix it that way. Thanks, Ingo ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [PATCH v7 0/4] Compile-time stack validation 2015-07-15 10:16 ` Ingo Molnar @ 2015-07-15 16:05 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf 1 sibling, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-15 16:05 UTC (permalink / raw) To: Ingo Molnar Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel On Wed, Jul 15, 2015 at 12:16:28PM +0200, Ingo Molnar wrote: > > * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > > > On Tue, Jul 14, 2015 at 12:14:06PM -0500, Josh Poimboeuf wrote: > > > Posting a listing of reported warnings in a reply to this email. > > > > These are the reported stackvalidate warnings on tip/master with my Fedora-based > > config. There were 1399 warnings in 26 .c files and 16 .S files. It was mostly > > repeat warnings so I removed a lot of the repeats to keep it short. > > Are most of these warnings legit, what's the false positive rate in your > impression? Examining the warnings per-file (since that's a much easier analysis than per-warning): Of the 26 .c files: - 21 have real frame pointer bugs, most of them caused by a handful of inline asm() macros - 5 have false positives (but several of these have questionable usage of asm() which might be convertible to C code) Of the 16 .S files: - 12 have real frame pointer bugs*, typically caused by not having FRAME/ENDFRAME (note: many of these files also have false positive warnings) - 4 have no bugs and only false positives Most of the false positives in the .S files are actually incorrect ELF annotations. I still consider them false positives because they're not "real" bugs, per se. But they're still fixable. Overall I think there will end up being only be a handful of locations that need to use one of the whitelist macros (STACKVALIDATE_IGNORE_{INSN,FILE}). > You might want to start fixing a few typical types, just to see what it involves > exactly and whether we want to fix it that way. I already have a good idea of what needs to be done for most of the warnings. I'll post some patches and try to give a representive sampling of what the different types of fixes look like. [*] But note that the definition of a frame pointer bug is open to interpretation, especially for "special" asm code like suspend, hibernate, relocate, reboot, ftrace, bpf, entry code, etc. In general, when looking at whether frame pointers are needed, I asked myself "what would gcc do?" -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings 2015-07-15 10:16 ` Ingo Molnar 2015-07-15 16:05 ` Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 01/21] stackvalidate: Process ignores earlier and add more ignore checks Josh Poimboeuf ` (21 more replies) 1 sibling, 22 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel These patches fix many of the warnings reported by stackvalidate. They're based on top of the "Compile-time stack validation" v7 patch set [1]. They've been compile-tested and boot tested in a VM, but I haven't attempted any meaningful testing for most of them. This should give an idea of what kinds of changes I think are needed. [1] https://lkml.kernel.org/r/cover.1436893563.git.jpoimboe@redhat.com Josh Poimboeuf (21): stackvalidate: Process ignores earlier and add more ignore checks stackvalidate: Add C version of STACKVALIDATE_IGNORE_INSN x86/asm: Add C versions of FRAME and ENDFRAME macros x86/hweight: Add stack frame dependency for __arch_hweight*() x86/xen: Add stack frame dependency to hypercall inline asm calls x86/paravirt: Add stack frame dependency to PVOP inline asm calls x86/paravirt: Fix frame pointer usage in PV_CALLEE_SAVE_REGS_THUNK x86/paravirt: Align paravirt thunk functions at 16-byte boundaries x86/amd: Set ELF function type for vide() x86/reboot: Add ljmp instructions to stackvalidate whitelist x86/xen: Add xen_cpuid() and xen_setup_gdt() to stackvalidate whitelists sched: Add __schedule() to stackvalidate whitelist x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S x86/asm/crypto: Move .Lbswap_mask data to .rodata section x86/asm/crypto: Move jump_table to .rodata section x86/asm/crypto: Fix frame pointer usage in clmul_ghash_mul/update() x86/asm/entry: Fix frame pointer usage in thunk functions x86/asm/acpi: Fix frame pointer usage in do_suspend_lowlevel() x86/asm: Fix frame pointer usage in rwsem functions x86/asm/efi: Fix frame pointer usage in efi_call() x86/asm/power: Fix frame pointer usage in hibernate_asm_64.S arch/x86/crypto/aesni-intel_asm.S | 21 +++++++++ arch/x86/crypto/crc32c-pcl-intel-asm_64.S | 8 ++-- arch/x86/crypto/ghash-clmulni-intel_asm.S | 5 ++ arch/x86/entry/thunk_64.S | 4 ++ arch/x86/include/asm/arch_hweight.h | 6 ++- arch/x86/include/asm/frame.h | 20 +++++++- arch/x86/include/asm/paravirt.h | 10 +++- arch/x86/include/asm/paravirt_types.h | 18 ++++---- arch/x86/include/asm/stackvalidate.h | 9 ++++ arch/x86/include/asm/xen/hypercall.h | 5 +- arch/x86/kernel/acpi/wakeup_64.S | 3 ++ arch/x86/kernel/cpu/amd.c | 5 +- arch/x86/kernel/reboot.c | 7 ++- arch/x86/lib/rwsem.S | 11 ++++- arch/x86/platform/efi/efi_stub_64.S | 3 ++ arch/x86/power/hibernate_asm_64.S | 7 +++ arch/x86/xen/enlighten.c | 4 +- kernel/sched/core.c | 2 + scripts/stackvalidate/stackvalidate.c | 77 ++++++++++++++++++++++--------- 19 files changed, 179 insertions(+), 46 deletions(-) -- 2.1.0 ^ permalink raw reply [flat|nested] 89+ messages in thread
* [RFC PATCH 01/21] stackvalidate: Process ignores earlier and add more ignore checks 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 02/21] stackvalidate: Add C version of STACKVALIDATE_IGNORE_INSN Josh Poimboeuf ` (20 subsequent siblings) 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel Process the ignore macros earlier and associate them with their corresponding instructions. This allows ignores to be checked in get_jump_destinations() which is needed for some funky xen code which introduces fake instructions (XEN_EMULATE_PREFIX). Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- scripts/stackvalidate/stackvalidate.c | 77 +++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 21 deletions(-) diff --git a/scripts/stackvalidate/stackvalidate.c b/scripts/stackvalidate/stackvalidate.c index a817130..6173412 100644 --- a/scripts/stackvalidate/stackvalidate.c +++ b/scripts/stackvalidate/stackvalidate.c @@ -49,7 +49,7 @@ struct instruction { unsigned int len, state; unsigned char type; unsigned long immediate; - bool alt_group, visited; + bool alt_group, visited, ignore; struct symbol *call_dest; struct instruction *jump_dest; struct list_head alts; @@ -106,8 +106,7 @@ static struct argp argp = { options, parse_opt, args_doc, 0 }; /* * Check for the STACKVALIDATE_IGNORE_INSN macro. */ -static bool ignore_insn(struct elf *elf, struct section *sec, - unsigned long offset) +static bool ignore_insn(struct elf *elf, struct instruction *insn) { struct section *macro_sec; struct rela *rela; @@ -118,8 +117,8 @@ static bool ignore_insn(struct elf *elf, struct section *sec, list_for_each_entry(rela, ¯o_sec->rela->relas, list) if (rela->sym->type == STT_SECTION && - rela->sym == sec->sym && - rela->addend == offset) + rela->sym == insn->sec->sym && + rela->addend == insn->offset) return true; return false; @@ -138,9 +137,11 @@ static bool ignore_func(struct elf *elf, struct symbol *func) return false; list_for_each_entry(rela, ¯o_sec->rela->relas, list) - if (rela->sym == func) + if (rela->sym->sec == func->sec && + rela->addend == func->offset) return true; + return false; } @@ -266,6 +267,44 @@ static int decode_instructions(struct elf *elf) } /* + * Warnings shouldn't be reported for ignored instructions. Set insn->ignore + * for each ignored instruction and each instruction contained in an ignored + * function. + */ +static void get_ignores(struct elf *elf) +{ + struct instruction *insn; + struct section *sec; + struct symbol *func; + + list_for_each_entry(insn, &insns, list) + insn->ignore = ignore_insn(elf, insn); + + list_for_each_entry(sec, &elf->sections, list) { + list_for_each_entry(func, &sec->symbols, list) { + if (func->type != STT_FUNC) + continue; + + if (!ignore_func(elf, func)) + continue; + + insn = find_instruction(sec, func->offset); + if (!insn) + continue; + + list_for_each_entry_from(insn, &insns, list) { + if (insn->sec != func->sec || + insn->offset >= func->offset + func->len) + break; + + insn->ignore = true; + insn->visited = true; + } + } + } +} + +/* * Find the destination instructions for all jumps. */ static int get_jump_destinations(struct elf *elf) @@ -300,7 +339,7 @@ static int get_jump_destinations(struct elf *elf) } insn->jump_dest = find_instruction(dest_sec, dest_off); - if (!insn->jump_dest) { + if (!insn->jump_dest && !insn->ignore) { /* * This is a special case where an alt instruction @@ -591,6 +630,8 @@ static int decode_sections(struct elf *elf) if (ret) return ret; + get_ignores(elf); + ret = get_jump_destinations(elf); if (ret) return ret; @@ -734,7 +775,8 @@ static int validate_branch(struct elf *elf, struct instruction *first, break; case INSN_JUMP_DYNAMIC: - if (list_empty(&insn->alts) && insn->state) { + if (list_empty(&insn->alts) && insn->state && + !insn->ignore) { WARN("%s: sibling call from callable instruction with changed frame pointer", offstr(sec, insn->offset)); warnings++; @@ -743,9 +785,11 @@ static int validate_branch(struct elf *elf, struct instruction *first, return warnings; case INSN_CONTEXT_SWITCH: - WARN("%s: kernel entry/exit from callable instruction", - offstr(sec, insn->offset)); - warnings++; + if (!insn->ignore) { + WARN("%s: kernel entry/exit from callable instruction", + offstr(sec, insn->offset)); + warnings++; + } return warnings; @@ -786,15 +830,6 @@ static int validate_functions(struct elf *elf) continue; } - if (ignore_func(elf, func)) { - list_for_each_entry_from(insn, &insns, list) { - if (insn->sec != func->sec || - insn->offset >= func->offset + func->len) - break; - insn->visited = true; - } - } - ret = validate_branch(elf, insn, 0); warnings += ret; } @@ -835,7 +870,7 @@ static int validate_uncallable_instructions(struct elf *elf) list_for_each_entry(insn, &insns, list) { if (!insn->visited && insn->type == INSN_RETURN && - !ignore_insn(elf, insn->sec, insn->offset)) { + !insn->ignore) { WARN("%s: return instruction outside of a callable function", offstr(insn->sec, insn->offset)); warnings++; -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [RFC PATCH 02/21] stackvalidate: Add C version of STACKVALIDATE_IGNORE_INSN 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 01/21] stackvalidate: Process ignores earlier and add more ignore checks Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-18 14:56 ` Borislav Petkov [not found] ` <CA+55aFyoO75n-mQBrB_YBLx9yNpAjisFAqkO8+YsphD-xmgY+w@mail.gmail.com> 2015-07-17 16:47 ` [RFC PATCH 03/21] x86/asm: Add C versions of FRAME and ENDFRAME macros Josh Poimboeuf ` (19 subsequent siblings) 21 siblings, 2 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel Add a C inline asm string version of the STACKVALIDATE_IGNORE_INSN macro which tells stackvalidate to ignore the subsequent instruction. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/include/asm/stackvalidate.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/x86/include/asm/stackvalidate.h b/arch/x86/include/asm/stackvalidate.h index 2d23c23..dac935c 100644 --- a/arch/x86/include/asm/stackvalidate.h +++ b/arch/x86/include/asm/stackvalidate.h @@ -23,6 +23,15 @@ .endif .endm +#else /* !__ASSEMBLY__ */ + +#define STACKVALIDATE_IGNORE_INSN \ + ".Ltemp" __stringify(__LINE__) ":;" \ + ".pushsection __stackvalidate_ignore_insn, \"a\";" \ + _ASM_ALIGN ";" \ + ".long .Ltemp" __stringify(__LINE__) " - .;" \ + ".popsection;" + #endif /* __ASSEMBLY__ */ #endif /* _ASM_X86_STACKVALIDATE_H */ -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 02/21] stackvalidate: Add C version of STACKVALIDATE_IGNORE_INSN 2015-07-17 16:47 ` [RFC PATCH 02/21] stackvalidate: Add C version of STACKVALIDATE_IGNORE_INSN Josh Poimboeuf @ 2015-07-18 14:56 ` Borislav Petkov 2015-07-18 16:00 ` Josh Poimboeuf [not found] ` <CA+55aFyoO75n-mQBrB_YBLx9yNpAjisFAqkO8+YsphD-xmgY+w@mail.gmail.com> 1 sibling, 1 reply; 89+ messages in thread From: Borislav Petkov @ 2015-07-18 14:56 UTC (permalink / raw) To: Josh Poimboeuf Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel On Fri, Jul 17, 2015 at 11:47:18AM -0500, Josh Poimboeuf wrote: > Add a C inline asm string version of the STACKVALIDATE_IGNORE_INSN macro > which tells stackvalidate to ignore the subsequent instruction. > > Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> > --- > arch/x86/include/asm/stackvalidate.h | 9 +++++++++ > 1 file changed, 9 insertions(+) > > diff --git a/arch/x86/include/asm/stackvalidate.h b/arch/x86/include/asm/stackvalidate.h > index 2d23c23..dac935c 100644 > --- a/arch/x86/include/asm/stackvalidate.h > +++ b/arch/x86/include/asm/stackvalidate.h > @@ -23,6 +23,15 @@ > .endif > .endm > > +#else /* !__ASSEMBLY__ */ > + #ifdef CONFIG_STACK_VALIDATION > +#define STACKVALIDATE_IGNORE_INSN \ > + ".Ltemp" __stringify(__LINE__) ":;" \ > + ".pushsection __stackvalidate_ignore_insn, \"a\";" \ > + _ASM_ALIGN ";" \ > + ".long .Ltemp" __stringify(__LINE__) " - .;" \ > + ".popsection;" > + #endif Also, you should end your lines with "\n" so that the .s output looks a bit more readable, not like now: #APP # 30 "./arch/x86/include/asm/arch_hweight.h" 1 661: .Ltemp32:;.pushsection __stackvalidate_ignore_insn, "a"; .balign 8 ;.long .Ltemp32 - .;.popsection;call __sw_hweight32 662: -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply. -- ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 02/21] stackvalidate: Add C version of STACKVALIDATE_IGNORE_INSN 2015-07-18 14:56 ` Borislav Petkov @ 2015-07-18 16:00 ` Josh Poimboeuf 0 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-18 16:00 UTC (permalink / raw) To: Borislav Petkov Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel On Sat, Jul 18, 2015 at 04:56:54PM +0200, Borislav Petkov wrote: > On Fri, Jul 17, 2015 at 11:47:18AM -0500, Josh Poimboeuf wrote: > > Add a C inline asm string version of the STACKVALIDATE_IGNORE_INSN macro > > which tells stackvalidate to ignore the subsequent instruction. > > > > Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> > > --- > > arch/x86/include/asm/stackvalidate.h | 9 +++++++++ > > 1 file changed, 9 insertions(+) > > > > diff --git a/arch/x86/include/asm/stackvalidate.h b/arch/x86/include/asm/stackvalidate.h > > index 2d23c23..dac935c 100644 > > --- a/arch/x86/include/asm/stackvalidate.h > > +++ b/arch/x86/include/asm/stackvalidate.h > > @@ -23,6 +23,15 @@ > > .endif > > .endm > > > > +#else /* !__ASSEMBLY__ */ > > + > > #ifdef CONFIG_STACK_VALIDATION > > > +#define STACKVALIDATE_IGNORE_INSN \ > > + ".Ltemp" __stringify(__LINE__) ":;" \ > > + ".pushsection __stackvalidate_ignore_insn, \"a\";" \ > > + _ASM_ALIGN ";" \ > > + ".long .Ltemp" __stringify(__LINE__) " - .;" \ > > + ".popsection;" > > + > > #endif > > > Also, you should end your lines with "\n" so that the .s output looks > a bit more readable, not like now: > > #APP > # 30 "./arch/x86/include/asm/arch_hweight.h" 1 > 661: > .Ltemp32:;.pushsection __stackvalidate_ignore_insn, "a"; .balign 8 ;.long .Ltemp32 - .;.popsection;call __sw_hweight32 > 662: Ok, will fix both issues. Thanks. -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
[parent not found: <CA+55aFyoO75n-mQBrB_YBLx9yNpAjisFAqkO8+YsphD-xmgY+w@mail.gmail.com>]
* Re: [RFC PATCH 02/21] stackvalidate: Add C version of STACKVALIDATE_IGNORE_INSN [not found] ` <CA+55aFyoO75n-mQBrB_YBLx9yNpAjisFAqkO8+YsphD-xmgY+w@mail.gmail.com> @ 2015-07-18 16:40 ` Josh Poimboeuf 0 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-18 16:40 UTC (permalink / raw) To: Linus Torvalds Cc: Michal Marek, Thomas Gleixner, Ingo Molnar, Borislav Petkov, linux-kernel, Andi Kleen, Andy Lutomirski, Pedro Alves, live-patching, x86, H. Peter Anvin, Peter Zijlstra On Sat, Jul 18, 2015 at 09:16:58AM -0700, Linus Torvalds wrote: > On Jul 17, 2015 09:57, "Josh Poimboeuf" <jpoimboe@redhat.com> wrote: > > > > + > > +#define STACKVALIDATE_IGNORE_INSN \ > > + ".Ltemp" __stringify(__LINE__) ":;" \ > > This is wrong. It won't work for people who do multiple of these on the > same line (think macros etc). > > For temporary labels, you should just use numeric labels. Think Pascal > style ones. Then use "b" or "f" after the number when referring to it to > say "back" or "forward" reference. > > So the code for an endless loop with a true temporary label looks like: > > 1: code > jmp 1b > > and a branch over would look like > > jne 7f > .. code ... > 7: ... > > and now you can have multiple of these truly temp labels without ever > getting errors from having a label redefined. Yeah, I think I'll change the C macro to do that. However for asm macros you have to worry about collisions. For example: .macro FOO 1: ... .endm 1: ... FOO jmp 1b It would jump to "1" in the macro instead of the "1" before the macro. So for the asm version of the macro I ended up using Andy's idea of using "\@" to get a unique identifier: .macro STACKVALIDATE_IGNORE_INSN .if CONFIG_STACK_VALIDATION .Ltemp_\@: .pushsection __stackvalidate_ignore_insn, "a" _ASM_ALIGN .long .Ltemp_\@ - . .popsection .endif .endm -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* [RFC PATCH 03/21] x86/asm: Add C versions of FRAME and ENDFRAME macros 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 01/21] stackvalidate: Process ignores earlier and add more ignore checks Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 02/21] stackvalidate: Add C version of STACKVALIDATE_IGNORE_INSN Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 04/21] x86/hweight: Add stack frame dependency for __arch_hweight*() Josh Poimboeuf ` (18 subsequent siblings) 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel Add C versions of the FRAME and ENDFRAME macros which can be used to create a stack frame in inline assembly. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/include/asm/frame.h | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/frame.h b/arch/x86/include/asm/frame.h index a9438cd..bfe96e3 100644 --- a/arch/x86/include/asm/frame.h +++ b/arch/x86/include/asm/frame.h @@ -1,10 +1,10 @@ #ifndef _ASM_X86_FRAME_H #define _ASM_X86_FRAME_H -#ifdef __ASSEMBLY__ - #include <asm/asm.h> +#ifdef __ASSEMBLY__ + /* * These are stack frame creation macros. They should be used by every * callable non-leaf asm function to make kernel stack traces more reliable. @@ -22,5 +22,21 @@ .endif .endm +#else /* !__ASSEMBLY__ */ + +#ifdef CONFIG_FRAME_POINTER + +#define FRAME \ + "push %" _ASM_BP ";" \ + _ASM_MOV "%" _ASM_SP ", %" _ASM_BP ";" + +#define ENDFRAME "pop %" _ASM_BP ";" + +#else /* !CONFIG_FRAME_POINTER */ + +#define FRAME "" +#define ENDFRAME "" + +#endif /* CONFIG_FRAME_POINTER */ #endif /* __ASSEMBLY__ */ #endif /* _ASM_X86_FRAME_H */ -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [RFC PATCH 04/21] x86/hweight: Add stack frame dependency for __arch_hweight*() 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (2 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 03/21] x86/asm: Add C versions of FRAME and ENDFRAME macros Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 17:17 ` Borislav Petkov 2015-07-17 16:47 ` [RFC PATCH 05/21] x86/xen: Add stack frame dependency to hypercall inline asm calls Josh Poimboeuf ` (17 subsequent siblings) 21 siblings, 1 reply; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel If __arch_hweight32() or __arch_hweight64() is inlined at the beginning of a function, gcc can insert the call instruction before setting up a stack frame, which breaks frame pointer convention if CONFIG_FRAME_POINTER is enabled and can result in a bad stack trace. Force a stack frame to be created if CONFIG_FRAME_POINTER is enabled by listing the stack pointer as an output operand for the inline asm statement. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/include/asm/arch_hweight.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/arch_hweight.h b/arch/x86/include/asm/arch_hweight.h index 9686c3d..e438a0d 100644 --- a/arch/x86/include/asm/arch_hweight.h +++ b/arch/x86/include/asm/arch_hweight.h @@ -23,10 +23,11 @@ */ static inline unsigned int __arch_hweight32(unsigned int w) { + register void *__sp asm("esp"); unsigned int res = 0; asm (ALTERNATIVE("call __sw_hweight32", POPCNT32, X86_FEATURE_POPCNT) - : "="REG_OUT (res) + : "="REG_OUT (res), "+r" (__sp) : REG_IN (w)); return res; @@ -44,6 +45,7 @@ static inline unsigned int __arch_hweight8(unsigned int w) static inline unsigned long __arch_hweight64(__u64 w) { + register void __maybe_unused *__sp asm("rsp"); unsigned long res = 0; #ifdef CONFIG_X86_32 @@ -51,7 +53,7 @@ static inline unsigned long __arch_hweight64(__u64 w) __arch_hweight32((u32)(w >> 32)); #else asm (ALTERNATIVE("call __sw_hweight64", POPCNT64, X86_FEATURE_POPCNT) - : "="REG_OUT (res) + : "="REG_OUT (res), "+r" (__sp) : REG_IN (w)); #endif /* CONFIG_X86_32 */ -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 04/21] x86/hweight: Add stack frame dependency for __arch_hweight*() 2015-07-17 16:47 ` [RFC PATCH 04/21] x86/hweight: Add stack frame dependency for __arch_hweight*() Josh Poimboeuf @ 2015-07-17 17:17 ` Borislav Petkov 2015-07-17 17:32 ` Josh Poimboeuf 0 siblings, 1 reply; 89+ messages in thread From: Borislav Petkov @ 2015-07-17 17:17 UTC (permalink / raw) To: Josh Poimboeuf Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel On Fri, Jul 17, 2015 at 11:47:20AM -0500, Josh Poimboeuf wrote: > If __arch_hweight32() or __arch_hweight64() is inlined at the beginning > of a function, gcc can insert the call instruction before setting up a > stack frame, which breaks frame pointer convention if > CONFIG_FRAME_POINTER is enabled and can result in a bad stack trace. > > Force a stack frame to be created if CONFIG_FRAME_POINTER is enabled by > listing the stack pointer as an output operand for the inline asm > statement. > > Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> > --- > arch/x86/include/asm/arch_hweight.h | 6 ++++-- > 1 file changed, 4 insertions(+), 2 deletions(-) > > diff --git a/arch/x86/include/asm/arch_hweight.h b/arch/x86/include/asm/arch_hweight.h > index 9686c3d..e438a0d 100644 > --- a/arch/x86/include/asm/arch_hweight.h > +++ b/arch/x86/include/asm/arch_hweight.h > @@ -23,10 +23,11 @@ > */ > static inline unsigned int __arch_hweight32(unsigned int w) > { > + register void *__sp asm("esp"); > unsigned int res = 0; > > asm (ALTERNATIVE("call __sw_hweight32", POPCNT32, X86_FEATURE_POPCNT) > - : "="REG_OUT (res) > + : "="REG_OUT (res), "+r" (__sp) > : REG_IN (w)); > > return res; > @@ -44,6 +45,7 @@ static inline unsigned int __arch_hweight8(unsigned int w) > > static inline unsigned long __arch_hweight64(__u64 w) > { > + register void __maybe_unused *__sp asm("rsp"); > unsigned long res = 0; > > #ifdef CONFIG_X86_32 > @@ -51,7 +53,7 @@ static inline unsigned long __arch_hweight64(__u64 w) > __arch_hweight32((u32)(w >> 32)); > #else > asm (ALTERNATIVE("call __sw_hweight64", POPCNT64, X86_FEATURE_POPCNT) > - : "="REG_OUT (res) > + : "="REG_OUT (res), "+r" (__sp) > : REG_IN (w)); > #endif /* CONFIG_X86_32 */ Eeew, useless code so that some compile-time validation is done. Let's not add this clutter please. In this particular case, the majority of CPUs out there will get POPCNT patched in and that CALL is gone. And for the remaining cases where we do end up using the __sw_* variants, I'd prefer to rather not do the validation instead of polluting the code with that fake rsp dependency. -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply. -- ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 04/21] x86/hweight: Add stack frame dependency for __arch_hweight*() 2015-07-17 17:17 ` Borislav Petkov @ 2015-07-17 17:32 ` Josh Poimboeuf 2015-07-18 5:05 ` Borislav Petkov 0 siblings, 1 reply; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 17:32 UTC (permalink / raw) To: Borislav Petkov Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel On Fri, Jul 17, 2015 at 07:17:26PM +0200, Borislav Petkov wrote: > On Fri, Jul 17, 2015 at 11:47:20AM -0500, Josh Poimboeuf wrote: > > If __arch_hweight32() or __arch_hweight64() is inlined at the beginning > > of a function, gcc can insert the call instruction before setting up a > > stack frame, which breaks frame pointer convention if > > CONFIG_FRAME_POINTER is enabled and can result in a bad stack trace. > > > > Force a stack frame to be created if CONFIG_FRAME_POINTER is enabled by > > listing the stack pointer as an output operand for the inline asm > > statement. > > > > Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> > > --- > > arch/x86/include/asm/arch_hweight.h | 6 ++++-- > > 1 file changed, 4 insertions(+), 2 deletions(-) > > > > diff --git a/arch/x86/include/asm/arch_hweight.h b/arch/x86/include/asm/arch_hweight.h > > index 9686c3d..e438a0d 100644 > > --- a/arch/x86/include/asm/arch_hweight.h > > +++ b/arch/x86/include/asm/arch_hweight.h > > @@ -23,10 +23,11 @@ > > */ > > static inline unsigned int __arch_hweight32(unsigned int w) > > { > > + register void *__sp asm("esp"); > > unsigned int res = 0; > > > > asm (ALTERNATIVE("call __sw_hweight32", POPCNT32, X86_FEATURE_POPCNT) > > - : "="REG_OUT (res) > > + : "="REG_OUT (res), "+r" (__sp) > > : REG_IN (w)); > > > > return res; > > @@ -44,6 +45,7 @@ static inline unsigned int __arch_hweight8(unsigned int w) > > > > static inline unsigned long __arch_hweight64(__u64 w) > > { > > + register void __maybe_unused *__sp asm("rsp"); > > unsigned long res = 0; > > > > #ifdef CONFIG_X86_32 > > @@ -51,7 +53,7 @@ static inline unsigned long __arch_hweight64(__u64 w) > > __arch_hweight32((u32)(w >> 32)); > > #else > > asm (ALTERNATIVE("call __sw_hweight64", POPCNT64, X86_FEATURE_POPCNT) > > - : "="REG_OUT (res) > > + : "="REG_OUT (res), "+r" (__sp) > > : REG_IN (w)); > > #endif /* CONFIG_X86_32 */ > > Eeew, useless code so that some compile-time validation is done. Let's > not add this clutter please. > > In this particular case, the majority of CPUs out there will get POPCNT > patched in and that CALL is gone. And for the remaining cases where we > do end up using the __sw_* variants, I'd prefer to rather not do the > validation instead of polluting the code with that fake rsp dependency. Well, but this isn't some whitelist code to make stackvalidate happy. It's actually a real runtime frame pointer bug, and the rsp dependency is real. If it does the call without first creating the stack frame then it breaks frame pointer based stack traces. -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 04/21] x86/hweight: Add stack frame dependency for __arch_hweight*() 2015-07-17 17:32 ` Josh Poimboeuf @ 2015-07-18 5:05 ` Borislav Petkov 2015-07-18 13:44 ` Josh Poimboeuf 0 siblings, 1 reply; 89+ messages in thread From: Borislav Petkov @ 2015-07-18 5:05 UTC (permalink / raw) To: Josh Poimboeuf Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel On Fri, Jul 17, 2015 at 12:32:20PM -0500, Josh Poimboeuf wrote: > Well, but this isn't some whitelist code to make stackvalidate happy. > > It's actually a real runtime frame pointer bug, and the rsp dependency > is real. If it does the call without first creating the stack frame > then it breaks frame pointer based stack traces. I think we can live with the stack trace being a little wrong in those __sw_* variants. And besides, we're talking about the very very small percentage of machines (which keeps getting smaller) which don't support POPCNT. And from those, only for the cases where the arg is not __builtin_constant_p() because there we do the __const_hweight* thing. I'd prefer to not clutter the code more in that case. -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply. -- ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 04/21] x86/hweight: Add stack frame dependency for __arch_hweight*() 2015-07-18 5:05 ` Borislav Petkov @ 2015-07-18 13:44 ` Josh Poimboeuf 2015-07-18 14:56 ` Borislav Petkov 0 siblings, 1 reply; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-18 13:44 UTC (permalink / raw) To: Borislav Petkov Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel On Sat, Jul 18, 2015 at 07:05:36AM +0200, Borislav Petkov wrote: > On Fri, Jul 17, 2015 at 12:32:20PM -0500, Josh Poimboeuf wrote: > > Well, but this isn't some whitelist code to make stackvalidate happy. > > > > It's actually a real runtime frame pointer bug, and the rsp dependency > > is real. If it does the call without first creating the stack frame > > then it breaks frame pointer based stack traces. > > I think we can live with the stack trace being a little wrong in those > __sw_* variants. And besides, we're talking about the very very small > percentage of machines (which keeps getting smaller) which don't > support POPCNT. And from those, only for the cases where the arg is not > __builtin_constant_p() because there we do the __const_hweight* thing. > > I'd prefer to not clutter the code more in that case. Ok, so would you rather adding a whitelist to tell stackvalidate to ignore it? Something like this? diff --git a/arch/x86/include/asm/arch_hweight.h b/arch/x86/include/asm/arch_hweight.h index 9686c3d..d604691 100644 --- a/arch/x86/include/asm/arch_hweight.h +++ b/arch/x86/include/asm/arch_hweight.h @@ -1,6 +1,8 @@ #ifndef _ASM_X86_HWEIGHT_H #define _ASM_X86_HWEIGHT_H +#include <linux/stackvalidate.h> + #ifdef CONFIG_64BIT /* popcnt %edi, %eax -- redundant REX prefix for alignment */ #define POPCNT32 ".byte 0xf3,0x40,0x0f,0xb8,0xc7" @@ -25,7 +27,9 @@ static inline unsigned int __arch_hweight32(unsigned int w) { unsigned int res = 0; - asm (ALTERNATIVE("call __sw_hweight32", POPCNT32, X86_FEATURE_POPCNT) + asm (ALTERNATIVE(STACKVALIDATE_IGNORE_INSN + "call __sw_hweight32", + POPCNT32, X86_FEATURE_POPCNT) : "="REG_OUT (res) : REG_IN (w)); @@ -50,7 +54,9 @@ static inline unsigned long __arch_hweight64(__u64 w) return __arch_hweight32((u32)w) + __arch_hweight32((u32)(w >> 32)); #else - asm (ALTERNATIVE("call __sw_hweight64", POPCNT64, X86_FEATURE_POPCNT) + asm (ALTERNATIVE(STACKVALIDATE_IGNORE_INSN + "call __sw_hweight64", + POPCNT64, X86_FEATURE_POPCNT) : "="REG_OUT (res) : REG_IN (w)); #endif /* CONFIG_X86_32 */ -- Josh ^ permalink raw reply related [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 04/21] x86/hweight: Add stack frame dependency for __arch_hweight*() 2015-07-18 13:44 ` Josh Poimboeuf @ 2015-07-18 14:56 ` Borislav Petkov 2015-07-18 15:57 ` Josh Poimboeuf 0 siblings, 1 reply; 89+ messages in thread From: Borislav Petkov @ 2015-07-18 14:56 UTC (permalink / raw) To: Josh Poimboeuf Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel On Sat, Jul 18, 2015 at 08:44:15AM -0500, Josh Poimboeuf wrote: > Ok, so would you rather adding a whitelist to tell stackvalidate to > ignore it? Something like this? I tried it and maybe I'm missing something but that doesn't work: $ make drivers/gpu/drm/i915/intel_ringbuffer.o CHK include/config/kernel.release CHK include/generated/uapi/linux/version.h CHK include/generated/utsrelease.h CHK include/generated/timeconst.h CHK include/generated/bounds.h CHK include/generated/asm-offsets.h CALL scripts/checksyscalls.sh CC drivers/gpu/drm/i915/intel_ringbuffer.o ./arch/x86/include/asm/arch_hweight.h: Assembler messages: ./arch/x86/include/asm/arch_hweight.h:31: Error: symbol `.Ltemp32' is already defined ./arch/x86/include/asm/arch_hweight.h:31: Error: symbol `.Ltemp32' is already defined ./arch/x86/include/asm/arch_hweight.h:31: Error: symbol `.Ltemp32' is already defined scripts/Makefile.build:258: recipe for target 'drivers/gpu/drm/i915/intel_ringbuffer.o' failed make[1]: *** [drivers/gpu/drm/i915/intel_ringbuffer.o] Error 1 Makefile:1528: recipe for target 'drivers/gpu/drm/i915/intel_ringbuffer.o' failed make: *** [drivers/gpu/drm/i915/intel_ringbuffer.o] Error 2 Also, that label temp32 could be more descriptive. Regardless of the above, I don't like the idea of adding some compile-time checking and thus obfuscating what is already non-obvious code. And since your tool is already parsing ELF files and all that other fun, what I'd do is make that checking out-of-line *without* adding any new code to the kernel. In this particular case, you have: #APP # 28 "./arch/x86/include/asm/arch_hweight.h" 1 661: call __sw_hweight32 662: .skip -(((6651f-6641f)-(662b-661b)) > 0) * ((6651f-6641f)-(662b-661b)),0x90 663: .pushsection .altinstructions,"a" .long 661b - . .long 6641f - . .word ( 4*32+23) .byte 663b-661b .byte 6651f-6641f .byte 663b-662b .popsection .pushsection .altinstr_replacement, "ax" 6641: .byte 0xf3,0x40,0x0f,0xb8,0xc7 6651: .popsection # 0 "" 2 so you see that a CALL instruction gets replaced with a POPCNT and the feature bit used is 4*32+23 which is X86_FEATURE_POPCNT. This information is enough to detect that particular case and add the offset ".long 661b - ." to the list of instructions which stackvalidate should ignore. Anyway, this is what I'd do. IMNSVHO, we must be very conservative and not add some markers/helpers/etc to code only so that tools can do their job. Not if it can be helped. Instead, tools should do the hard work and we should keep kernel code clean. -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply. -- ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 04/21] x86/hweight: Add stack frame dependency for __arch_hweight*() 2015-07-18 14:56 ` Borislav Petkov @ 2015-07-18 15:57 ` Josh Poimboeuf 2015-07-19 4:12 ` Borislav Petkov 0 siblings, 1 reply; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-18 15:57 UTC (permalink / raw) To: Borislav Petkov Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel On Sat, Jul 18, 2015 at 04:56:29PM +0200, Borislav Petkov wrote: > On Sat, Jul 18, 2015 at 08:44:15AM -0500, Josh Poimboeuf wrote: > > Ok, so would you rather adding a whitelist to tell stackvalidate to > > ignore it? Something like this? > > I tried it and maybe I'm missing something but that doesn't work: > > $ make drivers/gpu/drm/i915/intel_ringbuffer.o > CHK include/config/kernel.release > CHK include/generated/uapi/linux/version.h > CHK include/generated/utsrelease.h > CHK include/generated/timeconst.h > CHK include/generated/bounds.h > CHK include/generated/asm-offsets.h > CALL scripts/checksyscalls.sh > CC drivers/gpu/drm/i915/intel_ringbuffer.o > ./arch/x86/include/asm/arch_hweight.h: Assembler messages: > ./arch/x86/include/asm/arch_hweight.h:31: Error: symbol `.Ltemp32' is already defined > ./arch/x86/include/asm/arch_hweight.h:31: Error: symbol `.Ltemp32' is already defined > ./arch/x86/include/asm/arch_hweight.h:31: Error: symbol `.Ltemp32' is already defined > scripts/Makefile.build:258: recipe for target 'drivers/gpu/drm/i915/intel_ringbuffer.o' failed > make[1]: *** [drivers/gpu/drm/i915/intel_ringbuffer.o] Error 1 > Makefile:1528: recipe for target 'drivers/gpu/drm/i915/intel_ringbuffer.o' failed > make: *** [drivers/gpu/drm/i915/intel_ringbuffer.o] Error 2 Yeah, it doesn't actually support this particular example yet. I was just trying to figure out if that's what you were proposing. > Also, that label temp32 could be more descriptive. Yeah, that's from: ".Ltemp" __stringify(__LINE__) ":;" Which was intended to give a unique ID for each use of the macro, but apparently that didn't work as planned here. > so you see that a CALL instruction gets replaced with a POPCNT and > the feature bit used is 4*32+23 which is X86_FEATURE_POPCNT. This > information is enough to detect that particular case and add the offset > ".long 661b - ." to the list of instructions which stackvalidate should > ignore. Currently, when stackvalidate sees an ALTERNATIVE, it assumes that either code path is possible, so it follows both paths in parallel. If I understand right, you're proposing that stackvalidate should only follow the POPCNT path and never follow the !POPCNT path? > Anyway, this is what I'd do. > > IMNSVHO, we must be very conservative and not add some > markers/helpers/etc to code only so that tools can do their job. Not if > it can be helped. Instead, tools should do the hard work and we should > keep kernel code clean. In general, I agree, and I like the original patch much better. IMO, it achieved the goal of keeping the kernel code clean, while fixing the frame pointer bug. If you insist on breaking stack traces on !POPCNT, I can probably add some intelligence to stackvalidate to look for !POPCNT and ignore it. It seems less "clean" to me, though. -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 04/21] x86/hweight: Add stack frame dependency for __arch_hweight*() 2015-07-18 15:57 ` Josh Poimboeuf @ 2015-07-19 4:12 ` Borislav Petkov 2015-07-22 0:13 ` Andy Lutomirski 0 siblings, 1 reply; 89+ messages in thread From: Borislav Petkov @ 2015-07-19 4:12 UTC (permalink / raw) To: Josh Poimboeuf Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel On Sat, Jul 18, 2015 at 10:57:14AM -0500, Josh Poimboeuf wrote: > Currently, when stackvalidate sees an ALTERNATIVE, it assumes that > either code path is possible, so it follows both paths in parallel. > > If I understand right, you're proposing that stackvalidate should only > follow the POPCNT path and never follow the !POPCNT path? Actually, you don't even need to follow the POPCNT case either because it is a single instruction - no stack operations there. So yeah, either that or special-case the case where the original insn is CALL and the replacement is a POPCNT and ignore those CALL locations. The advantage is that the burden is put on the tool and not by adding markers to kernel code paths. > In general, I agree, and I like the original patch much better. IMO, it > achieved the goal of keeping the kernel code clean, while fixing the > frame pointer bug. And I think that in that case, adding that rSP dependency is too much because even though it fixes the "bug", it is very very unlikely any stack trace will have __sw_hweight* in it for reasons pointed out earlier and also because those functions can't fail and they get integral types as args which can't fail when deref-fing either. And even if they do, they don't call any other functions so rIP pointing to them is already enough. So even if we're not 100% correct wrt stack traces in this case, I think that's ok. -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply. -- ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 04/21] x86/hweight: Add stack frame dependency for __arch_hweight*() 2015-07-19 4:12 ` Borislav Petkov @ 2015-07-22 0:13 ` Andy Lutomirski 2015-07-22 4:25 ` Borislav Petkov 0 siblings, 1 reply; 89+ messages in thread From: Andy Lutomirski @ 2015-07-22 0:13 UTC (permalink / raw) To: Borislav Petkov Cc: Michal Marek, Thomas Gleixner, Ingo Molnar, Josh Poimboeuf, linux-kernel@vger.kernel.org, Andi Kleen, Pedro Alves, live-patching, X86 ML, H. Peter Anvin, Linus Torvalds, Peter Zijlstra On Jul 18, 2015 9:13 PM, "Borislav Petkov" <bp@alien8.de> wrote: > > On Sat, Jul 18, 2015 at 10:57:14AM -0500, Josh Poimboeuf wrote: > > Currently, when stackvalidate sees an ALTERNATIVE, it assumes that > > either code path is possible, so it follows both paths in parallel. > > > > If I understand right, you're proposing that stackvalidate should only > > follow the POPCNT path and never follow the !POPCNT path? > > Actually, you don't even need to follow the POPCNT case either because > it is a single instruction - no stack operations there. > > So yeah, either that or special-case the case where the original insn is > CALL and the replacement is a POPCNT and ignore those CALL locations. > > The advantage is that the burden is put on the tool and not by adding > markers to kernel code paths. > > > In general, I agree, and I like the original patch much better. IMO, it > > achieved the goal of keeping the kernel code clean, while fixing the > > frame pointer bug. > > And I think that in that case, adding that rSP dependency is too much > because even though it fixes the "bug", it is very very unlikely any > stack trace will have __sw_hweight* in it for reasons pointed out > earlier and also because those functions can't fail and they get > integral types as args which can't fail when deref-fing either. And even > if they do, they don't call any other functions so rIP pointing to them > is already enough. Enough for oopses, perhaps, but maybe not enough for perf. It sounds like you want CFI unwinding :) --Andy ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 04/21] x86/hweight: Add stack frame dependency for __arch_hweight*() 2015-07-22 0:13 ` Andy Lutomirski @ 2015-07-22 4:25 ` Borislav Petkov 2015-07-22 4:39 ` Andy Lutomirski 0 siblings, 1 reply; 89+ messages in thread From: Borislav Petkov @ 2015-07-22 4:25 UTC (permalink / raw) To: Andy Lutomirski Cc: Michal Marek, Thomas Gleixner, Ingo Molnar, Josh Poimboeuf, linux-kernel@vger.kernel.org, Andi Kleen, Pedro Alves, live-patching, X86 ML, H. Peter Anvin, Linus Torvalds, Peter Zijlstra On Tue, Jul 21, 2015 at 05:13:12PM -0700, Andy Lutomirski wrote: > Enough for oopses, perhaps, but maybe not enough for perf. > > It sounds like you want CFI unwinding :) What would you want to unwind in those __sw_hweight* almost-trivial, tail functions? -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply. -- ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 04/21] x86/hweight: Add stack frame dependency for __arch_hweight*() 2015-07-22 4:25 ` Borislav Petkov @ 2015-07-22 4:39 ` Andy Lutomirski 2015-07-22 4:45 ` Borislav Petkov 0 siblings, 1 reply; 89+ messages in thread From: Andy Lutomirski @ 2015-07-22 4:39 UTC (permalink / raw) To: Borislav Petkov Cc: Michal Marek, Thomas Gleixner, Ingo Molnar, Josh Poimboeuf, linux-kernel@vger.kernel.org, Andi Kleen, Pedro Alves, live-patching, X86 ML, H. Peter Anvin, Linus Torvalds, Peter Zijlstra On Tue, Jul 21, 2015 at 9:25 PM, Borislav Petkov <bp@alien8.de> wrote: > On Tue, Jul 21, 2015 at 05:13:12PM -0700, Andy Lutomirski wrote: >> Enough for oopses, perhaps, but maybe not enough for perf. >> >> It sounds like you want CFI unwinding :) > > What would you want to unwind in those __sw_hweight* almost-trivial, > tail functions? So your shiny perf profile shows cumulative time in whatever called them. Sure, this is arguably silly if we're stuck with frame pointers. --Andy ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 04/21] x86/hweight: Add stack frame dependency for __arch_hweight*() 2015-07-22 4:39 ` Andy Lutomirski @ 2015-07-22 4:45 ` Borislav Petkov 0 siblings, 0 replies; 89+ messages in thread From: Borislav Petkov @ 2015-07-22 4:45 UTC (permalink / raw) To: Andy Lutomirski Cc: Michal Marek, Thomas Gleixner, Ingo Molnar, Josh Poimboeuf, linux-kernel@vger.kernel.org, Andi Kleen, Pedro Alves, live-patching, X86 ML, H. Peter Anvin, Linus Torvalds, Peter Zijlstra On Tue, Jul 21, 2015 at 09:39:23PM -0700, Andy Lutomirski wrote: > So your shiny perf profile shows cumulative time in whatever called > them. Sure, this is arguably silly if we're stuck with frame > pointers. You can count 20ish cycles tops for any one of them. At least that was from the last time when comparing POPCNT perf to the __sw_hweight* ones. IOW, POPCNT didn't show any improvement vs those sw versions. -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply. -- ^ permalink raw reply [flat|nested] 89+ messages in thread
* [RFC PATCH 05/21] x86/xen: Add stack frame dependency to hypercall inline asm calls 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (3 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 04/21] x86/hweight: Add stack frame dependency for __arch_hweight*() Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 06/21] x86/paravirt: Add stack frame dependency to PVOP " Josh Poimboeuf ` (16 subsequent siblings) 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel If a hypercall is inlined at the beginning of a function, gcc can insert the call instruction before setting up a stack frame, which breaks frame pointer convention if CONFIG_FRAME_POINTER is enabled and can result in a bad stack trace. Force a stack frame to be created if CONFIG_FRAME_POINTER is enabled by listing the stack pointer as an output operand for the hypercall inline asm statements. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/include/asm/xen/hypercall.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h index ca08a27..4488fbc 100644 --- a/arch/x86/include/asm/xen/hypercall.h +++ b/arch/x86/include/asm/xen/hypercall.h @@ -110,9 +110,10 @@ extern struct { char _entry[32]; } hypercall_page[]; register unsigned long __arg2 asm(__HYPERCALL_ARG2REG) = __arg2; \ register unsigned long __arg3 asm(__HYPERCALL_ARG3REG) = __arg3; \ register unsigned long __arg4 asm(__HYPERCALL_ARG4REG) = __arg4; \ - register unsigned long __arg5 asm(__HYPERCALL_ARG5REG) = __arg5; + register unsigned long __arg5 asm(__HYPERCALL_ARG5REG) = __arg5; \ + register void *__sp asm(_ASM_SP); -#define __HYPERCALL_0PARAM "=r" (__res) +#define __HYPERCALL_0PARAM "=r" (__res), "+r" (__sp) #define __HYPERCALL_1PARAM __HYPERCALL_0PARAM, "+r" (__arg1) #define __HYPERCALL_2PARAM __HYPERCALL_1PARAM, "+r" (__arg2) #define __HYPERCALL_3PARAM __HYPERCALL_2PARAM, "+r" (__arg3) -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [RFC PATCH 06/21] x86/paravirt: Add stack frame dependency to PVOP inline asm calls 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (4 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 05/21] x86/xen: Add stack frame dependency to hypercall inline asm calls Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 07/21] x86/paravirt: Fix frame pointer usage in PV_CALLEE_SAVE_REGS_THUNK Josh Poimboeuf ` (15 subsequent siblings) 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel If a PVOP call macro is inlined at the beginning of a function, gcc can insert the call instruction before setting up a stack frame, which breaks frame pointer convention if CONFIG_FRAME_POINTER is enabled and can result in a bad stack trace. Force a stack frame to be created by listing the stack pointer as an output operand for the PVOP inline asm statements. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/include/asm/paravirt_types.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h index ce029e4..1812294 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h @@ -497,8 +497,9 @@ int paravirt_disable_iospace(void); * makes sure the incoming and outgoing types are always correct. */ #ifdef CONFIG_X86_32 -#define PVOP_VCALL_ARGS \ - unsigned long __eax = __eax, __edx = __edx, __ecx = __ecx +#define PVOP_VCALL_ARGS \ + unsigned long __eax = __eax, __edx = __edx, __ecx = __ecx; \ + register void *__sp asm("esp") #define PVOP_CALL_ARGS PVOP_VCALL_ARGS #define PVOP_CALL_ARG1(x) "a" ((unsigned long)(x)) @@ -516,9 +517,10 @@ int paravirt_disable_iospace(void); #define VEXTRA_CLOBBERS #else /* CONFIG_X86_64 */ /* [re]ax isn't an arg, but the return val */ -#define PVOP_VCALL_ARGS \ - unsigned long __edi = __edi, __esi = __esi, \ - __edx = __edx, __ecx = __ecx, __eax = __eax +#define PVOP_VCALL_ARGS \ + unsigned long __edi = __edi, __esi = __esi, \ + __edx = __edx, __ecx = __ecx, __eax = __eax; \ + register void *__sp asm("rsp") #define PVOP_CALL_ARGS PVOP_VCALL_ARGS #define PVOP_CALL_ARG1(x) "D" ((unsigned long)(x)) @@ -557,7 +559,7 @@ int paravirt_disable_iospace(void); asm volatile(pre \ paravirt_alt(PARAVIRT_CALL) \ post \ - : call_clbr \ + : "+r" (__sp), call_clbr \ : paravirt_type(op), \ paravirt_clobber(clbr), \ ##__VA_ARGS__ \ @@ -567,7 +569,7 @@ int paravirt_disable_iospace(void); asm volatile(pre \ paravirt_alt(PARAVIRT_CALL) \ post \ - : call_clbr \ + : "+r" (__sp), call_clbr \ : paravirt_type(op), \ paravirt_clobber(clbr), \ ##__VA_ARGS__ \ @@ -594,7 +596,7 @@ int paravirt_disable_iospace(void); asm volatile(pre \ paravirt_alt(PARAVIRT_CALL) \ post \ - : call_clbr \ + : "+r" (__sp), call_clbr \ : paravirt_type(op), \ paravirt_clobber(clbr), \ ##__VA_ARGS__ \ -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [RFC PATCH 07/21] x86/paravirt: Fix frame pointer usage in PV_CALLEE_SAVE_REGS_THUNK 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (5 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 06/21] x86/paravirt: Add stack frame dependency to PVOP " Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 08/21] x86/paravirt: Align paravirt thunk functions at 16-byte boundaries Josh Poimboeuf ` (14 subsequent siblings) 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel A function created with the PV_CALLEE_SAVE_REGS_THUNK macro doesn't set up a new stack frame before the call instruction, which breaks frame pointer convention if CONFIG_FRAME_POINTER is enabled and can result in a bad stack trace. Also, the thunk functions aren't annotated as ELF callable functions. Create a stack frame when CONFIG_FRAME_POINTER is enabled and add the ELF function type. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/include/asm/paravirt.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index c2be037..2545f3e 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -13,6 +13,7 @@ #include <linux/bug.h> #include <linux/types.h> #include <linux/cpumask.h> +#include <asm/frame.h> static inline int paravirt_enabled(void) { @@ -772,15 +773,19 @@ static __always_inline void __ticket_unlock_kick(struct arch_spinlock *lock, * call. The return value in rax/eax will not be saved, even for void * functions. */ +#define PV_THUNK_NAME(func) "__raw_callee_save_" #func #define PV_CALLEE_SAVE_REGS_THUNK(func) \ extern typeof(func) __raw_callee_save_##func; \ \ asm(".pushsection .text;" \ - ".globl __raw_callee_save_" #func " ; " \ - "__raw_callee_save_" #func ": " \ + ".globl " PV_THUNK_NAME(func) ";" \ + ".type " PV_THUNK_NAME(func) ", @function;" \ + PV_THUNK_NAME(func) ":" \ + FRAME \ PV_SAVE_ALL_CALLER_REGS \ "call " #func ";" \ PV_RESTORE_ALL_CALLER_REGS \ + ENDFRAME \ "ret;" \ ".popsection") -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [RFC PATCH 08/21] x86/paravirt: Align paravirt thunk functions at 16-byte boundaries 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (6 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 07/21] x86/paravirt: Fix frame pointer usage in PV_CALLEE_SAVE_REGS_THUNK Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 09/21] x86/amd: Set ELF function type for vide() Josh Poimboeuf ` (13 subsequent siblings) 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel Paravirt thunk functions aren't aligned, which can impact performance and is inconsistent with gcc-generated functions. Align them at 16-byte boundaries to be consistent with gcc functions. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/include/asm/paravirt.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index 2545f3e..5dcbf17 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -778,6 +778,7 @@ static __always_inline void __ticket_unlock_kick(struct arch_spinlock *lock, extern typeof(func) __raw_callee_save_##func; \ \ asm(".pushsection .text;" \ + ".align 16;" \ ".globl " PV_THUNK_NAME(func) ";" \ ".type " PV_THUNK_NAME(func) ", @function;" \ PV_THUNK_NAME(func) ":" \ -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [RFC PATCH 09/21] x86/amd: Set ELF function type for vide() 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (7 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 08/21] x86/paravirt: Align paravirt thunk functions at 16-byte boundaries Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 10/21] x86/reboot: Add ljmp instructions to stackvalidate whitelist Josh Poimboeuf ` (12 subsequent siblings) 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel vide() is a callable function, but is missing the ELF function type, which confuses tools like stackvalidate. Properly annotate it to be a callable function. The generated code is unchanged. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/kernel/cpu/amd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 51ad2af..6507bab6 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -74,7 +74,10 @@ static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val) */ extern __visible void vide(void); -__asm__(".globl vide\n\t.align 4\nvide: ret"); +__asm__(".globl vide;" + ".type vide, @function;" + ".align 4;" + "vide: ret;"); static void init_amd_k5(struct cpuinfo_x86 *c) { -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [RFC PATCH 10/21] x86/reboot: Add ljmp instructions to stackvalidate whitelist 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (8 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 09/21] x86/amd: Set ELF function type for vide() Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 11/21] x86/xen: Add xen_cpuid() and xen_setup_gdt() to stackvalidate whitelists Josh Poimboeuf ` (11 subsequent siblings) 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel stackvalidate reports a false positive warning for the ljmp instruction in machine_real_restart(). Normally, ljmp isn't allowed in a function, but this is a special case where it's jumping into real mode. Add the jumps to a whitelist which tells stackvalidate to ignore them. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/kernel/reboot.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 86db4bc..0931d87 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -9,6 +9,7 @@ #include <linux/sched.h> #include <linux/tboot.h> #include <linux/delay.h> +#include <linux/stackvalidate.h> #include <acpi/reboot.h> #include <asm/io.h> #include <asm/apic.h> @@ -97,11 +98,13 @@ void __noreturn machine_real_restart(unsigned int type) /* Jump to the identity-mapped low memory code */ #ifdef CONFIG_X86_32 - asm volatile("jmpl *%0" : : + asm volatile(STACKVALIDATE_IGNORE_INSN + "jmpl *%0;" : : "rm" (real_mode_header->machine_real_restart_asm), "a" (type)); #else - asm volatile("ljmpl *%0" : : + asm volatile(STACKVALIDATE_IGNORE_INSN + "ljmpl *%0" : : "m" (real_mode_header->machine_real_restart_asm), "D" (type)); #endif -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [RFC PATCH 11/21] x86/xen: Add xen_cpuid() and xen_setup_gdt() to stackvalidate whitelists 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (9 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 10/21] x86/reboot: Add ljmp instructions to stackvalidate whitelist Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 12/21] sched: Add __schedule() to stackvalidate whitelist Josh Poimboeuf ` (10 subsequent siblings) 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel stackvalidate reports the following false positive warnings: stackvalidate: arch/x86/xen/enlighten.o: xen_cpuid()+0x41: can't find jump dest instruction at .text+0x108 stackvalidate: arch/x86/xen/enlighten.o: xen_setup_gdt.constprop.23()+0x2e: kernel entry/exit from callable instruction The first warning is due to xen_cpuid()'s use of XEN_EMULATE_PREFIX to insert some fake instructions which stackvalidate doesn't know how to decode. The second warning is due to xen_setup_gdt()'s use of an lret instruction, which stackvalidate normally doesn't allow in callable functions. But this seems to be a valid use of the instruction. Add both functions to the stackvalidate whitelist. This results in no actual changes to the generated code. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/xen/enlighten.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 32136bf..8091836 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -32,6 +32,7 @@ #include <linux/gfp.h> #include <linux/memblock.h> #include <linux/edd.h> +#include <linux/stackvalidate.h> #include <xen/xen.h> #include <xen/events.h> @@ -345,8 +346,8 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx, *cx &= maskecx; *cx |= setecx; *dx &= maskedx; - } +STACKVALIDATE_IGNORE_FUNC(xen_cpuid); static bool __init xen_check_mwait(void) { @@ -1403,6 +1404,7 @@ static void __ref xen_setup_gdt(int cpu) pv_cpu_ops.write_gdt_entry = xen_write_gdt_entry; pv_cpu_ops.load_gdt = xen_load_gdt; } +STACKVALIDATE_IGNORE_FUNC(xen_setup_gdt); #ifdef CONFIG_XEN_PVH /* -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [RFC PATCH 12/21] sched: Add __schedule() to stackvalidate whitelist 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (10 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 11/21] x86/xen: Add xen_cpuid() and xen_setup_gdt() to stackvalidate whitelists Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 19:46 ` Peter Zijlstra 2015-07-17 16:47 ` [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S Josh Poimboeuf ` (9 subsequent siblings) 21 siblings, 1 reply; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel stackvalidate reports the following warnings for __schedule(): stackvalidate: kernel/sched/core.o: __schedule()+0x3e7: duplicate frame pointer save stackvalidate: kernel/sched/core.o: __schedule()+0x424: sibling call from callable instruction with changed frame pointer stackvalidate: kernel/sched/core.o: __schedule()+0x431: call without frame pointer save/setup stackvalidate: kernel/sched/core.o: __schedule()+0x8b8: frame pointer state mismatch stackvalidate: kernel/sched/core.o: __schedule()+0x447: frame pointer state mismatch __schedule() is obviously a special case which is allowed to do unusual things with the frame pointer. Add it to the stackvalidate whitelist. This results in no actual changes to the generated code. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- kernel/sched/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 78b4bad10..9f49eae 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -74,6 +74,7 @@ #include <linux/binfmts.h> #include <linux/context_tracking.h> #include <linux/compiler.h> +#include <linux/stackvalidate.h> #include <asm/switch_to.h> #include <asm/tlb.h> @@ -3059,6 +3060,7 @@ static void __sched __schedule(void) balance_callback(rq); } +STACKVALIDATE_IGNORE_FUNC(__schedule); static inline void sched_submit_work(struct task_struct *tsk) { -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 12/21] sched: Add __schedule() to stackvalidate whitelist 2015-07-17 16:47 ` [RFC PATCH 12/21] sched: Add __schedule() to stackvalidate whitelist Josh Poimboeuf @ 2015-07-17 19:46 ` Peter Zijlstra 2015-07-17 19:58 ` Andy Lutomirski 0 siblings, 1 reply; 89+ messages in thread From: Peter Zijlstra @ 2015-07-17 19:46 UTC (permalink / raw) To: Josh Poimboeuf Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel On Fri, Jul 17, 2015 at 11:47:28AM -0500, Josh Poimboeuf wrote: > stackvalidate reports the following warnings for __schedule(): > > stackvalidate: kernel/sched/core.o: __schedule()+0x3e7: duplicate frame pointer save > stackvalidate: kernel/sched/core.o: __schedule()+0x424: sibling call from callable instruction with changed frame pointer > stackvalidate: kernel/sched/core.o: __schedule()+0x431: call without frame pointer save/setup > stackvalidate: kernel/sched/core.o: __schedule()+0x8b8: frame pointer state mismatch > stackvalidate: kernel/sched/core.o: __schedule()+0x447: frame pointer state mismatch > > __schedule() is obviously a special case which is allowed to do unusual > things with the frame pointer. Yes, but is the code actually correct? We can't dismiss the warnings just on that basis alone. ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 12/21] sched: Add __schedule() to stackvalidate whitelist 2015-07-17 19:46 ` Peter Zijlstra @ 2015-07-17 19:58 ` Andy Lutomirski 2015-07-17 21:03 ` Peter Zijlstra ` (2 more replies) 0 siblings, 3 replies; 89+ messages in thread From: Andy Lutomirski @ 2015-07-17 19:58 UTC (permalink / raw) To: Peter Zijlstra Cc: Josh Poimboeuf, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Fri, Jul 17, 2015 at 12:46 PM, Peter Zijlstra <peterz@infradead.org> wrote: > On Fri, Jul 17, 2015 at 11:47:28AM -0500, Josh Poimboeuf wrote: >> stackvalidate reports the following warnings for __schedule(): >> >> stackvalidate: kernel/sched/core.o: __schedule()+0x3e7: duplicate frame pointer save >> stackvalidate: kernel/sched/core.o: __schedule()+0x424: sibling call from callable instruction with changed frame pointer >> stackvalidate: kernel/sched/core.o: __schedule()+0x431: call without frame pointer save/setup >> stackvalidate: kernel/sched/core.o: __schedule()+0x8b8: frame pointer state mismatch >> stackvalidate: kernel/sched/core.o: __schedule()+0x447: frame pointer state mismatch >> >> __schedule() is obviously a special case which is allowed to do unusual >> things with the frame pointer. > > Yes, but is the code actually correct? We can't dismiss the warnings > just on that basis alone. It's really only __switch_to that does weird things, right? I kinda want to rework that thing anyway to have a well-defined saved state format anyway, which would have the nice benefit of letting us get rid of all the ret_from_fork crap. That is, we'd context switch like: static inline void __switch_to(...) { switch extra stuff; switch everything except gpregs; asm volatile ("call __switch_stack_and_ip" : [__sp thing goes here] : "S" (&prev->bottom_of_stack), "D" (&next->bottom_of_stack) : "basically all regs and flags"); } Then the low level bit would be: __switch_stack_and_ip: pushq %rbp mov %rsp, (%rsi) mov (%rdi), %rsp popq %rbp ret Now, when we create a new task, we can set up its stack directly rather than setting some TI flag, because we actually know the layout. Hmm? --Andy ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 12/21] sched: Add __schedule() to stackvalidate whitelist 2015-07-17 19:58 ` Andy Lutomirski @ 2015-07-17 21:03 ` Peter Zijlstra 2015-07-17 21:23 ` Josh Poimboeuf 2015-07-18 3:44 ` Ingo Molnar 2 siblings, 0 replies; 89+ messages in thread From: Peter Zijlstra @ 2015-07-17 21:03 UTC (permalink / raw) To: Andy Lutomirski Cc: Josh Poimboeuf, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Fri, Jul 17, 2015 at 12:58:12PM -0700, Andy Lutomirski wrote: > On Fri, Jul 17, 2015 at 12:46 PM, Peter Zijlstra <peterz@infradead.org> wrote: > > On Fri, Jul 17, 2015 at 11:47:28AM -0500, Josh Poimboeuf wrote: > >> stackvalidate reports the following warnings for __schedule(): > >> > >> stackvalidate: kernel/sched/core.o: __schedule()+0x3e7: duplicate frame pointer save > >> stackvalidate: kernel/sched/core.o: __schedule()+0x424: sibling call from callable instruction with changed frame pointer > >> stackvalidate: kernel/sched/core.o: __schedule()+0x431: call without frame pointer save/setup > >> stackvalidate: kernel/sched/core.o: __schedule()+0x8b8: frame pointer state mismatch > >> stackvalidate: kernel/sched/core.o: __schedule()+0x447: frame pointer state mismatch > >> > >> __schedule() is obviously a special case which is allowed to do unusual > >> things with the frame pointer. > > > > Yes, but is the code actually correct? We can't dismiss the warnings > > just on that basis alone. > > It's really only __switch_to that does weird things, right? Yep, but context_switch() gets inlined and __switch_to() is a macro, so it all ends up being __schedule(). > I kinda > want to rework that thing anyway to have a well-defined saved state > format anyway, which would have the nice benefit of letting us get rid > of all the ret_from_fork crap. > > That is, we'd context switch like: > > static inline void __switch_to(...) { > switch extra stuff; > switch everything except gpregs; > asm volatile ("call __switch_stack_and_ip" : [__sp thing goes here] > : "S" (&prev->bottom_of_stack), "D" (&next->bottom_of_stack) : > "basically all regs and flags"); > } > > Then the low level bit would be: > > __switch_stack_and_ip: > pushq %rbp > mov %rsp, (%rsi) > mov (%rdi), %rsp > popq %rbp > ret > > Now, when we create a new task, we can set up its stack directly > rather than setting some TI flag, because we actually know the layout. > > Hmm? I've never really looked at the x86 details, but yes it would be good to get rid of that fork special case. ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 12/21] sched: Add __schedule() to stackvalidate whitelist 2015-07-17 19:58 ` Andy Lutomirski 2015-07-17 21:03 ` Peter Zijlstra @ 2015-07-17 21:23 ` Josh Poimboeuf 2015-07-18 3:44 ` Ingo Molnar 2 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 21:23 UTC (permalink / raw) To: Andy Lutomirski Cc: Peter Zijlstra, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Fri, Jul 17, 2015 at 12:58:12PM -0700, Andy Lutomirski wrote: > On Fri, Jul 17, 2015 at 12:46 PM, Peter Zijlstra <peterz@infradead.org> wrote: > > On Fri, Jul 17, 2015 at 11:47:28AM -0500, Josh Poimboeuf wrote: > >> stackvalidate reports the following warnings for __schedule(): > >> > >> stackvalidate: kernel/sched/core.o: __schedule()+0x3e7: duplicate frame pointer save > >> stackvalidate: kernel/sched/core.o: __schedule()+0x424: sibling call from callable instruction with changed frame pointer > >> stackvalidate: kernel/sched/core.o: __schedule()+0x431: call without frame pointer save/setup > >> stackvalidate: kernel/sched/core.o: __schedule()+0x8b8: frame pointer state mismatch > >> stackvalidate: kernel/sched/core.o: __schedule()+0x447: frame pointer state mismatch > >> > >> __schedule() is obviously a special case which is allowed to do unusual > >> things with the frame pointer. > > > > Yes, but is the code actually correct? We can't dismiss the warnings > > just on that basis alone. > > It's really only __switch_to that does weird things, right? I kinda > want to rework that thing anyway to have a well-defined saved state > format anyway, which would have the nice benefit of letting us get rid > of all the ret_from_fork crap. > > That is, we'd context switch like: > > static inline void __switch_to(...) { > switch extra stuff; > switch everything except gpregs; > asm volatile ("call __switch_stack_and_ip" : [__sp thing goes here] > : "S" (&prev->bottom_of_stack), "D" (&next->bottom_of_stack) : > "basically all regs and flags"); > } > > Then the low level bit would be: > > __switch_stack_and_ip: > pushq %rbp > mov %rsp, (%rsi) > mov (%rdi), %rsp > popq %rbp > ret > > Now, when we create a new task, we can set up its stack directly > rather than setting some TI flag, because we actually know the layout. > > Hmm? I think that would make stackvalidate much happier. I'll drop this patch for now so stackvalidate will keep reminding me to bug you to implement this ;-) -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 12/21] sched: Add __schedule() to stackvalidate whitelist 2015-07-17 19:58 ` Andy Lutomirski 2015-07-17 21:03 ` Peter Zijlstra 2015-07-17 21:23 ` Josh Poimboeuf @ 2015-07-18 3:44 ` Ingo Molnar 2 siblings, 0 replies; 89+ messages in thread From: Ingo Molnar @ 2015-07-18 3:44 UTC (permalink / raw) To: Andy Lutomirski Cc: Peter Zijlstra, Josh Poimboeuf, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org * Andy Lutomirski <luto@amacapital.net> wrote: > On Fri, Jul 17, 2015 at 12:46 PM, Peter Zijlstra <peterz@infradead.org> wrote: > > On Fri, Jul 17, 2015 at 11:47:28AM -0500, Josh Poimboeuf wrote: > >> stackvalidate reports the following warnings for __schedule(): > >> > >> stackvalidate: kernel/sched/core.o: __schedule()+0x3e7: duplicate frame pointer save > >> stackvalidate: kernel/sched/core.o: __schedule()+0x424: sibling call from callable instruction with changed frame pointer > >> stackvalidate: kernel/sched/core.o: __schedule()+0x431: call without frame pointer save/setup > >> stackvalidate: kernel/sched/core.o: __schedule()+0x8b8: frame pointer state mismatch > >> stackvalidate: kernel/sched/core.o: __schedule()+0x447: frame pointer state mismatch > >> > >> __schedule() is obviously a special case which is allowed to do unusual > >> things with the frame pointer. > > > > Yes, but is the code actually correct? We can't dismiss the warnings > > just on that basis alone. > > It's really only __switch_to that does weird things, right? I kinda > want to rework that thing anyway to have a well-defined saved state > format anyway, which would have the nice benefit of letting us get rid > of all the ret_from_fork crap. > > That is, we'd context switch like: > > static inline void __switch_to(...) { > switch extra stuff; > switch everything except gpregs; > asm volatile ("call __switch_stack_and_ip" : [__sp thing goes here] > : "S" (&prev->bottom_of_stack), "D" (&next->bottom_of_stack) : > "basically all regs and flags"); > } > > Then the low level bit would be: > > __switch_stack_and_ip: > pushq %rbp > mov %rsp, (%rsi) > mov (%rdi), %rsp > popq %rbp > ret > > Now, when we create a new task, we can set up its stack directly > rather than setting some TI flag, because we actually know the layout. > > Hmm? Sounds good to me! Thanks, Ingo ^ permalink raw reply [flat|nested] 89+ messages in thread
* [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (11 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 12/21] sched: Add __schedule() to stackvalidate whitelist Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 19:43 ` Ingo Molnar 2015-07-17 16:47 ` [RFC PATCH 14/21] x86/asm/crypto: Move .Lbswap_mask data to .rodata section Josh Poimboeuf ` (8 subsequent siblings) 21 siblings, 1 reply; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel aesni-intel_asm.S has several callable non-leaf functions which don't honor CONFIG_FRAME_POINTER, which can result in bad stack traces. Create stack frames for them when CONFIG_FRAME_POINTER is enabled. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/crypto/aesni-intel_asm.S | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/x86/crypto/aesni-intel_asm.S b/arch/x86/crypto/aesni-intel_asm.S index 6bd2c6c..3df557b 100644 --- a/arch/x86/crypto/aesni-intel_asm.S +++ b/arch/x86/crypto/aesni-intel_asm.S @@ -31,6 +31,7 @@ #include <linux/linkage.h> #include <asm/inst.h> +#include <asm/frame.h> /* * The following macros are used to move an (un)aligned 16 byte value to/from @@ -1800,6 +1801,7 @@ ENDPROC(_key_expansion_256b) * unsigned int key_len) */ ENTRY(aesni_set_key) + FRAME #ifndef __x86_64__ pushl KEYP movl 8(%esp), KEYP # ctx @@ -1905,6 +1907,7 @@ ENTRY(aesni_set_key) #ifndef __x86_64__ popl KEYP #endif + ENDFRAME ret ENDPROC(aesni_set_key) @@ -1912,6 +1915,7 @@ ENDPROC(aesni_set_key) * void aesni_enc(struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src) */ ENTRY(aesni_enc) + FRAME #ifndef __x86_64__ pushl KEYP pushl KLEN @@ -1927,6 +1931,7 @@ ENTRY(aesni_enc) popl KLEN popl KEYP #endif + ENDFRAME ret ENDPROC(aesni_enc) @@ -2101,6 +2106,7 @@ ENDPROC(_aesni_enc4) * void aesni_dec (struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src) */ ENTRY(aesni_dec) + FRAME #ifndef __x86_64__ pushl KEYP pushl KLEN @@ -2117,6 +2123,7 @@ ENTRY(aesni_dec) popl KLEN popl KEYP #endif + ENDFRAME ret ENDPROC(aesni_dec) @@ -2292,6 +2299,7 @@ ENDPROC(_aesni_dec4) * size_t len) */ ENTRY(aesni_ecb_enc) + FRAME #ifndef __x86_64__ pushl LEN pushl KEYP @@ -2342,6 +2350,7 @@ ENTRY(aesni_ecb_enc) popl KEYP popl LEN #endif + ENDFRAME ret ENDPROC(aesni_ecb_enc) @@ -2350,6 +2359,7 @@ ENDPROC(aesni_ecb_enc) * size_t len); */ ENTRY(aesni_ecb_dec) + FRAME #ifndef __x86_64__ pushl LEN pushl KEYP @@ -2401,6 +2411,7 @@ ENTRY(aesni_ecb_dec) popl KEYP popl LEN #endif + ENDFRAME ret ENDPROC(aesni_ecb_dec) @@ -2409,6 +2420,7 @@ ENDPROC(aesni_ecb_dec) * size_t len, u8 *iv) */ ENTRY(aesni_cbc_enc) + FRAME #ifndef __x86_64__ pushl IVP pushl LEN @@ -2443,6 +2455,7 @@ ENTRY(aesni_cbc_enc) popl LEN popl IVP #endif + ENDFRAME ret ENDPROC(aesni_cbc_enc) @@ -2451,6 +2464,7 @@ ENDPROC(aesni_cbc_enc) * size_t len, u8 *iv) */ ENTRY(aesni_cbc_dec) + FRAME #ifndef __x86_64__ pushl IVP pushl LEN @@ -2534,6 +2548,7 @@ ENTRY(aesni_cbc_dec) popl LEN popl IVP #endif + ENDFRAME ret ENDPROC(aesni_cbc_dec) @@ -2598,6 +2613,7 @@ ENDPROC(_aesni_inc) * size_t len, u8 *iv) */ ENTRY(aesni_ctr_enc) + FRAME cmp $16, LEN jb .Lctr_enc_just_ret mov 480(KEYP), KLEN @@ -2651,6 +2667,7 @@ ENTRY(aesni_ctr_enc) .Lctr_enc_ret: movups IV, (IVP) .Lctr_enc_just_ret: + ENDFRAME ret ENDPROC(aesni_ctr_enc) @@ -2677,6 +2694,7 @@ ENDPROC(aesni_ctr_enc) * bool enc, u8 *iv) */ ENTRY(aesni_xts_crypt8) + FRAME cmpb $0, %cl movl $0, %ecx movl $240, %r10d @@ -2777,6 +2795,7 @@ ENTRY(aesni_xts_crypt8) pxor INC, STATE4 movdqu STATE4, 0x70(OUTP) + ENDFRAME ret ENDPROC(aesni_xts_crypt8) -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-17 16:47 ` [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S Josh Poimboeuf @ 2015-07-17 19:43 ` Ingo Molnar 2015-07-17 19:44 ` Andy Lutomirski 0 siblings, 1 reply; 89+ messages in thread From: Ingo Molnar @ 2015-07-17 19:43 UTC (permalink / raw) To: Josh Poimboeuf Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > ENTRY(aesni_set_key) > + FRAME > #ifndef __x86_64__ > pushl KEYP > movl 8(%esp), KEYP # ctx > @@ -1905,6 +1907,7 @@ ENTRY(aesni_set_key) > #ifndef __x86_64__ > popl KEYP > #endif > + ENDFRAME > ret > ENDPROC(aesni_set_key) So cannot we make this a bit more compact and less fragile? Instead of: ENTRY(aesni_set_key) FRAME ... ENDFRAME ret ENDPROC(aesni_set_key) How about writing this as: FUNCTION_ENTRY(aesni_set_key) ... FUNCTION_RETURN(aesni_set_key) which does the same thing in a short, symmetric construct? One potential problem with this approach would be that what 'looks' like an entry declaration, but it will now generate real code. OTOH if people find this intuitive enough then it's a lot harder to mess it up, and I think 'RETURN' makes it clear enough that there's a real instruction generated there. Thanks, Ingo ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-17 19:43 ` Ingo Molnar @ 2015-07-17 19:44 ` Andy Lutomirski 2015-07-17 20:37 ` Josh Poimboeuf 0 siblings, 1 reply; 89+ messages in thread From: Andy Lutomirski @ 2015-07-17 19:44 UTC (permalink / raw) To: Ingo Molnar Cc: Josh Poimboeuf, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Fri, Jul 17, 2015 at 12:43 PM, Ingo Molnar <mingo@kernel.org> wrote: > > * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > >> ENTRY(aesni_set_key) >> + FRAME >> #ifndef __x86_64__ >> pushl KEYP >> movl 8(%esp), KEYP # ctx >> @@ -1905,6 +1907,7 @@ ENTRY(aesni_set_key) >> #ifndef __x86_64__ >> popl KEYP >> #endif >> + ENDFRAME >> ret >> ENDPROC(aesni_set_key) > > So cannot we make this a bit more compact and less fragile? > > Instead of: > > ENTRY(aesni_set_key) > FRAME > ... > ENDFRAME > ret > ENDPROC(aesni_set_key) > > > How about writing this as: > > FUNCTION_ENTRY(aesni_set_key) > ... > FUNCTION_RETURN(aesni_set_key) > > which does the same thing in a short, symmetric construct? > > One potential problem with this approach would be that what 'looks' like an entry > declaration, but it will now generate real code. > > OTOH if people find this intuitive enough then it's a lot harder to mess it up, > and I think 'RETURN' makes it clear enough that there's a real instruction > generated there. > How about FUNCTION_PROLOGUE and FUNCTION_EPILOGUE? -Andy ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-17 19:44 ` Andy Lutomirski @ 2015-07-17 20:37 ` Josh Poimboeuf 2015-07-17 20:39 ` Andy Lutomirski 2015-07-18 2:51 ` Ingo Molnar 0 siblings, 2 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 20:37 UTC (permalink / raw) To: Andy Lutomirski Cc: Ingo Molnar, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Fri, Jul 17, 2015 at 12:44:42PM -0700, Andy Lutomirski wrote: > On Fri, Jul 17, 2015 at 12:43 PM, Ingo Molnar <mingo@kernel.org> wrote: > > > > * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > > > >> ENTRY(aesni_set_key) > >> + FRAME > >> #ifndef __x86_64__ > >> pushl KEYP > >> movl 8(%esp), KEYP # ctx > >> @@ -1905,6 +1907,7 @@ ENTRY(aesni_set_key) > >> #ifndef __x86_64__ > >> popl KEYP > >> #endif > >> + ENDFRAME > >> ret > >> ENDPROC(aesni_set_key) > > > > So cannot we make this a bit more compact and less fragile? > > > > Instead of: > > > > ENTRY(aesni_set_key) > > FRAME > > ... > > ENDFRAME > > ret > > ENDPROC(aesni_set_key) > > > > > > How about writing this as: > > > > FUNCTION_ENTRY(aesni_set_key) > > ... > > FUNCTION_RETURN(aesni_set_key) > > > > which does the same thing in a short, symmetric construct? > > > > One potential problem with this approach would be that what 'looks' like an entry > > declaration, but it will now generate real code. > > > > OTOH if people find this intuitive enough then it's a lot harder to mess it up, > > and I think 'RETURN' makes it clear enough that there's a real instruction > > generated there. > > > > How about FUNCTION_PROLOGUE and FUNCTION_EPILOGUE? Perhaps the macro name should describe what the epilogue does, since frame pointers aren't required for _all_ functions, only those which don't have call instructions. What do you think about ENTRY_FRAME and ENDPROC_FRAME_RETURN? The ending macro is kind of long, but at least it a) matches the existing ENTRY/ENDPROC convention for asm functions; b) gives a clue that frame pointers are involved; and c) lets you know that the return is there. -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-17 20:37 ` Josh Poimboeuf @ 2015-07-17 20:39 ` Andy Lutomirski 2015-07-17 20:44 ` Josh Poimboeuf 2015-07-18 2:51 ` Ingo Molnar 1 sibling, 1 reply; 89+ messages in thread From: Andy Lutomirski @ 2015-07-17 20:39 UTC (permalink / raw) To: Josh Poimboeuf Cc: Ingo Molnar, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Fri, Jul 17, 2015 at 1:37 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > On Fri, Jul 17, 2015 at 12:44:42PM -0700, Andy Lutomirski wrote: >> On Fri, Jul 17, 2015 at 12:43 PM, Ingo Molnar <mingo@kernel.org> wrote: >> > >> > * Josh Poimboeuf <jpoimboe@redhat.com> wrote: >> > >> >> ENTRY(aesni_set_key) >> >> + FRAME >> >> #ifndef __x86_64__ >> >> pushl KEYP >> >> movl 8(%esp), KEYP # ctx >> >> @@ -1905,6 +1907,7 @@ ENTRY(aesni_set_key) >> >> #ifndef __x86_64__ >> >> popl KEYP >> >> #endif >> >> + ENDFRAME >> >> ret >> >> ENDPROC(aesni_set_key) >> > >> > So cannot we make this a bit more compact and less fragile? >> > >> > Instead of: >> > >> > ENTRY(aesni_set_key) >> > FRAME >> > ... >> > ENDFRAME >> > ret >> > ENDPROC(aesni_set_key) >> > >> > >> > How about writing this as: >> > >> > FUNCTION_ENTRY(aesni_set_key) >> > ... >> > FUNCTION_RETURN(aesni_set_key) >> > >> > which does the same thing in a short, symmetric construct? >> > >> > One potential problem with this approach would be that what 'looks' like an entry >> > declaration, but it will now generate real code. >> > >> > OTOH if people find this intuitive enough then it's a lot harder to mess it up, >> > and I think 'RETURN' makes it clear enough that there's a real instruction >> > generated there. >> > >> >> How about FUNCTION_PROLOGUE and FUNCTION_EPILOGUE? > > Perhaps the macro name should describe what the epilogue does, since > frame pointers aren't required for _all_ functions, only those which > don't have call instructions. > > What do you think about ENTRY_FRAME and ENDPROC_FRAME_RETURN? The > ending macro is kind of long, but at least it a) matches the existing > ENTRY/ENDPROC convention for asm functions; b) gives a clue that frame > pointers are involved; and c) lets you know that the return is there. > This really is about frame pointers, right? How about ENTRY_FRAMEPTR_xyz where xyz can be prologue, epilogue, return, whatever? > -- > Josh -- Andy Lutomirski AMA Capital Management, LLC ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-17 20:39 ` Andy Lutomirski @ 2015-07-17 20:44 ` Josh Poimboeuf 2015-07-17 20:46 ` Andy Lutomirski 0 siblings, 1 reply; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 20:44 UTC (permalink / raw) To: Andy Lutomirski Cc: Ingo Molnar, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Fri, Jul 17, 2015 at 01:39:09PM -0700, Andy Lutomirski wrote: > On Fri, Jul 17, 2015 at 1:37 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > > On Fri, Jul 17, 2015 at 12:44:42PM -0700, Andy Lutomirski wrote: > >> On Fri, Jul 17, 2015 at 12:43 PM, Ingo Molnar <mingo@kernel.org> wrote: > >> > > >> > * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > >> > > >> >> ENTRY(aesni_set_key) > >> >> + FRAME > >> >> #ifndef __x86_64__ > >> >> pushl KEYP > >> >> movl 8(%esp), KEYP # ctx > >> >> @@ -1905,6 +1907,7 @@ ENTRY(aesni_set_key) > >> >> #ifndef __x86_64__ > >> >> popl KEYP > >> >> #endif > >> >> + ENDFRAME > >> >> ret > >> >> ENDPROC(aesni_set_key) > >> > > >> > So cannot we make this a bit more compact and less fragile? > >> > > >> > Instead of: > >> > > >> > ENTRY(aesni_set_key) > >> > FRAME > >> > ... > >> > ENDFRAME > >> > ret > >> > ENDPROC(aesni_set_key) > >> > > >> > > >> > How about writing this as: > >> > > >> > FUNCTION_ENTRY(aesni_set_key) > >> > ... > >> > FUNCTION_RETURN(aesni_set_key) > >> > > >> > which does the same thing in a short, symmetric construct? > >> > > >> > One potential problem with this approach would be that what 'looks' like an entry > >> > declaration, but it will now generate real code. > >> > > >> > OTOH if people find this intuitive enough then it's a lot harder to mess it up, > >> > and I think 'RETURN' makes it clear enough that there's a real instruction > >> > generated there. > >> > > >> > >> How about FUNCTION_PROLOGUE and FUNCTION_EPILOGUE? > > > > Perhaps the macro name should describe what the epilogue does, since > > frame pointers aren't required for _all_ functions, only those which > > don't have call instructions. > > > > What do you think about ENTRY_FRAME and ENDPROC_FRAME_RETURN? The > > ending macro is kind of long, but at least it a) matches the existing > > ENTRY/ENDPROC convention for asm functions; b) gives a clue that frame > > pointers are involved; and c) lets you know that the return is there. > > > > This really is about frame pointers, right? How about > ENTRY_FRAMEPTR_xyz where xyz can be prologue, epilogue, return, > whatever? Wouldn't the "ENTRY" in ENTRY_FRAMEPTR_RETURN be confusing at the end of a function? -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-17 20:44 ` Josh Poimboeuf @ 2015-07-17 20:46 ` Andy Lutomirski 2015-07-17 20:59 ` Josh Poimboeuf 0 siblings, 1 reply; 89+ messages in thread From: Andy Lutomirski @ 2015-07-17 20:46 UTC (permalink / raw) To: Josh Poimboeuf Cc: Ingo Molnar, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Fri, Jul 17, 2015 at 1:44 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > On Fri, Jul 17, 2015 at 01:39:09PM -0700, Andy Lutomirski wrote: >> On Fri, Jul 17, 2015 at 1:37 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: >> > On Fri, Jul 17, 2015 at 12:44:42PM -0700, Andy Lutomirski wrote: >> >> On Fri, Jul 17, 2015 at 12:43 PM, Ingo Molnar <mingo@kernel.org> wrote: >> >> > >> >> > * Josh Poimboeuf <jpoimboe@redhat.com> wrote: >> >> > >> >> >> ENTRY(aesni_set_key) >> >> >> + FRAME >> >> >> #ifndef __x86_64__ >> >> >> pushl KEYP >> >> >> movl 8(%esp), KEYP # ctx >> >> >> @@ -1905,6 +1907,7 @@ ENTRY(aesni_set_key) >> >> >> #ifndef __x86_64__ >> >> >> popl KEYP >> >> >> #endif >> >> >> + ENDFRAME >> >> >> ret >> >> >> ENDPROC(aesni_set_key) >> >> > >> >> > So cannot we make this a bit more compact and less fragile? >> >> > >> >> > Instead of: >> >> > >> >> > ENTRY(aesni_set_key) >> >> > FRAME >> >> > ... >> >> > ENDFRAME >> >> > ret >> >> > ENDPROC(aesni_set_key) >> >> > >> >> > >> >> > How about writing this as: >> >> > >> >> > FUNCTION_ENTRY(aesni_set_key) >> >> > ... >> >> > FUNCTION_RETURN(aesni_set_key) >> >> > >> >> > which does the same thing in a short, symmetric construct? >> >> > >> >> > One potential problem with this approach would be that what 'looks' like an entry >> >> > declaration, but it will now generate real code. >> >> > >> >> > OTOH if people find this intuitive enough then it's a lot harder to mess it up, >> >> > and I think 'RETURN' makes it clear enough that there's a real instruction >> >> > generated there. >> >> > >> >> >> >> How about FUNCTION_PROLOGUE and FUNCTION_EPILOGUE? >> > >> > Perhaps the macro name should describe what the epilogue does, since >> > frame pointers aren't required for _all_ functions, only those which >> > don't have call instructions. >> > >> > What do you think about ENTRY_FRAME and ENDPROC_FRAME_RETURN? The >> > ending macro is kind of long, but at least it a) matches the existing >> > ENTRY/ENDPROC convention for asm functions; b) gives a clue that frame >> > pointers are involved; and c) lets you know that the return is there. >> > >> >> This really is about frame pointers, right? How about >> ENTRY_FRAMEPTR_xyz where xyz can be prologue, epilogue, return, >> whatever? > > Wouldn't the "ENTRY" in ENTRY_FRAMEPTR_RETURN be confusing at the end of > a function? I meant ENTRY_FRAMEPTR_xyz and the beginning and ENDPROC_FRAMEPTR_xyz (ENTRY is debatable, but that's what we currently have). ENDPROC could easily be replaced with anything else. --Andy > > -- > Josh -- Andy Lutomirski AMA Capital Management, LLC ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-17 20:46 ` Andy Lutomirski @ 2015-07-17 20:59 ` Josh Poimboeuf 2015-07-17 21:01 ` Andy Lutomirski 0 siblings, 1 reply; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 20:59 UTC (permalink / raw) To: Andy Lutomirski Cc: Ingo Molnar, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Fri, Jul 17, 2015 at 01:46:39PM -0700, Andy Lutomirski wrote: > On Fri, Jul 17, 2015 at 1:44 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > > On Fri, Jul 17, 2015 at 01:39:09PM -0700, Andy Lutomirski wrote: > >> On Fri, Jul 17, 2015 at 1:37 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > >> > On Fri, Jul 17, 2015 at 12:44:42PM -0700, Andy Lutomirski wrote: > >> >> On Fri, Jul 17, 2015 at 12:43 PM, Ingo Molnar <mingo@kernel.org> wrote: > >> >> > > >> >> > * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > >> >> > > >> >> >> ENTRY(aesni_set_key) > >> >> >> + FRAME > >> >> >> #ifndef __x86_64__ > >> >> >> pushl KEYP > >> >> >> movl 8(%esp), KEYP # ctx > >> >> >> @@ -1905,6 +1907,7 @@ ENTRY(aesni_set_key) > >> >> >> #ifndef __x86_64__ > >> >> >> popl KEYP > >> >> >> #endif > >> >> >> + ENDFRAME > >> >> >> ret > >> >> >> ENDPROC(aesni_set_key) > >> >> > > >> >> > So cannot we make this a bit more compact and less fragile? > >> >> > > >> >> > Instead of: > >> >> > > >> >> > ENTRY(aesni_set_key) > >> >> > FRAME > >> >> > ... > >> >> > ENDFRAME > >> >> > ret > >> >> > ENDPROC(aesni_set_key) > >> >> > > >> >> > > >> >> > How about writing this as: > >> >> > > >> >> > FUNCTION_ENTRY(aesni_set_key) > >> >> > ... > >> >> > FUNCTION_RETURN(aesni_set_key) > >> >> > > >> >> > which does the same thing in a short, symmetric construct? > >> >> > > >> >> > One potential problem with this approach would be that what 'looks' like an entry > >> >> > declaration, but it will now generate real code. > >> >> > > >> >> > OTOH if people find this intuitive enough then it's a lot harder to mess it up, > >> >> > and I think 'RETURN' makes it clear enough that there's a real instruction > >> >> > generated there. > >> >> > > >> >> > >> >> How about FUNCTION_PROLOGUE and FUNCTION_EPILOGUE? > >> > > >> > Perhaps the macro name should describe what the epilogue does, since > >> > frame pointers aren't required for _all_ functions, only those which > >> > don't have call instructions. > >> > > >> > What do you think about ENTRY_FRAME and ENDPROC_FRAME_RETURN? The > >> > ending macro is kind of long, but at least it a) matches the existing > >> > ENTRY/ENDPROC convention for asm functions; b) gives a clue that frame > >> > pointers are involved; and c) lets you know that the return is there. > >> > > >> > >> This really is about frame pointers, right? How about > >> ENTRY_FRAMEPTR_xyz where xyz can be prologue, epilogue, return, > >> whatever? > > > > Wouldn't the "ENTRY" in ENTRY_FRAMEPTR_RETURN be confusing at the end of > > a function? > > I meant ENTRY_FRAMEPTR_xyz and the beginning and ENDPROC_FRAMEPTR_xyz > (ENTRY is debatable, but that's what we currently have). ENDPROC > could easily be replaced with anything else. So do you mean ENTRY_FRAMEPTR_PROLOGUE and ENDPROC_FRAMEPTR_EPILOGUE? Or something else? -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-17 20:59 ` Josh Poimboeuf @ 2015-07-17 21:01 ` Andy Lutomirski 2015-07-17 21:10 ` Josh Poimboeuf 0 siblings, 1 reply; 89+ messages in thread From: Andy Lutomirski @ 2015-07-17 21:01 UTC (permalink / raw) To: Josh Poimboeuf Cc: Ingo Molnar, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Fri, Jul 17, 2015 at 1:59 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > On Fri, Jul 17, 2015 at 01:46:39PM -0700, Andy Lutomirski wrote: >> On Fri, Jul 17, 2015 at 1:44 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: >> > On Fri, Jul 17, 2015 at 01:39:09PM -0700, Andy Lutomirski wrote: >> >> On Fri, Jul 17, 2015 at 1:37 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: >> >> > On Fri, Jul 17, 2015 at 12:44:42PM -0700, Andy Lutomirski wrote: >> >> >> On Fri, Jul 17, 2015 at 12:43 PM, Ingo Molnar <mingo@kernel.org> wrote: >> >> >> > >> >> >> > * Josh Poimboeuf <jpoimboe@redhat.com> wrote: >> >> >> > >> >> >> >> ENTRY(aesni_set_key) >> >> >> >> + FRAME >> >> >> >> #ifndef __x86_64__ >> >> >> >> pushl KEYP >> >> >> >> movl 8(%esp), KEYP # ctx >> >> >> >> @@ -1905,6 +1907,7 @@ ENTRY(aesni_set_key) >> >> >> >> #ifndef __x86_64__ >> >> >> >> popl KEYP >> >> >> >> #endif >> >> >> >> + ENDFRAME >> >> >> >> ret >> >> >> >> ENDPROC(aesni_set_key) >> >> >> > >> >> >> > So cannot we make this a bit more compact and less fragile? >> >> >> > >> >> >> > Instead of: >> >> >> > >> >> >> > ENTRY(aesni_set_key) >> >> >> > FRAME >> >> >> > ... >> >> >> > ENDFRAME >> >> >> > ret >> >> >> > ENDPROC(aesni_set_key) >> >> >> > >> >> >> > >> >> >> > How about writing this as: >> >> >> > >> >> >> > FUNCTION_ENTRY(aesni_set_key) >> >> >> > ... >> >> >> > FUNCTION_RETURN(aesni_set_key) >> >> >> > >> >> >> > which does the same thing in a short, symmetric construct? >> >> >> > >> >> >> > One potential problem with this approach would be that what 'looks' like an entry >> >> >> > declaration, but it will now generate real code. >> >> >> > >> >> >> > OTOH if people find this intuitive enough then it's a lot harder to mess it up, >> >> >> > and I think 'RETURN' makes it clear enough that there's a real instruction >> >> >> > generated there. >> >> >> > >> >> >> >> >> >> How about FUNCTION_PROLOGUE and FUNCTION_EPILOGUE? >> >> > >> >> > Perhaps the macro name should describe what the epilogue does, since >> >> > frame pointers aren't required for _all_ functions, only those which >> >> > don't have call instructions. >> >> > >> >> > What do you think about ENTRY_FRAME and ENDPROC_FRAME_RETURN? The >> >> > ending macro is kind of long, but at least it a) matches the existing >> >> > ENTRY/ENDPROC convention for asm functions; b) gives a clue that frame >> >> > pointers are involved; and c) lets you know that the return is there. >> >> > >> >> >> >> This really is about frame pointers, right? How about >> >> ENTRY_FRAMEPTR_xyz where xyz can be prologue, epilogue, return, >> >> whatever? >> > >> > Wouldn't the "ENTRY" in ENTRY_FRAMEPTR_RETURN be confusing at the end of >> > a function? >> >> I meant ENTRY_FRAMEPTR_xyz and the beginning and ENDPROC_FRAMEPTR_xyz >> (ENTRY is debatable, but that's what we currently have). ENDPROC >> could easily be replaced with anything else. > > So do you mean ENTRY_FRAMEPTR_PROLOGUE and ENDPROC_FRAMEPTR_EPILOGUE? > Or something else? > I like it. I think this bikeshed might be well painted now! --Andy > -- > Josh -- Andy Lutomirski AMA Capital Management, LLC ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-17 21:01 ` Andy Lutomirski @ 2015-07-17 21:10 ` Josh Poimboeuf 2015-07-18 8:42 ` Borislav Petkov 0 siblings, 1 reply; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 21:10 UTC (permalink / raw) To: Andy Lutomirski Cc: Ingo Molnar, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Fri, Jul 17, 2015 at 02:01:33PM -0700, Andy Lutomirski wrote: > On Fri, Jul 17, 2015 at 1:59 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > > On Fri, Jul 17, 2015 at 01:46:39PM -0700, Andy Lutomirski wrote: > >> On Fri, Jul 17, 2015 at 1:44 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > >> > On Fri, Jul 17, 2015 at 01:39:09PM -0700, Andy Lutomirski wrote: > >> >> On Fri, Jul 17, 2015 at 1:37 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > >> >> > On Fri, Jul 17, 2015 at 12:44:42PM -0700, Andy Lutomirski wrote: > >> >> >> On Fri, Jul 17, 2015 at 12:43 PM, Ingo Molnar <mingo@kernel.org> wrote: > >> >> >> > > >> >> >> > * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > >> >> >> > > >> >> >> >> ENTRY(aesni_set_key) > >> >> >> >> + FRAME > >> >> >> >> #ifndef __x86_64__ > >> >> >> >> pushl KEYP > >> >> >> >> movl 8(%esp), KEYP # ctx > >> >> >> >> @@ -1905,6 +1907,7 @@ ENTRY(aesni_set_key) > >> >> >> >> #ifndef __x86_64__ > >> >> >> >> popl KEYP > >> >> >> >> #endif > >> >> >> >> + ENDFRAME > >> >> >> >> ret > >> >> >> >> ENDPROC(aesni_set_key) > >> >> >> > > >> >> >> > So cannot we make this a bit more compact and less fragile? > >> >> >> > > >> >> >> > Instead of: > >> >> >> > > >> >> >> > ENTRY(aesni_set_key) > >> >> >> > FRAME > >> >> >> > ... > >> >> >> > ENDFRAME > >> >> >> > ret > >> >> >> > ENDPROC(aesni_set_key) > >> >> >> > > >> >> >> > > >> >> >> > How about writing this as: > >> >> >> > > >> >> >> > FUNCTION_ENTRY(aesni_set_key) > >> >> >> > ... > >> >> >> > FUNCTION_RETURN(aesni_set_key) > >> >> >> > > >> >> >> > which does the same thing in a short, symmetric construct? > >> >> >> > > >> >> >> > One potential problem with this approach would be that what 'looks' like an entry > >> >> >> > declaration, but it will now generate real code. > >> >> >> > > >> >> >> > OTOH if people find this intuitive enough then it's a lot harder to mess it up, > >> >> >> > and I think 'RETURN' makes it clear enough that there's a real instruction > >> >> >> > generated there. > >> >> >> > > >> >> >> > >> >> >> How about FUNCTION_PROLOGUE and FUNCTION_EPILOGUE? > >> >> > > >> >> > Perhaps the macro name should describe what the epilogue does, since > >> >> > frame pointers aren't required for _all_ functions, only those which > >> >> > don't have call instructions. > >> >> > > >> >> > What do you think about ENTRY_FRAME and ENDPROC_FRAME_RETURN? The > >> >> > ending macro is kind of long, but at least it a) matches the existing > >> >> > ENTRY/ENDPROC convention for asm functions; b) gives a clue that frame > >> >> > pointers are involved; and c) lets you know that the return is there. > >> >> > > >> >> > >> >> This really is about frame pointers, right? How about > >> >> ENTRY_FRAMEPTR_xyz where xyz can be prologue, epilogue, return, > >> >> whatever? > >> > > >> > Wouldn't the "ENTRY" in ENTRY_FRAMEPTR_RETURN be confusing at the end of > >> > a function? > >> > >> I meant ENTRY_FRAMEPTR_xyz and the beginning and ENDPROC_FRAMEPTR_xyz > >> (ENTRY is debatable, but that's what we currently have). ENDPROC > >> could easily be replaced with anything else. > > > > So do you mean ENTRY_FRAMEPTR_PROLOGUE and ENDPROC_FRAMEPTR_EPILOGUE? > > Or something else? > > > > I like it. I think this bikeshed might be well painted now! Actually I'm not done painting. Personally it seems a little too verbose. I still like ENTRY_FRAME and ENDPROC_FRAME_RETURN :p -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-17 21:10 ` Josh Poimboeuf @ 2015-07-18 8:42 ` Borislav Petkov 2015-07-18 13:46 ` Josh Poimboeuf 0 siblings, 1 reply; 89+ messages in thread From: Borislav Petkov @ 2015-07-18 8:42 UTC (permalink / raw) To: Josh Poimboeuf Cc: Andy Lutomirski, Ingo Molnar, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Fri, Jul 17, 2015 at 04:10:19PM -0500, Josh Poimboeuf wrote: > Actually I'm not done painting. Personally it seems a little too > verbose. I still like ENTRY_FRAME and ENDPROC_FRAME_RETURN :p Let's balance it out even more: ENTRY_FRAME(..) ... ENDPROC_FRAME(..) -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply. -- ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-18 8:42 ` Borislav Petkov @ 2015-07-18 13:46 ` Josh Poimboeuf 2015-07-18 14:25 ` Borislav Petkov 0 siblings, 1 reply; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-18 13:46 UTC (permalink / raw) To: Borislav Petkov Cc: Andy Lutomirski, Ingo Molnar, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Sat, Jul 18, 2015 at 10:42:36AM +0200, Borislav Petkov wrote: > On Fri, Jul 17, 2015 at 04:10:19PM -0500, Josh Poimboeuf wrote: > > Actually I'm not done painting. Personally it seems a little too > > verbose. I still like ENTRY_FRAME and ENDPROC_FRAME_RETURN :p > > Let's balance it out even more: > > ENTRY_FRAME(..) > > ... > > ENDPROC_FRAME(..) I like the balance, but the "ret" is still non-obvious. How about: FRAME_ENTRY(...) FRAME_RETURN(...) -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-18 13:46 ` Josh Poimboeuf @ 2015-07-18 14:25 ` Borislav Petkov 2015-07-18 15:40 ` Josh Poimboeuf 0 siblings, 1 reply; 89+ messages in thread From: Borislav Petkov @ 2015-07-18 14:25 UTC (permalink / raw) To: Josh Poimboeuf Cc: Andy Lutomirski, Ingo Molnar, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Sat, Jul 18, 2015 at 08:46:55AM -0500, Josh Poimboeuf wrote: > I like the balance, but the "ret" is still non-obvious. Does it have to be obvious? -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply. -- ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-18 14:25 ` Borislav Petkov @ 2015-07-18 15:40 ` Josh Poimboeuf 0 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-18 15:40 UTC (permalink / raw) To: Borislav Petkov Cc: Andy Lutomirski, Ingo Molnar, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Sat, Jul 18, 2015 at 04:25:25PM +0200, Borislav Petkov wrote: > On Sat, Jul 18, 2015 at 08:46:55AM -0500, Josh Poimboeuf wrote: > > I like the balance, but the "ret" is still non-obvious. > > Does it have to be obvious? I feel that making "ret" obvious is better. But if somebody messes up and adds a second "ret", I suppose stackvalidate would warn about the fact that it returned without restoring the frame pointer. So if there are no other objections, your suggestion of ENTRY_FRAME and ENDPROC_FRAME is fine with me. -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-17 20:37 ` Josh Poimboeuf 2015-07-17 20:39 ` Andy Lutomirski @ 2015-07-18 2:51 ` Ingo Molnar 2015-07-18 3:56 ` Josh Poimboeuf 1 sibling, 1 reply; 89+ messages in thread From: Ingo Molnar @ 2015-07-18 2:51 UTC (permalink / raw) To: Josh Poimboeuf Cc: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > On Fri, Jul 17, 2015 at 12:44:42PM -0700, Andy Lutomirski wrote: > > On Fri, Jul 17, 2015 at 12:43 PM, Ingo Molnar <mingo@kernel.org> wrote: > > > > > > * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > > > > > >> ENTRY(aesni_set_key) > > >> + FRAME > > >> #ifndef __x86_64__ > > >> pushl KEYP > > >> movl 8(%esp), KEYP # ctx > > >> @@ -1905,6 +1907,7 @@ ENTRY(aesni_set_key) > > >> #ifndef __x86_64__ > > >> popl KEYP > > >> #endif > > >> + ENDFRAME > > >> ret > > >> ENDPROC(aesni_set_key) > > > > > > So cannot we make this a bit more compact and less fragile? > > > > > > Instead of: > > > > > > ENTRY(aesni_set_key) > > > FRAME > > > ... > > > ENDFRAME > > > ret > > > ENDPROC(aesni_set_key) > > > > > > > > > How about writing this as: > > > > > > FUNCTION_ENTRY(aesni_set_key) > > > ... > > > FUNCTION_RETURN(aesni_set_key) > > > > > > which does the same thing in a short, symmetric construct? > > > > > > One potential problem with this approach would be that what 'looks' like an entry > > > declaration, but it will now generate real code. > > > > > > OTOH if people find this intuitive enough then it's a lot harder to mess it up, > > > and I think 'RETURN' makes it clear enough that there's a real instruction > > > generated there. > > > > > > > How about FUNCTION_PROLOGUE and FUNCTION_EPILOGUE? > > Perhaps the macro name should describe what the epilogue does, since > frame pointers aren't required for _all_ functions, only those which > don't have call instructions. > > What do you think about ENTRY_FRAME and ENDPROC_FRAME_RETURN? The > ending macro is kind of long, but at least it a) matches the existing > ENTRY/ENDPROC convention for asm functions; b) gives a clue that frame > pointers are involved; and c) lets you know that the return is there. So the thing I like about these: FUNCTION_ENTRY(aesni_set_key) ... FUNCTION_RETURN(aesni_set_key) is the symmetry - it's a lot harder to misplace/miswrite these than two completely separately named things: ENTRY_FRAME(aesni_set_key) ... ENDPROC_FRAME_RETURN(aesni_set_key) Also, the 'FRAME' part will be pointless and somewhat misleading once we do dwarves, right? Another valid variants would be: FUNCTION_ENTER(aesni_set_key) ... FUNCTION_RET(aesni_set_key) or: FUNCTION_START(aesni_set_key) ... FUNCTION_RET(aesni_set_key) or: ASM_FUNCTION_START(aesni_set_key) ... ASM_FUNCTION_RET(aesni_set_key) Note that the name has two parts: - The symmetric 'FUNCTION_' prefix tells us that this is a callable function that we are defining. That is a very significant property of this construct, and should be present in both the 'start' and the 'end' markers. - The '_RET' stresses the fact that it always generates a 'ret' instruction. Note what the names _don't_ contain: that we generate debug info! That fact is not present in the naming, and that's very much intentional, because the precise form of debug info is conditional: - if CONFIG_FRAME_POINTERS=y then we push/pop a stack frame - if (later on) we do CFI annotations we don't push/pop a stack frame but emit CFI debuginfo In that sense 'FRAME' should never be in these names I think, nor 'PROC' (which is not symmetric). Plus all 3 variants I suggested are very easy to remember, why I'd always have to look up any non-symmetric macro name called 'PROC'... Thanks, Ingo ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-18 2:51 ` Ingo Molnar @ 2015-07-18 3:56 ` Josh Poimboeuf 2015-07-20 7:56 ` Ingo Molnar 2015-07-20 15:30 ` Andy Lutomirski 0 siblings, 2 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-18 3:56 UTC (permalink / raw) To: Ingo Molnar Cc: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Sat, Jul 18, 2015 at 04:51:16AM +0200, Ingo Molnar wrote: > Note what the names _don't_ contain: that we generate debug info! That fact is not > present in the naming, and that's very much intentional, because the precise form > of debug info is conditional: > > - if CONFIG_FRAME_POINTERS=y then we push/pop a stack frame > > - if (later on) we do CFI annotations we don't push/pop a stack frame but emit > CFI debuginfo According to current plan, the macro won't add CFI annotations. That will be done instead by a separate tool. So the macro really is frame pointer specific. > > In that sense 'FRAME' should never be in these names I think, nor 'PROC' (which is > not symmetric). > > Plus all 3 variants I suggested are very easy to remember, why I'd always have to > look up any non-symmetric macro name called 'PROC'... The reason I suggested to put FRAME in the macro name is to try to prevent it from being accidentally used for leaf functions, where it isn't needed. Also the naming of FUNCTION_ENTRY and FUNCTION_RETURN doesn't do anything to distinguish them from the already ubiquitous ENTRY and ENDPROC. So as a kernel developer it seems confusing to me, e.g. how do I remember when to use FUNCTION_ENTRY vs ENTRY? -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-18 3:56 ` Josh Poimboeuf @ 2015-07-20 7:56 ` Ingo Molnar 2015-07-20 13:59 ` Josh Poimboeuf 2015-07-20 15:30 ` Andy Lutomirski 1 sibling, 1 reply; 89+ messages in thread From: Ingo Molnar @ 2015-07-20 7:56 UTC (permalink / raw) To: Josh Poimboeuf Cc: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > On Sat, Jul 18, 2015 at 04:51:16AM +0200, Ingo Molnar wrote: > > Note what the names _don't_ contain: that we generate debug info! That fact is not > > present in the naming, and that's very much intentional, because the precise form > > of debug info is conditional: > > > > - if CONFIG_FRAME_POINTERS=y then we push/pop a stack frame > > > > - if (later on) we do CFI annotations we don't push/pop a stack frame but emit > > CFI debuginfo > > According to current plan, the macro won't add CFI annotations. That will be > done instead by a separate tool. So the macro really is frame pointer specific. Still the same argument applies: it's a debug info detail we should hide as much as sensibly possible. In the CONFIG_FRAME_POINTERS=y case it will be code, in the future !CONFIG_FRAME_POINTERS case it will be nothing. > > In that sense 'FRAME' should never be in these names I think, nor 'PROC' > > (which is not symmetric). > > > > Plus all 3 variants I suggested are very easy to remember, why I'd always have > > to look up any non-symmetric macro name called 'PROC'... > > The reason I suggested to put FRAME in the macro name is to try to prevent it > from being accidentally used for leaf functions, where it isn't needed. Well, we could use LEAF_FUNCTION to mark that fact. Wether a function written in assembly is a leaf function or not is a higher level (and thus more valuable) piece of information whether we generate frame pointer debuginfo or not. > Also the naming of FUNCTION_ENTRY and FUNCTION_RETURN doesn't do anything to > distinguish them from the already ubiquitous ENTRY and ENDPROC. So as a kernel > developer it seems confusing to me, e.g. how do I remember when to use > FUNCTION_ENTRY vs ENTRY? 'ENDPROC' is really leftover from older debuginfo cruft, it's not a valuable construct IMHO, even if it's (sadly) ubiquitious. We want to create new, clean, as minimal as possible and as clearly named as possible debuginfo constructs from first principles. Thanks, Ingo ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-20 7:56 ` Ingo Molnar @ 2015-07-20 13:59 ` Josh Poimboeuf 2015-07-20 17:21 ` Ingo Molnar 0 siblings, 1 reply; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-20 13:59 UTC (permalink / raw) To: Ingo Molnar Cc: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Mon, Jul 20, 2015 at 09:56:11AM +0200, Ingo Molnar wrote: > > > > The reason I suggested to put FRAME in the macro name is to try to prevent it > > from being accidentally used for leaf functions, where it isn't needed. > > Well, we could use LEAF_FUNCTION to mark that fact. > > Wether a function written in assembly is a leaf function or not is a higher level > (and thus more valuable) piece of information whether we generate frame pointer > debuginfo or not. > > > Also the naming of FUNCTION_ENTRY and FUNCTION_RETURN doesn't do anything to > > distinguish them from the already ubiquitous ENTRY and ENDPROC. So as a kernel > > developer it seems confusing to me, e.g. how do I remember when to use > > FUNCTION_ENTRY vs ENTRY? > > 'ENDPROC' is really leftover from older debuginfo cruft, it's not a valuable > construct IMHO, even if it's (sadly) ubiquitious. > > We want to create new, clean, as minimal as possible and as clearly named as > possible debuginfo constructs from first principles. Ok. So if I understand right, the proposal is: Replace *all* x86 usage of ENTRY/ENDPROC with either: FUNCTION_ENTRY(func) FUNCTION_RETURN(func) or LEAF_FUNCTION_ENTRY(func) LEAF_FUNCTION_RETURN(func) Those sound fine to me. I should point out that there are still a few cases where the more granular FRAME/ENDFRAME and ENTRY/ENDPROC macros would still be needed. For example, if the function ends with a jump instead of a ret. If the jump is a sibling call, the code would look like: FUNCTION_ENTRY(func) ... ENDFRAME jmp another_func ENDPROC(func) Or if it's a jump within the function to an internal ret: FUNCTION_ENTRY(func) ... 1: ... ENDFRAME ret 2: ... jmp 1b ENDPROC(func) Or if it jumps to some shared code before returning: FUNCTION_ENTRY(func_1) ... jmp common_return ENDPROC(func_1) FUNCTION_ENTRY(func_2) ... jmp common_return ENDPROC(func_2) common_return: ... ENDFRAME ret So in some cases we'd still need the more granular macros, unless we decided to make special macros for these cases as well. -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-20 13:59 ` Josh Poimboeuf @ 2015-07-20 17:21 ` Ingo Molnar 2015-07-20 18:00 ` Josh Poimboeuf 0 siblings, 1 reply; 89+ messages in thread From: Ingo Molnar @ 2015-07-20 17:21 UTC (permalink / raw) To: Josh Poimboeuf Cc: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > On Mon, Jul 20, 2015 at 09:56:11AM +0200, Ingo Molnar wrote: > > > > > > The reason I suggested to put FRAME in the macro name is to try to prevent it > > > from being accidentally used for leaf functions, where it isn't needed. > > > > Well, we could use LEAF_FUNCTION to mark that fact. > > > > Wether a function written in assembly is a leaf function or not is a higher level > > (and thus more valuable) piece of information whether we generate frame pointer > > debuginfo or not. > > > > > Also the naming of FUNCTION_ENTRY and FUNCTION_RETURN doesn't do anything to > > > distinguish them from the already ubiquitous ENTRY and ENDPROC. So as a kernel > > > developer it seems confusing to me, e.g. how do I remember when to use > > > FUNCTION_ENTRY vs ENTRY? > > > > 'ENDPROC' is really leftover from older debuginfo cruft, it's not a valuable > > construct IMHO, even if it's (sadly) ubiquitious. > > > > We want to create new, clean, as minimal as possible and as clearly named as > > possible debuginfo constructs from first principles. > > Ok. So if I understand right, the proposal is: > > Replace *all* x86 usage of ENTRY/ENDPROC with either: > > FUNCTION_ENTRY(func) > FUNCTION_RETURN(func) > > or > > LEAF_FUNCTION_ENTRY(func) > LEAF_FUNCTION_RETURN(func) > > Those sound fine to me. Yeah - but keep the old constructs as well and don't necessarily do the full migration straight away, only once the dust has settled - to reduce churn. > I should point out that there are still a few cases where the more granular > FRAME/ENDFRAME and ENTRY/ENDPROC macros would still be needed. > > For example, if the function ends with a jump instead of a ret. If the > jump is a sibling call, the code would look like: > > FUNCTION_ENTRY(func) > ... > ENDFRAME > jmp another_func > ENDPROC(func) > > > Or if it's a jump within the function to an internal ret: > > FUNCTION_ENTRY(func) > ... > 1: ... > ENDFRAME > ret > 2: ... > jmp 1b > ENDPROC(func) > > > Or if it jumps to some shared code before returning: > > FUNCTION_ENTRY(func_1) > ... > jmp common_return > ENDPROC(func_1) > > FUNCTION_ENTRY(func_2) > ... > jmp common_return > ENDPROC(func_2) > > common_return: > ... > ENDFRAME > ret > > > So in some cases we'd still need the more granular macros, unless we > decided to make special macros for these cases as well. Ok, I see how the naming scheme I proposed won't work with all that very well, but I'd still suggest using consistently named patterns. Let me suggest yet another approach. How about open-coding something like this: FUNCTION_START(func) push_bp mov_sp_bp ... pop_bp ret FUNCTION_END(func) This is just two easy things: - a redefine of the FUNCTION_ENTRY and ENDPROC names - the introduction of three quasi-mnemonics: push_bp, mov_sp_bp, pop_bp - which all look very similar to a real frame setup sequence, except that we can easily make them go away in the !CONFIG_FRAME_POINTERS case. The advantage of this approach would be: - it looks pretty 'natural' and very close to how the real disassembly looks like in CONFIG_FRAME_POINTERS=y kernels. So while it's not as compact as some of the other variants, it's close to what the real instruction sequence looks like and that is a positive quality in itself. - it also makes it apparent 'on sight' that it's probably a bug to have unbalanced push/pop sequences in a regular function, to any reasonably alert assembly coder. - if we ever unsupport framepointer kernels in the (far far) future, we can get rid of all lines with those 3 mnemonics and be done with it. - it's finegrained enough so that we can express all the special function/tail variants you listed above. What do you think? I'd still keep existing frame setup functionality and names and only use these in fixes, new code and new annotations - and do a full rename and cleanup once the dust has settled. Thanks, Ingo ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-20 17:21 ` Ingo Molnar @ 2015-07-20 18:00 ` Josh Poimboeuf 2015-07-22 11:52 ` Josh Poimboeuf 0 siblings, 1 reply; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-20 18:00 UTC (permalink / raw) To: Ingo Molnar Cc: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Mon, Jul 20, 2015 at 07:21:24PM +0200, Ingo Molnar wrote: > * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > > On Mon, Jul 20, 2015 at 09:56:11AM +0200, Ingo Molnar wrote: > > I should point out that there are still a few cases where the more granular > > FRAME/ENDFRAME and ENTRY/ENDPROC macros would still be needed. > > > > For example, if the function ends with a jump instead of a ret. If the > > jump is a sibling call, the code would look like: > > > > FUNCTION_ENTRY(func) > > ... > > ENDFRAME > > jmp another_func > > ENDPROC(func) > > > > > > Or if it's a jump within the function to an internal ret: > > > > FUNCTION_ENTRY(func) > > ... > > 1: ... > > ENDFRAME > > ret > > 2: ... > > jmp 1b > > ENDPROC(func) > > > > > > Or if it jumps to some shared code before returning: > > > > FUNCTION_ENTRY(func_1) > > ... > > jmp common_return > > ENDPROC(func_1) > > > > FUNCTION_ENTRY(func_2) > > ... > > jmp common_return > > ENDPROC(func_2) > > > > common_return: > > ... > > ENDFRAME > > ret > > > > > > So in some cases we'd still need the more granular macros, unless we > > decided to make special macros for these cases as well. > > Ok, I see how the naming scheme I proposed won't work with all that very well, but > I'd still suggest using consistently named patterns. > > Let me suggest yet another approach. How about open-coding something like this: > > FUNCTION_START(func) > > push_bp > mov_sp_bp > > ... > > pop_bp > ret > > FUNCTION_END(func) > > This is just two easy things: > > - a redefine of the FUNCTION_ENTRY and ENDPROC names > > - the introduction of three quasi-mnemonics: push_bp, mov_sp_bp, pop_bp - which > all look very similar to a real frame setup sequence, except that we can easily > make them go away in the !CONFIG_FRAME_POINTERS case. > > The advantage of this approach would be: > > - it looks pretty 'natural' and very close to how the real disassembly looks > like in CONFIG_FRAME_POINTERS=y kernels. So while it's not as compact as some > of the other variants, it's close to what the real instruction sequence looks > like and that is a positive quality in itself. > > - it also makes it apparent 'on sight' that it's probably a bug to have > unbalanced push/pop sequences in a regular function, to any reasonably alert > assembly coder. > > - if we ever unsupport framepointer kernels in the (far far) future, we can get > rid of all lines with those 3 mnemonics and be done with it. > > - it's finegrained enough so that we can express all the special function/tail > variants you listed above. > > What do you think? I agree that the edge cases make FUNCTION_ENTRY and FUNCTION_RETURN less attractive. Slowly we are circling around to where we started :-) Personally, I prefer FRAME/ENDFRAME instead of push_bp/mov_sp_bp/pop_bp, because it more communicates *what* it's doing rather than how. IMO, it's easier to grok with a quick glance. > I'd still keep existing frame setup functionality and names and only use these in > fixes, new code and new annotations - and do a full rename and cleanup once the > dust has settled. That sounds good. -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-20 18:00 ` Josh Poimboeuf @ 2015-07-22 11:52 ` Josh Poimboeuf 0 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-22 11:52 UTC (permalink / raw) To: Ingo Molnar Cc: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Mon, Jul 20, 2015 at 01:00:06PM -0500, Josh Poimboeuf wrote: > On Mon, Jul 20, 2015 at 07:21:24PM +0200, Ingo Molnar wrote: > > * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > > Ok, I see how the naming scheme I proposed won't work with all that very well, but > > I'd still suggest using consistently named patterns. > > > > Let me suggest yet another approach. How about open-coding something like this: > > > > FUNCTION_START(func) > > > > push_bp > > mov_sp_bp > > > > ... > > > > pop_bp > > ret > > > > FUNCTION_END(func) > > > > This is just two easy things: > > > > - a redefine of the FUNCTION_ENTRY and ENDPROC names > > > > - the introduction of three quasi-mnemonics: push_bp, mov_sp_bp, pop_bp - which > > all look very similar to a real frame setup sequence, except that we can easily > > make them go away in the !CONFIG_FRAME_POINTERS case. > > > > The advantage of this approach would be: > > > > - it looks pretty 'natural' and very close to how the real disassembly looks > > like in CONFIG_FRAME_POINTERS=y kernels. So while it's not as compact as some > > of the other variants, it's close to what the real instruction sequence looks > > like and that is a positive quality in itself. > > > > - it also makes it apparent 'on sight' that it's probably a bug to have > > unbalanced push/pop sequences in a regular function, to any reasonably alert > > assembly coder. > > > > - if we ever unsupport framepointer kernels in the (far far) future, we can get > > rid of all lines with those 3 mnemonics and be done with it. > > > > - it's finegrained enough so that we can express all the special function/tail > > variants you listed above. > > > > What do you think? > > I agree that the edge cases make FUNCTION_ENTRY and FUNCTION_RETURN less > attractive. Slowly we are circling around to where we started :-) > > Personally, I prefer FRAME/ENDFRAME instead of push_bp/mov_sp_bp/pop_bp, > because it more communicates *what* it's doing rather than how. IMO, > it's easier to grok with a quick glance. Ingo, any chance this last paragraph was a convincing argument to continue to use FRAME/ENDFRAME over push_bp/mov_sp_bp/pop_bp? (I think this is the last outstanding issue from the reviews, so I'm all set to send out a new version of the patches once there's agreement on this issue.) -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-18 3:56 ` Josh Poimboeuf 2015-07-20 7:56 ` Ingo Molnar @ 2015-07-20 15:30 ` Andy Lutomirski 2015-07-20 16:36 ` Josh Poimboeuf 1 sibling, 1 reply; 89+ messages in thread From: Andy Lutomirski @ 2015-07-20 15:30 UTC (permalink / raw) To: Josh Poimboeuf Cc: Ingo Molnar, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Fri, Jul 17, 2015 at 8:56 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > The reason I suggested to put FRAME in the macro name is to try to > prevent it from being accidentally used for leaf functions, where it > isn't needed. > Could someone remind me why it isn't needed for leaf functions? --Andy ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-20 15:30 ` Andy Lutomirski @ 2015-07-20 16:36 ` Josh Poimboeuf 2015-07-20 16:52 ` Peter Zijlstra 2015-07-21 8:00 ` Ingo Molnar 0 siblings, 2 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-20 16:36 UTC (permalink / raw) To: Andy Lutomirski Cc: Ingo Molnar, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Mon, Jul 20, 2015 at 08:30:52AM -0700, Andy Lutomirski wrote: > On Fri, Jul 17, 2015 at 8:56 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > > The reason I suggested to put FRAME in the macro name is to try to > > prevent it from being accidentally used for leaf functions, where it > > isn't needed. > > > > Could someone remind me why it isn't needed for leaf functions? If a function doesn't call any other functions, then it won't ever show up in a stack trace unless: a) the function itself walks the stack, in which case the frame pointer isn't necessary; or b) The function gets hit by an interrupt/exception, in which case frame pointers can't be 100% relied upon anyway. I've noticed that gcc *does* seem to create stack frames for leaf functions. But it's inconsistent, because the early exit path of some functions will skip the stack frame creation and go straight to the return. We could probably get a good performance boost with the -momit-leaf-frame-pointer flag. Though it would make stack traces less reliable when a leaf function gets interrupted. -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-20 16:36 ` Josh Poimboeuf @ 2015-07-20 16:52 ` Peter Zijlstra 2015-07-20 17:19 ` Josh Poimboeuf 2015-07-21 8:00 ` Ingo Molnar 1 sibling, 1 reply; 89+ messages in thread From: Peter Zijlstra @ 2015-07-20 16:52 UTC (permalink / raw) To: Josh Poimboeuf Cc: Andy Lutomirski, Ingo Molnar, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Mon, Jul 20, 2015 at 11:36:46AM -0500, Josh Poimboeuf wrote: > If a function doesn't call any other functions, then it won't ever show > up in a stack trace unless: > > a) the function itself walks the stack, in which case the frame pointer > isn't necessary; or > > b) The function gets hit by an interrupt/exception, in which case frame > pointers can't be 100% relied upon anyway. In case the interrupt happens whilst setting up the frame, right? > I've noticed that gcc *does* seem to create stack frames for leaf > functions. But it's inconsistent, because the early exit path of some > functions will skip the stack frame creation and go straight to the > return. > > We could probably get a good performance boost with the > -momit-leaf-frame-pointer flag. Though it would make stack traces less > reliable when a leaf function gets interrupted. So the information we'd loose in that case would be the location in the calling function, right? Which isn't a problem, if the current function (as obtained through RIP) is only ever called once. However if there's multiple call sites this might be a wee bit confusing. ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-20 16:52 ` Peter Zijlstra @ 2015-07-20 17:19 ` Josh Poimboeuf 0 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-20 17:19 UTC (permalink / raw) To: Peter Zijlstra Cc: Andy Lutomirski, Ingo Molnar, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Mon, Jul 20, 2015 at 06:52:32PM +0200, Peter Zijlstra wrote: > On Mon, Jul 20, 2015 at 11:36:46AM -0500, Josh Poimboeuf wrote: > > If a function doesn't call any other functions, then it won't ever show > > up in a stack trace unless: > > > > a) the function itself walks the stack, in which case the frame pointer > > isn't necessary; or > > > > b) The function gets hit by an interrupt/exception, in which case frame > > pointers can't be 100% relied upon anyway. > > In case the interrupt happens whilst setting up the frame, right? Right. > > I've noticed that gcc *does* seem to create stack frames for leaf > > functions. But it's inconsistent, because the early exit path of some > > functions will skip the stack frame creation and go straight to the > > return. > > > > We could probably get a good performance boost with the > > -momit-leaf-frame-pointer flag. Though it would make stack traces less > > reliable when a leaf function gets interrupted. > > So the information we'd loose in that case would be the location in the > calling function, right? Right. > Which isn't a problem, if the current function (as obtained > through RIP) is only ever called once. However if there's multiple call > sites this might be a wee bit confusing. Agreed, though the stack dump code always prints '?' for any kernel address it finds on the stack. So there would still be a good clue. -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-20 16:36 ` Josh Poimboeuf 2015-07-20 16:52 ` Peter Zijlstra @ 2015-07-21 8:00 ` Ingo Molnar 2015-07-21 12:06 ` Josh Poimboeuf 1 sibling, 1 reply; 89+ messages in thread From: Ingo Molnar @ 2015-07-21 8:00 UTC (permalink / raw) To: Josh Poimboeuf Cc: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > On Mon, Jul 20, 2015 at 08:30:52AM -0700, Andy Lutomirski wrote: > > On Fri, Jul 17, 2015 at 8:56 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > > > The reason I suggested to put FRAME in the macro name is to try to > > > prevent it from being accidentally used for leaf functions, where it > > > isn't needed. > > > > > > > Could someone remind me why it isn't needed for leaf functions? > > If a function doesn't call any other functions, then it won't ever show > up in a stack trace unless: > > a) the function itself walks the stack, in which case the frame pointer > isn't necessary; or > > b) The function gets hit by an interrupt/exception, in which case frame > pointers can't be 100% relied upon anyway. > > I've noticed that gcc *does* seem to create stack frames for leaf functions. > But it's inconsistent, because the early exit path of some functions will skip > the stack frame creation and go straight to the return. > > We could probably get a good performance boost with the > -momit-leaf-frame-pointer flag. Though it would make stack traces less reliable > when a leaf function gets interrupted. So in theory we could resolve this during the stack walk: when we pass from the IRQ stack to the process stack we actually know the RIP of the interrupted context, and could include that. Visualizing context boundaries in the stack dump would also be pretty useful independently of the performance boost. We already demark them to a certain degree: [ 37.287036] Call Trace: [ 37.287042] <IRQ> [<ffffffffb5161eee>] dump_stack+0x4c/0x65 [ 37.287045] [<ffffffffb3d40288>] ? down_trylock+0x28/0x33 [ 37.287048] [<ffffffffb3cfa74d>] warn_slowpath_common+0x7b/0xb1 [ 37.287050] [<ffffffffb3cfa7f7>] warn_slowpath_fmt+0x50/0x6e [ 37.287053] [<ffffffffb3cfe0ba>] ? __do_softirq+0x224/0x289 [ 37.287055] [<ffffffffb3cfe047>] ? __do_softirq+0x1b1/0x289 [ 37.287057] [<ffffffffb3d71b4c>] can_stop_full_tick+0x69/0xa1 [ 37.287059] [<ffffffffb3d72273>] tick_nohz_irq_exit+0x72/0x98 [ 37.287061] [<ffffffffb3cfe3b5>] irq_exit+0xbf/0x104 [ 37.287064] [<ffffffffb3c6b01a>] smp_apic_timer_interrupt+0x42/0x51 [ 37.287067] [<ffffffffb51821d9>] apic_timer_interrupt+0x89/0x90 [ 37.287071] <EOI> [<ffffffffb3d283ab>] ? ___might_sleep+0x150/0x232 [ 37.287075] [<ffffffffb3d4b684>] ? lock_torture_reader+0x102/0x102 including the RIP of interrupted nested contexts would be helpful. Thanks, Ingo ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S 2015-07-21 8:00 ` Ingo Molnar @ 2015-07-21 12:06 ` Josh Poimboeuf 0 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-21 12:06 UTC (permalink / raw) To: Ingo Molnar Cc: Andy Lutomirski, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Tue, Jul 21, 2015 at 10:00:16AM +0200, Ingo Molnar wrote: > > * Josh Poimboeuf <jpoimboe@redhat.com> wrote: > > > On Mon, Jul 20, 2015 at 08:30:52AM -0700, Andy Lutomirski wrote: > > > On Fri, Jul 17, 2015 at 8:56 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > > > > The reason I suggested to put FRAME in the macro name is to try to > > > > prevent it from being accidentally used for leaf functions, where it > > > > isn't needed. > > > > > > > > > > Could someone remind me why it isn't needed for leaf functions? > > > > If a function doesn't call any other functions, then it won't ever show > > up in a stack trace unless: > > > > a) the function itself walks the stack, in which case the frame pointer > > isn't necessary; or > > > > b) The function gets hit by an interrupt/exception, in which case frame > > pointers can't be 100% relied upon anyway. > > > > I've noticed that gcc *does* seem to create stack frames for leaf functions. > > But it's inconsistent, because the early exit path of some functions will skip > > the stack frame creation and go straight to the return. > > > > We could probably get a good performance boost with the > > -momit-leaf-frame-pointer flag. Though it would make stack traces less reliable > > when a leaf function gets interrupted. > > So in theory we could resolve this during the stack walk: when we pass from the > IRQ stack to the process stack we actually know the RIP of the interrupted > context, and could include that. The problem is with the *caller* of the leaf function. Without the leaf's frame pointer there's no way to find the call site pointer on the stack, so the leaf's caller gets skipped. -- Josh ^ permalink raw reply [flat|nested] 89+ messages in thread
* [RFC PATCH 14/21] x86/asm/crypto: Move .Lbswap_mask data to .rodata section 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (12 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 15/21] x86/asm/crypto: Move jump_table " Josh Poimboeuf ` (7 subsequent siblings) 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel stackvalidate reports the following warning: stackvalidate: arch/x86/crypto/aesni-intel_asm.o: _aesni_inc_init(): can't find starting instruction stackvalidate gets confused when it tries to disassemble the following data in the .text section: .Lbswap_mask: .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 Move it to .rodata which is a more appropriate section for read-only data. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/crypto/aesni-intel_asm.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/crypto/aesni-intel_asm.S b/arch/x86/crypto/aesni-intel_asm.S index 3df557b..dea6cd8 100644 --- a/arch/x86/crypto/aesni-intel_asm.S +++ b/arch/x86/crypto/aesni-intel_asm.S @@ -2553,9 +2553,11 @@ ENTRY(aesni_cbc_dec) ENDPROC(aesni_cbc_dec) #ifdef __x86_64__ +.pushsection .rodata .align 16 .Lbswap_mask: .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 +.popsection /* * _aesni_inc_init: internal ABI -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [RFC PATCH 15/21] x86/asm/crypto: Move jump_table to .rodata section 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (13 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 14/21] x86/asm/crypto: Move .Lbswap_mask data to .rodata section Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 16/21] x86/asm/crypto: Fix frame pointer usage in clmul_ghash_mul/update() Josh Poimboeuf ` (6 subsequent siblings) 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel stackvalidate reports the following warning: stackvalidate: arch/x86/crypto/crc32c-pcl-intel-asm_64.o: crc_pcl()+0x11dd: can't decode instruction It gets confused when trying to decode jump_table data. Move jump_table to the .rodata section which is a more appropriate home for read-only data. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/crypto/crc32c-pcl-intel-asm_64.S | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/crypto/crc32c-pcl-intel-asm_64.S b/arch/x86/crypto/crc32c-pcl-intel-asm_64.S index 225be06..dc05f01 100644 --- a/arch/x86/crypto/crc32c-pcl-intel-asm_64.S +++ b/arch/x86/crypto/crc32c-pcl-intel-asm_64.S @@ -170,8 +170,8 @@ continue_block: ## branch into array lea jump_table(%rip), bufp movzxw (bufp, %rax, 2), len - offset=crc_array-jump_table - lea offset(bufp, len, 1), bufp + lea crc_array(%rip), bufp + lea (bufp, len, 1), bufp jmp *bufp ################################################################ @@ -310,7 +310,9 @@ do_return: popq %rdi popq %rbx ret +ENDPROC(crc_pcl) +.section .rodata, "a", %progbits ################################################################ ## jump table Table is 129 entries x 2 bytes each ################################################################ @@ -324,13 +326,11 @@ JMPTBL_ENTRY %i i=i+1 .endr -ENDPROC(crc_pcl) ################################################################ ## PCLMULQDQ tables ## Table is 128 entries x 2 words (8 bytes) each ################################################################ -.section .rotata, "a", %progbits .align 8 K_table: .long 0x493c7d27, 0x00000001 -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [RFC PATCH 16/21] x86/asm/crypto: Fix frame pointer usage in clmul_ghash_mul/update() 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (14 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 15/21] x86/asm/crypto: Move jump_table " Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 17/21] x86/asm/entry: Fix frame pointer usage in thunk functions Josh Poimboeuf ` (5 subsequent siblings) 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel clmul_ghash_mul() and clmul_ghash_update() are callable non-leaf functions which don't honor CONFIG_FRAME_POINTER, which can result in bad stack traces. Create stack frames for them when CONFIG_FRAME_POINTER is enabled. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/crypto/ghash-clmulni-intel_asm.S | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/x86/crypto/ghash-clmulni-intel_asm.S b/arch/x86/crypto/ghash-clmulni-intel_asm.S index 5d1e007..a5a17e6 100644 --- a/arch/x86/crypto/ghash-clmulni-intel_asm.S +++ b/arch/x86/crypto/ghash-clmulni-intel_asm.S @@ -18,6 +18,7 @@ #include <linux/linkage.h> #include <asm/inst.h> +#include <asm/frame.h> .data @@ -94,6 +95,7 @@ ENDPROC(__clmul_gf128mul_ble) /* void clmul_ghash_mul(char *dst, const u128 *shash) */ ENTRY(clmul_ghash_mul) + FRAME movups (%rdi), DATA movups (%rsi), SHASH movaps .Lbswap_mask, BSWAP @@ -101,6 +103,7 @@ ENTRY(clmul_ghash_mul) call __clmul_gf128mul_ble PSHUFB_XMM BSWAP DATA movups DATA, (%rdi) + ENDFRAME ret ENDPROC(clmul_ghash_mul) @@ -109,6 +112,7 @@ ENDPROC(clmul_ghash_mul) * const u128 *shash); */ ENTRY(clmul_ghash_update) + FRAME cmp $16, %rdx jb .Lupdate_just_ret # check length movaps .Lbswap_mask, BSWAP @@ -128,5 +132,6 @@ ENTRY(clmul_ghash_update) PSHUFB_XMM BSWAP DATA movups DATA, (%rdi) .Lupdate_just_ret: + ENDFRAME ret ENDPROC(clmul_ghash_update) -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [RFC PATCH 17/21] x86/asm/entry: Fix frame pointer usage in thunk functions 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (15 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 16/21] x86/asm/crypto: Fix frame pointer usage in clmul_ghash_mul/update() Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 18/21] x86/asm/acpi: Fix frame pointer usage in do_suspend_lowlevel() Josh Poimboeuf ` (4 subsequent siblings) 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel Thunk functions are callable non-leaf functions that don't honor CONFIG_FRAME_POINTER, which can result in bad stack traces. Also they aren't annotated as ELF callable functions which can confuse tooling. Create stack frames for them when CONFIG_FRAME_POINTER is enabled and add the ELF function type. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/entry/thunk_64.S | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/x86/entry/thunk_64.S b/arch/x86/entry/thunk_64.S index efb2b93..03ee0cd 100644 --- a/arch/x86/entry/thunk_64.S +++ b/arch/x86/entry/thunk_64.S @@ -8,11 +8,14 @@ #include <linux/linkage.h> #include "calling.h" #include <asm/asm.h> +#include <asm/frame.h> /* rdi: arg1 ... normal C conventions. rax is saved/restored. */ .macro THUNK name, func, put_ret_addr_in_rdi=0 .globl \name + .type \name, @function \name: + FRAME /* this one pushes 9 elems, the next one would be %rIP */ pushq %rdi @@ -62,6 +65,7 @@ restore: popq %rdx popq %rsi popq %rdi + ENDFRAME ret _ASM_NOKPROBE(restore) #endif -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [RFC PATCH 18/21] x86/asm/acpi: Fix frame pointer usage in do_suspend_lowlevel() 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (16 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 17/21] x86/asm/entry: Fix frame pointer usage in thunk functions Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 19/21] x86/asm: Fix frame pointer usage in rwsem functions Josh Poimboeuf ` (3 subsequent siblings) 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel do_suspend_lowlevel() is a callable non-leaf function which doesn't honor CONFIG_FRAME_POINTER, which can result in bad stack traces. Create a stack frame for it when CONFIG_FRAME_POINTER is enabled. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/kernel/acpi/wakeup_64.S | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S index 8c35df4..7ada747 100644 --- a/arch/x86/kernel/acpi/wakeup_64.S +++ b/arch/x86/kernel/acpi/wakeup_64.S @@ -5,6 +5,7 @@ #include <asm/page_types.h> #include <asm/msr.h> #include <asm/asm-offsets.h> +#include <asm/frame.h> # Copyright 2003 Pavel Machek <pavel@suse.cz>, distribute under GPLv2 @@ -39,6 +40,7 @@ bogus_64_magic: jmp bogus_64_magic ENTRY(do_suspend_lowlevel) + FRAME subq $8, %rsp xorl %eax, %eax call save_processor_state @@ -109,6 +111,7 @@ ENTRY(do_suspend_lowlevel) xorl %eax, %eax addq $8, %rsp + ENDFRAME jmp restore_processor_state ENDPROC(do_suspend_lowlevel) -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [RFC PATCH 19/21] x86/asm: Fix frame pointer usage in rwsem functions 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (17 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 18/21] x86/asm/acpi: Fix frame pointer usage in do_suspend_lowlevel() Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 20/21] x86/asm/efi: Fix frame pointer usage in efi_call() Josh Poimboeuf ` (2 subsequent siblings) 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel rwsem.S has several callable non-leaf functions which don't honor CONFIG_FRAME_POINTER, which can result in bad stack traces. Create stack frames for them when CONFIG_FRAME_POINTER is enabled. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/lib/rwsem.S | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/x86/lib/rwsem.S b/arch/x86/lib/rwsem.S index 40027db..332e533 100644 --- a/arch/x86/lib/rwsem.S +++ b/arch/x86/lib/rwsem.S @@ -15,6 +15,7 @@ #include <linux/linkage.h> #include <asm/alternative-asm.h> +#include <asm/frame.h> #define __ASM_HALF_REG(reg) __ASM_SEL(reg, e##reg) #define __ASM_HALF_SIZE(inst) __ASM_SEL(inst##w, inst##l) @@ -84,24 +85,29 @@ /* Fix up special calling conventions */ ENTRY(call_rwsem_down_read_failed) + FRAME save_common_regs __ASM_SIZE(push,) %__ASM_REG(dx) movq %rax,%rdi call rwsem_down_read_failed __ASM_SIZE(pop,) %__ASM_REG(dx) restore_common_regs + ENDFRAME ret ENDPROC(call_rwsem_down_read_failed) ENTRY(call_rwsem_down_write_failed) + FRAME save_common_regs movq %rax,%rdi call rwsem_down_write_failed restore_common_regs + ENDFRAME ret ENDPROC(call_rwsem_down_write_failed) ENTRY(call_rwsem_wake) + FRAME /* do nothing if still outstanding active readers */ __ASM_HALF_SIZE(dec) %__ASM_HALF_REG(dx) jnz 1f @@ -109,15 +115,18 @@ ENTRY(call_rwsem_wake) movq %rax,%rdi call rwsem_wake restore_common_regs -1: ret +1: ENDFRAME + ret ENDPROC(call_rwsem_wake) ENTRY(call_rwsem_downgrade_wake) + FRAME save_common_regs __ASM_SIZE(push,) %__ASM_REG(dx) movq %rax,%rdi call rwsem_downgrade_wake __ASM_SIZE(pop,) %__ASM_REG(dx) restore_common_regs + ENDFRAME ret ENDPROC(call_rwsem_downgrade_wake) -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [RFC PATCH 20/21] x86/asm/efi: Fix frame pointer usage in efi_call() 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (18 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 19/21] x86/asm: Fix frame pointer usage in rwsem functions Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 21/21] x86/asm/power: Fix frame pointer usage in hibernate_asm_64.S Josh Poimboeuf 2015-07-17 18:56 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Andy Lutomirski 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel efi_call() is a callable non-leaf function which doesn't honor CONFIG_FRAME_POINTER, which can result in bad stack traces. Create a stack frame for it when CONFIG_FRAME_POINTER is enabled. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/platform/efi/efi_stub_64.S | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/platform/efi/efi_stub_64.S b/arch/x86/platform/efi/efi_stub_64.S index 86d0f9e..fd68dea 100644 --- a/arch/x86/platform/efi/efi_stub_64.S +++ b/arch/x86/platform/efi/efi_stub_64.S @@ -11,6 +11,7 @@ #include <asm/msr.h> #include <asm/processor-flags.h> #include <asm/page_types.h> +#include <asm/frame.h> #define SAVE_XMM \ mov %rsp, %rax; \ @@ -74,6 +75,7 @@ .endm ENTRY(efi_call) + FRAME SAVE_XMM mov (%rsp), %rax mov 8(%rax), %rax @@ -88,6 +90,7 @@ ENTRY(efi_call) RESTORE_PGT addq $48, %rsp RESTORE_XMM + ENDFRAME ret ENDPROC(efi_call) -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* [RFC PATCH 21/21] x86/asm/power: Fix frame pointer usage in hibernate_asm_64.S 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (19 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 20/21] x86/asm/efi: Fix frame pointer usage in efi_call() Josh Poimboeuf @ 2015-07-17 16:47 ` Josh Poimboeuf 2015-07-17 18:56 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Andy Lutomirski 21 siblings, 0 replies; 89+ messages in thread From: Josh Poimboeuf @ 2015-07-17 16:47 UTC (permalink / raw) To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin Cc: Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, x86, live-patching, linux-kernel swsusp_arch_suspend() and restore_registers() are callable non-leaf functions which don't honor CONFIG_FRAME_POINTER, which can result in bad stack traces. Also they aren't annotated as ELF callable functions which can confuse tooling. Create a stack frame for them when CONFIG_FRAME_POINTER is enabled and give them proper ELF function annotations. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> --- arch/x86/power/hibernate_asm_64.S | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/x86/power/hibernate_asm_64.S b/arch/x86/power/hibernate_asm_64.S index e2386cb..4d41af2 100644 --- a/arch/x86/power/hibernate_asm_64.S +++ b/arch/x86/power/hibernate_asm_64.S @@ -21,8 +21,10 @@ #include <asm/page_types.h> #include <asm/asm-offsets.h> #include <asm/processor-flags.h> +#include <asm/frame.h> ENTRY(swsusp_arch_suspend) + FRAME movq $saved_context, %rax movq %rsp, pt_regs_sp(%rax) movq %rbp, pt_regs_bp(%rax) @@ -50,7 +52,9 @@ ENTRY(swsusp_arch_suspend) movq %rax, restore_cr3(%rip) call swsusp_save + ENDFRAME ret +ENDPROC(swsusp_arch_suspend) ENTRY(restore_image) /* switch to temporary page tables */ @@ -107,6 +111,7 @@ ENTRY(core_restore_code) */ ENTRY(restore_registers) + FRAME /* go back to the original page tables */ movq %rbx, %cr3 @@ -147,4 +152,6 @@ ENTRY(restore_registers) /* tell the hibernation core that we've just restored the memory */ movq %rax, in_suspend(%rip) + ENDFRAME ret +ENDPROC(restore_registers) -- 2.1.0 ^ permalink raw reply related [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf ` (20 preceding siblings ...) 2015-07-17 16:47 ` [RFC PATCH 21/21] x86/asm/power: Fix frame pointer usage in hibernate_asm_64.S Josh Poimboeuf @ 2015-07-17 18:56 ` Andy Lutomirski 2015-07-18 3:05 ` Ingo Molnar 21 siblings, 1 reply; 89+ messages in thread From: Andy Lutomirski @ 2015-07-17 18:56 UTC (permalink / raw) To: Josh Poimboeuf Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org On Fri, Jul 17, 2015 at 9:47 AM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > These patches fix many of the warnings reported by stackvalidate. > They're based on top of the "Compile-time stack validation" v7 patch set > [1]. > > They've been compile-tested and boot tested in a VM, but I haven't > attempted any meaningful testing for most of them. This should give an > idea of what kinds of changes I think are needed. > > [1] https://lkml.kernel.org/r/cover.1436893563.git.jpoimboe@redhat.com > Nothing here looks all that bad, but I think the extra frame pointers staring us in the face (as opposed to the ones that gcc adds transparently) might serve as added incentive to suck it up and get CFI unwinding working. --Andy ^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings 2015-07-17 18:56 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Andy Lutomirski @ 2015-07-18 3:05 ` Ingo Molnar 0 siblings, 0 replies; 89+ messages in thread From: Ingo Molnar @ 2015-07-18 3:05 UTC (permalink / raw) To: Andy Lutomirski Cc: Josh Poimboeuf, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Michal Marek, Peter Zijlstra, Andy Lutomirski, Borislav Petkov, Linus Torvalds, Andi Kleen, Pedro Alves, X86 ML, live-patching, linux-kernel@vger.kernel.org * Andy Lutomirski <luto@amacapital.net> wrote: > On Fri, Jul 17, 2015 at 9:47 AM, Josh Poimboeuf <jpoimboe@redhat.com> wrote: > > These patches fix many of the warnings reported by stackvalidate. > > They're based on top of the "Compile-time stack validation" v7 patch set > > [1]. > > > > They've been compile-tested and boot tested in a VM, but I haven't > > attempted any meaningful testing for most of them. This should give an > > idea of what kinds of changes I think are needed. > > > > [1] https://lkml.kernel.org/r/cover.1436893563.git.jpoimboe@redhat.com > > > > Nothing here looks all that bad, but I think the extra frame pointers > staring us in the face (as opposed to the ones that gcc adds > transparently) might serve as added incentive to suck it up and get > CFI unwinding working. So there are two aspects to frame pointers staring us in the face: - Syntactically there's extra debuginfo cruft added to the source code. Not good but very fixable: I already made a couple of suggestions of how to trim all that in a way that improves general readability as well over what we have today. - Instruction wise in the generated code. I'm afraid the 'transparent' frame pointers added by GCC are staring me in the face in perf top/report disassembly output just as much! ;-) But naming details aside, I like the direction of these patches a lot better than that of any previous debuginfo approach, because the approach is very proactive. ( Which it really has to be, given that deep down these patches are motivated by enabling more complex models of live kernel patching. But that's a win-win. ) Once the cleanliness of the annotations is improved and we have a reasonable path towards having no warnings on a regular kernel build, I plan on starting to apply the patches. So if anyone has any deep objections that were kept close to the vest so far, please holler now. Thanks, Ingo ^ permalink raw reply [flat|nested] 89+ messages in thread
end of thread, other threads:[~2015-07-22 11:52 UTC | newest] Thread overview: 89+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-07-14 17:14 [PATCH v7 0/4] Compile-time stack validation Josh Poimboeuf 2015-07-14 17:14 ` [PATCH v7 1/4] x86/asm: Frame pointer macro cleanup Josh Poimboeuf 2015-07-14 17:14 ` [PATCH v7 2/4] x86/stackvalidate: Compile-time stack validation Josh Poimboeuf 2015-07-14 20:57 ` Peter Zijlstra 2015-07-14 21:11 ` Josh Poimboeuf 2015-07-14 21:08 ` Peter Zijlstra 2015-07-14 21:30 ` Josh Poimboeuf 2015-07-14 21:56 ` Peter Zijlstra 2015-07-14 22:32 ` Josh Poimboeuf 2015-07-20 16:53 ` Namhyung Kim 2015-07-20 17:50 ` Josh Poimboeuf 2015-07-21 8:02 ` Ingo Molnar 2015-07-21 12:04 ` Josh Poimboeuf 2015-07-21 8:42 ` Bernd Petrovitsch 2015-07-21 12:06 ` Josh Poimboeuf 2015-07-14 17:14 ` [PATCH v7 3/4] x86/stackvalidate: Add file and directory ignores Josh Poimboeuf 2015-07-14 17:14 ` [PATCH v7 4/4] x86/stackvalidate: Add ignore macros Josh Poimboeuf 2015-07-14 17:25 ` [PATCH v7 0/4] Compile-time stack validation Josh Poimboeuf 2015-07-15 10:16 ` Ingo Molnar 2015-07-15 16:05 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 01/21] stackvalidate: Process ignores earlier and add more ignore checks Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 02/21] stackvalidate: Add C version of STACKVALIDATE_IGNORE_INSN Josh Poimboeuf 2015-07-18 14:56 ` Borislav Petkov 2015-07-18 16:00 ` Josh Poimboeuf [not found] ` <CA+55aFyoO75n-mQBrB_YBLx9yNpAjisFAqkO8+YsphD-xmgY+w@mail.gmail.com> 2015-07-18 16:40 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 03/21] x86/asm: Add C versions of FRAME and ENDFRAME macros Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 04/21] x86/hweight: Add stack frame dependency for __arch_hweight*() Josh Poimboeuf 2015-07-17 17:17 ` Borislav Petkov 2015-07-17 17:32 ` Josh Poimboeuf 2015-07-18 5:05 ` Borislav Petkov 2015-07-18 13:44 ` Josh Poimboeuf 2015-07-18 14:56 ` Borislav Petkov 2015-07-18 15:57 ` Josh Poimboeuf 2015-07-19 4:12 ` Borislav Petkov 2015-07-22 0:13 ` Andy Lutomirski 2015-07-22 4:25 ` Borislav Petkov 2015-07-22 4:39 ` Andy Lutomirski 2015-07-22 4:45 ` Borislav Petkov 2015-07-17 16:47 ` [RFC PATCH 05/21] x86/xen: Add stack frame dependency to hypercall inline asm calls Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 06/21] x86/paravirt: Add stack frame dependency to PVOP " Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 07/21] x86/paravirt: Fix frame pointer usage in PV_CALLEE_SAVE_REGS_THUNK Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 08/21] x86/paravirt: Align paravirt thunk functions at 16-byte boundaries Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 09/21] x86/amd: Set ELF function type for vide() Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 10/21] x86/reboot: Add ljmp instructions to stackvalidate whitelist Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 11/21] x86/xen: Add xen_cpuid() and xen_setup_gdt() to stackvalidate whitelists Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 12/21] sched: Add __schedule() to stackvalidate whitelist Josh Poimboeuf 2015-07-17 19:46 ` Peter Zijlstra 2015-07-17 19:58 ` Andy Lutomirski 2015-07-17 21:03 ` Peter Zijlstra 2015-07-17 21:23 ` Josh Poimboeuf 2015-07-18 3:44 ` Ingo Molnar 2015-07-17 16:47 ` [RFC PATCH 13/21] x86/asm/crypto: Fix frame pointer usage in aesni-intel_asm.S Josh Poimboeuf 2015-07-17 19:43 ` Ingo Molnar 2015-07-17 19:44 ` Andy Lutomirski 2015-07-17 20:37 ` Josh Poimboeuf 2015-07-17 20:39 ` Andy Lutomirski 2015-07-17 20:44 ` Josh Poimboeuf 2015-07-17 20:46 ` Andy Lutomirski 2015-07-17 20:59 ` Josh Poimboeuf 2015-07-17 21:01 ` Andy Lutomirski 2015-07-17 21:10 ` Josh Poimboeuf 2015-07-18 8:42 ` Borislav Petkov 2015-07-18 13:46 ` Josh Poimboeuf 2015-07-18 14:25 ` Borislav Petkov 2015-07-18 15:40 ` Josh Poimboeuf 2015-07-18 2:51 ` Ingo Molnar 2015-07-18 3:56 ` Josh Poimboeuf 2015-07-20 7:56 ` Ingo Molnar 2015-07-20 13:59 ` Josh Poimboeuf 2015-07-20 17:21 ` Ingo Molnar 2015-07-20 18:00 ` Josh Poimboeuf 2015-07-22 11:52 ` Josh Poimboeuf 2015-07-20 15:30 ` Andy Lutomirski 2015-07-20 16:36 ` Josh Poimboeuf 2015-07-20 16:52 ` Peter Zijlstra 2015-07-20 17:19 ` Josh Poimboeuf 2015-07-21 8:00 ` Ingo Molnar 2015-07-21 12:06 ` Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 14/21] x86/asm/crypto: Move .Lbswap_mask data to .rodata section Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 15/21] x86/asm/crypto: Move jump_table " Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 16/21] x86/asm/crypto: Fix frame pointer usage in clmul_ghash_mul/update() Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 17/21] x86/asm/entry: Fix frame pointer usage in thunk functions Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 18/21] x86/asm/acpi: Fix frame pointer usage in do_suspend_lowlevel() Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 19/21] x86/asm: Fix frame pointer usage in rwsem functions Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 20/21] x86/asm/efi: Fix frame pointer usage in efi_call() Josh Poimboeuf 2015-07-17 16:47 ` [RFC PATCH 21/21] x86/asm/power: Fix frame pointer usage in hibernate_asm_64.S Josh Poimboeuf 2015-07-17 18:56 ` [RFC PATCH 00/21] x86: Proposed fixes for stackvalidate warnings Andy Lutomirski 2015-07-18 3:05 ` Ingo Molnar
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).