Skip to contentSkip to conversation

Compile-time stack validation

PATCH Superseded Josh Poimboeuf 4 participants 30 messages Aug 14, 2015 – Aug 22, 2015

Subsystems (13)
Documentation x86 Kbuild ACPI +9 more subsystems

v10 of 19 Superseded Latest is v19 →

lore
Share & tools
lore
#0 lore raw

v10 cover Compile-time stack validation

This is v10 of the compile-time stack validation patch set, along with proposed fixes for many of the warnings it found. It's based on the tip/master branch.

The frame pointer macros have been renamed from FRAME/ENDFRAME to FRAME_BEGIN/FRAME_END.

v9 can be found here:

https://lkml.kernel.org/r/[email protected]

For more information about the motivation behind this patch set, and more details about what it does, please see the changelog in patch 3.

Patches 1-5 are the stackvalidate tool and some related macros.

Patches 6-20 are some proposed fixes for several of the warnings reported by stackvalidate. They've been compile-tested and boot tested in a VM, but I haven't attempted any meaningful testing for many of them.

v10:
- add scripts/mod to directory ignores
- remove circular dependencies for ignored objects which are built before stackvalidate
- fix CONFIG_MODVERSIONS incompatibility

v9:
- rename FRAME/ENDFRAME -> FRAME_BEGIN/FRAME_END
- fix jump table issue for when the original instruction is a jump
- drop paravirt thunk alignment patch
- add maintainers to CC for proposed warning fixes

v8:
- add proposed fixes for warnings
- fix all memory leaks
- process ignores earlier and add more ignore checks
- always assume POPCNT alternative is enabled
- drop hweight inline asm fix
- drop __schedule() ignore patch
- change .Ltemp_\@ to .Lstackvalidate_ignore_\@ in asm macro
- fix CONFIG_* checks in asm macros
- add C versions of ignore macros and frame macros
- change ";" to "\n" in C macros
- add ifdef CONFIG_STACK_VALIDATION checks in C ignore macros
- use numbered label in C ignore macro
- add missing break in switch case statement in arch-x86.c

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

Cc Michal Marek <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Andy Lutomirski <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Andi Kleen <[email protected]>
Cc Pedro Alves <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Bernd Petrovitsch <[email protected]>
Cc "Chris J Arges" <[email protected]>

Josh Poimboeuf (20):
x86/asm: Frame pointer macro cleanup
x86/asm: Add C versions of frame pointer macros x86/stackvalidate: Compile-time stack validation x86/stackvalidate: Add file and directory ignores x86/stackvalidate: Add ignore macros
x86/xen: Add stack frame dependency to hypercall inline asm calls x86/paravirt: Add stack frame dependency to PVOP inline asm calls x86/paravirt: Create a stack frame in PV_CALLEE_SAVE_REGS_THUNK 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
x86/asm/crypto: Create stack frames 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: Create stack frames in clmul_ghash_mul/update() x86/asm/entry: Create stack frames in thunk functions x86/asm/acpi: Create a stack frame in do_suspend_lowlevel() x86/asm: Create stack frames in rwsem functions x86/asm/efi: Create a stack frame in efi_call() x86/asm/power: Create stack frames in hibernate_asm_64.S

 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/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/entry/vdso/Makefile              |   5 +-
 arch/x86/include/asm/frame.h              |  51 +-
 arch/x86/include/asm/paravirt.h           |   9 +-
 arch/x86/include/asm/paravirt_types.h     |  18 +-
 arch/x86/include/asm/stackvalidate.h      |  45 ++
 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/kernel/vmlinux.lds.S             |   5 +-
 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/purgatory/Makefile               |   2 +
 arch/x86/realmode/Makefile                |   4 +-
 arch/x86/realmode/rm/Makefile             |   3 +-
 arch/x86/xen/enlighten.c                  |   4 +-
 drivers/firmware/efi/libstub/Makefile     |   1 +
 include/linux/stackvalidate.h             |  28 +
 lib/Kconfig.debug                         |  11 +
 scripts/Makefile                          |   1 +
 scripts/Makefile.build                    |  37 +-
 scripts/mod/Makefile                      |   2 +
 scripts/stackvalidate/Makefile            |  24 +
 scripts/stackvalidate/arch-x86.c          | 160 +++++
 scripts/stackvalidate/arch.h              |  44 ++
 scripts/stackvalidate/elf.c               | 427 +++++++++++++
 scripts/stackvalidate/elf.h               |  92 +++
 scripts/stackvalidate/list.h              | 217 +++++++
 scripts/stackvalidate/special.c           | 199 ++++++
 scripts/stackvalidate/special.h           |  42 ++
 scripts/stackvalidate/stackvalidate.c     | 976 ++++++++++++++++++++++++++++++
 43 files changed, 2658 insertions(+), 48 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
Signature · 1 line
2.4.3
#1 lore raw

PATCH v10 1/20 x86/asm: Frame pointer macro cleanup

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

Rename FRAME/ENDFRAME to FRAME_BEGIN/FRAME_END for more symmetry. Also make the code more readable and improve the comments.

---
 arch/x86/include/asm/frame.h | 33 ++++++++++++++++++---------------
 1 file changed, 18 insertions(+), 15 deletions(-)
arch/x86/include/asm/frame.h +18 -15
index 793179c..8a6cd26 100644
@@ -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 */
+/*
+ * 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_BEGIN
+#ifdef CONFIG_FRAME_POINTER
+	push %_ASM_BP
+	_ASM_MOV %_ASM_SP, %_ASM_BP
+#endif
+.endm
+
+.macro FRAME_END
 #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
+	pop %_ASM_BP
 #endif
+.endm
 
 #endif  /*  __ASSEMBLY__  */
+#endif /* _ASM_X86_FRAME_H */
Signature · 1 line
2.4.3
#2 lore raw

PATCH v10 2/20 x86/asm: Add C versions of frame pointer macros

In reply to Josh Poimboeuf

Add C versions of the frame pointer macros which can be used to create a stack frame in inline assembly.

---
 arch/x86/include/asm/frame.h | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)
arch/x86/include/asm/frame.h +18 -2
index 8a6cd26..9a30ec7 100644
@@ -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_BEGIN				\
+	"push %" _ASM_BP "\n"			\
+	_ASM_MOV "%" _ASM_SP ", %" _ASM_BP "\n"
+
+#define FRAME_END "pop %" _ASM_BP "\n"
+
+#else /* !CONFIG_FRAME_POINTER */
+
+#define FRAME_BEGIN ""
+#define FRAME_END ""
+
+#endif /* CONFIG_FRAME_POINTER */
 #endif  /*  __ASSEMBLY__  */
 #endif /* _ASM_X86_FRAME_H */
Signature · 1 line
2.4.3
#3 lore raw

PATCH v10 3/20 x86/stackvalidate: Compile-time stack validation

In reply to Josh Poimboeuf

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 also plan to add DWARF CFI validation for C .o files and CFI generation for asm .o files.

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_BEGIN/FRAME_END 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 laptop with a i7-4810MQ 4-core/8-thread CPU, building the kernel with it enabled adds less than 3 seconds of total build time. It hasn't been optimized for performance yet, so there are probably some opportunities for better build performance.

---
 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                |  37 +-
 scripts/stackvalidate/Makefile        |  24 +
 scripts/stackvalidate/arch-x86.c      | 160 ++++++
 scripts/stackvalidate/arch.h          |  44 ++
 scripts/stackvalidate/elf.c           | 427 +++++++++++++++
 scripts/stackvalidate/elf.h           |  92 ++++
 scripts/stackvalidate/list.h          | 217 ++++++++
 scripts/stackvalidate/special.c       | 199 +++++++
 scripts/stackvalidate/special.h       |  42 ++
 scripts/stackvalidate/stackvalidate.c | 976 ++++++++++++++++++++++++++++++++++
 17 files changed, 2439 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
Documentation/stack-validation.txt new file +193 -0
new file mode 100644
index 0000000..c3d3d35
@@ -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
+CFI validation for C files and CFI generation for asm files.
+
+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_BEGIN/FRAME_END 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 ENTRY/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 ENTRY/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.
MAINTAINERS +8 -0
index c1452d1..fb3deb4 100644
@@ -9679,6 +9679,14 @@ L:	[email protected]
 S:	Supported
 F:	Documentation/stable_kernel_rules.txt
 
+STACK VALIDATION
+M:	Josh Poimboeuf <[email protected]>
+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 <[email protected]>
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
arch/Kconfig +6 -0
index 021f8f9..ceb4eda 100644
@@ -525,6 +525,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
 #
arch/x86/Kconfig +1 -0
index f37010f..50877dc 100644
@@ -151,6 +151,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
arch/x86/Makefile +5 -1
index 747860c..fb7135b 100644
@@ -181,9 +181,13 @@ KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
 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
 
lib/Kconfig.debug +11 -0
index ab76b99..1c235c6 100644
@@ -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
scripts/Makefile +1 -0
index 2016a64..c882a91 100644
@@ -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
scripts/Makefile.build +33 -4
index 01df30a..a1c5376 100644
@@ -241,10 +241,30 @@ cmd_record_mcount =						\
 	fi;
 endif
 
+ifdef CONFIG_STACK_VALIDATION
+
+__stackvalidate_obj = $(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.
+stackvalidate_obj = $(if $(patsubst n%,, \
+	$(STACKVALIDATE_$(basetarget).o)$(STACKVALIDATE)y), \
+	$(__stackvalidate_obj))
+cmd_stackvalidate = $(if $(patsubst n%,, \
+	$(STACKVALIDATE_$(basetarget).o)$(STACKVALIDATE)y), \
+	$(__stackvalidate_obj) $(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_modversions)						  \
+	$(cmd_stackvalidate)						  \
 	$(call echo-cmd,record_mcount)					  \
 	$(cmd_record_mcount)						  \
 	scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' >    \
@@ -253,14 +273,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_obj) 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_obj) FORCE
 	$(call cmd,force_checksrc)
 	$(call if_changed_rule,cc_o_c)
 	@{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
@@ -290,8 +319,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_obj) FORCE
+	$(call if_changed_rule,as_o_S)
 
 targets += $(real-objs-y) $(real-objs-m) $(lib-y)
 targets += $(extra-y) $(MAKECMDGOALS) $(always)
scripts/stackvalidate/Makefile new file +24 -0
new file mode 100644
index 0000000..468c075
@@ -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
scripts/stackvalidate/arch-x86.c new file +160 -0

160 lines not on this page · raw message

scripts/stackvalidate/arch.h new file +44 -0

44 lines not on this page · raw message

scripts/stackvalidate/elf.c new file +427 -0

427 lines not on this page · raw message

scripts/stackvalidate/elf.h new file +92 -0

92 lines not on this page · raw message

scripts/stackvalidate/list.h new file +217 -0

217 lines not on this page · raw message

scripts/stackvalidate/special.c new file +199 -0

199 lines not on this page · raw message

scripts/stackvalidate/special.h new file +42 -0

42 lines not on this page · raw message

scripts/stackvalidate/stackvalidate.c new file +976 -0

976 lines not on this page · raw message

Signature · 1 line
2.4.3
maintainer
#4 lore raw

Re: [PATCH v10 03/20] x86/stackvalidate: Compile-time stack validation

Quoted 2 lines · On Thu, 13 Aug 2015 22:10:24 -0500 Josh Poimboeuf <[email protected]> wrote:

This adds a CONFIG_STACK_VALIDATION option which enables a host tool named stackvalidate which runs at compile time.

It would be useful to

- show example output for a typical error site

- describe the consequences of that error (ie: why should we fix these things?)

- describe what needs to be done to repair these sites.

IOW, what do we gain from merging all this stuff?

#5 lore raw

Re: [PATCH v10 03/20] x86/stackvalidate: Compile-time stack validation

Quoted 9 lines · Andrew Morton
Quoted 2 lines · On Thu, 13 Aug 2015 22:10:24 -0500 Josh Poimboeuf <[email protected]> wrote:

This adds a CONFIG_STACK_VALIDATION option which enables a host tool named stackvalidate which runs at compile time.

It would be useful to

- show example output for a typical error site

Quoted 7 lines

- describe the consequences of that error (ie: why should we fix these things?)

- describe what needs to be done to repair these sites.

IOW, what do we gain from merging all this stuff?

I attempted to do all that in Documentation/stack-validation.txt which is in patch 03/20. Does it address your concerns? Here it is:

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 CFI validation for C files and CFI generation for asm files.

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_BEGIN/FRAME_END 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 ENTRY/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 ENTRY/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.

Signature · 1 line
Josh
#6 lore raw

Re: [PATCH v10 03/20] x86/stackvalidate: Compile-time stack validation

Quoted 13 lines · Josh Poimboeuf
Quoted 12 lines · Andrew Morton
Quoted 2 lines · On Thu, 13 Aug 2015 22:10:24 -0500 Josh Poimboeuf <[email protected]> wrote:

This adds a CONFIG_STACK_VALIDATION option which enables a host tool named stackvalidate which runs at compile time.

It would be useful to

- show example output for a typical error site

- describe the consequences of that error (ie: why should we fix these things?)

Quoted 7 lines
Quoted 4 lines

- describe what needs to be done to repair these sites.

IOW, what do we gain from merging all this stuff?

I attempted to do all that in Documentation/stack-validation.txt which is in patch 03/20. Does it address your concerns? Here it is:

I think it answers the first and third question, but not the second one:

- describe the consequences of that error (ie: why should we fix these things?)

would be nice to document all that richly.

Thanks,

Ingo

#7 lore raw

Re: [PATCH v10 03/20] x86/stackvalidate: Compile-time stack validation

Quoted 24 lines · Ingo Molnar
Quoted 13 lines · Josh Poimboeuf
Quoted 12 lines · Andrew Morton
Quoted 2 lines · On Thu, 13 Aug 2015 22:10:24 -0500 Josh Poimboeuf <[email protected]> wrote:

This adds a CONFIG_STACK_VALIDATION option which enables a host tool named stackvalidate which runs at compile time.

It would be useful to

- show example output for a typical error site

- describe the consequences of that error (ie: why should we fix these things?)

Quoted 7 lines
Quoted 4 lines

- describe what needs to be done to repair these sites.

IOW, what do we gain from merging all this stuff?

I attempted to do all that in Documentation/stack-validation.txt which is in patch 03/20. Does it address your concerns? Here it is:

Quoted 6 lines

I think it answers the first and third question, but not the second one:

- describe the consequences of that error (ie: why should we fix these things?)

would be nice to document all that richly.

Ok. I've tried to answer the "why" question from both a broad perspective ("why do we need stackvalidate?") as well as for each of the rules that it enforces.

---8<---

Subject: [PATCH] stackvalidate: Document why it's needed

---
 Documentation/stack-validation.txt | 122 +++++++++++++++++++++++++++++++++++--
 1 file changed, 118 insertions(+), 4 deletions(-)
Documentation/stack-validation.txt +118 -4
index c3d3d35..94dad40 100644
@@ -24,6 +24,101 @@ instructions).  Similarly, it knows how to follow switch statements, for
 which gcc sometimes uses jump tables.
 
 
+Why do we need stack validation?
+--------------------------------
+
+Here are some of the benefits of validating stack metadata:
+
+a) More reliable stack traces for frame pointer enabled kernels
+
+   Frame pointers are used for debugging purposes.  They allow runtime
+   code and debug tools to be able to walk the stack to determine the
+   chain of function call sites that led to the currently executing
+   code.
+
+   For some architectures, frame pointers are enabled by
+   CONFIG_FRAME_POINTER.  For some other architectures they may be
+   required by the ABI (sometimes referred to as "backchain pointers").
+
+   For C code, gcc automatically generates instructions for setting up
+   frame pointers when the -fno-omit-frame-pointer option is used.
+
+   But for asm code, the frame setup instructions have to be written by
+   hand, which most people don't do.  So the end result is that
+   CONFIG_FRAME_POINTER is honored for C code but not for most asm code.
+
+   For stack traces based on frame pointers to be reliable, all
+   functions which call other functions must first create a stack frame
+   and update the frame pointer.  If a first function doesn't properly
+   create a stack frame before calling a second function, the *caller*
+   of the first function will be skipped on the stack trace.
+
+   The benefit of stackvalidate here is that it ensures that *all*
+   functions honor CONFIG_FRAME_POINTER.  As a result, no functions will
+   ever [*] be skipped on a stack trace.
+
+   [*] unless an interrupt or exception has occurred at the very
+       beginning of a function before the stack frame has been created,
+       or at the very end of the function after the stack frame has been
+       destroyed.  This is an inherent limitation of frame pointers.
+
+b) 100% reliable stack traces for DWARF enabled kernels
+
+   (NOTE: This is not yet implemented)
+
+   As an alternative to frame pointers, DWARF Call Frame Information
+   (CFI) metadata can be used to walk the stack.  Unlike frame pointers,
+   CFI metadata is out of band.  So it doesn't affect runtime
+   performance and it can be reliable even when interrupts or exceptions
+   are involved.
+
+   For C code, gcc automatically generates DWARF CFI metadata.  But for
+   asm code, generating CFI is a tedious manual approach which requires
+   manually placed .cfi assembler macros to be scattered throughout the
+   code.  It's clumsy and very easy to get wrong, and it makes the real
+   code harder to read.
+
+   Stackvalidate will improve this situation in several ways.  For code
+   which already has CFI annotations, it will validate them.  For code
+   which doesn't have CFI annotations, it will generate them.  So an
+   architecture can opt to strip out all the manual .cfi annotations
+   from their asm code and have stackvalidate generate them instead.
+
+   We might also add a runtime stack validation debug option where we
+   periodically walk the stack from schedule() and/or an NMI to ensure
+   that the stack metadata is sane and that we reach the bottom of the
+   stack.
+
+   So the benefit of stackvalidate here will be that external tooling
+   should always show perfect stack traces.  And the same will be true
+   for kernel warning/oops traces if the architecture has a runtime
+   DWARF unwinder.
+
+c) Higher live patching compatibility rate
+
+   (NOTE: This is not yet implemented)
+
+   Currently with CONFIG_LIVEPATCH there's a basic live patching
+   framework which is safe for roughly 85-90% of "security" fixes.  But
+   patches can't have complex features like function dependency or
+   prototype changes, or data structure changes.
+
+   There's a strong need to support patches which have the more complex
+   features so that the patch compatibility rate for security fixes can
+   eventually approach something resembling 100%.  To achieve that, a
+   "consistency model" is needed, which allows tasks to be safely
+   transitioned from an unpatched state to a patched state.
+
+   One of the key requirements of the currently proposed livepatch
+   consistency model [*] is that it needs to walk the stack of each
+   sleeping task to determine if it can be transitioned to the patched
+   state.  If stackvalidate can ensure that stack traces are reliable,
+   this consistency model can be used and the live patching
+   compatibility rate can be improved significantly.
+
+   [*] https://lkml.kernel.org/r/[email protected]
+
+
 Rules
 -----
 
@@ -35,15 +130,26 @@ To achieve the validation, stackvalidate enforces the following rules:
    outside of a function, it flags an error since that usually indicates
    callable code which should be annotated accordingly.
 
+   This rule is needed so that stackvalidate can properly identify each
+   callable function in order to analyze its stack metadata.
+
 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.
 
+   This rule is needed so that stackvalidate can ignore non-callable
+   code.  Such code doesn't have to follow any of the other rules.
+
 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_BEGIN/FRAME_END macros.
 
+   This rule ensures that frame pointer based stack traces will work as
+   designed.  If function A doesn't create a stack frame before calling
+   function B, the _caller_ of function A will be skipped on the stack
+   trace.
+
 4. Dynamic jumps and jumps to undefined symbols are only allowed if:
 
    a) the jump is part of a switch statement; or
@@ -51,10 +157,18 @@ To achieve the validation, stackvalidate enforces the following rules:
    b) the jump matches sibling call semantics and the frame pointer has
       the same value it had on function entry.
 
+   This rule is needed so that stackvalidate can reliably analyze all of
+   a function's code paths.  If a function jumps to code in another
+   file, and it's not a sibling call, stackvalidate has no way to follow
+   the jump because it only analyzes a single file at a time.
+
 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.
 
+   This rule is just a sanity check to ensure that callable functions
+   return normally.
+
 
 Errors in .S files
 ------------------
@@ -63,8 +177,8 @@ 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.
+Here are some examples of common warnings reported by stackvalidate,
+what they mean, and suggestions for how to fix them.
 
 
 1. stackvalidate: asm_file.o: func()+0x128: call without frame pointer save/setup
@@ -73,8 +187,8 @@ them.
    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.
+   logic using the FRAME_BEGIN and FRAME_END 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.
Signature · 1 line
2.4.3
#8 lore raw

Re: [PATCH v10 03/20] x86/stackvalidate: Compile-time stack validation

Quoted 27 lines · Josh Poimboeuf
Documentation/stack-validation.txt +27 -0
+Why do we need stack validation?
+--------------------------------
+
+Here are some of the benefits of validating stack metadata:
+
+a) More reliable stack traces for frame pointer enabled kernels
+
+   Frame pointers are used for debugging purposes.  They allow runtime
+   code and debug tools to be able to walk the stack to determine the
+   chain of function call sites that led to the currently executing
+   code.
+
+   For some architectures, frame pointers are enabled by
+   CONFIG_FRAME_POINTER.  For some other architectures they may be
+   required by the ABI (sometimes referred to as "backchain pointers").
+
+   For C code, gcc automatically generates instructions for setting up
+   frame pointers when the -fno-omit-frame-pointer option is used.
+
+   But for asm code, the frame setup instructions have to be written by
+   hand, which most people don't do.  So the end result is that
+   CONFIG_FRAME_POINTER is honored for C code but not for most asm code.
+
+   For stack traces based on frame pointers to be reliable, all
+   functions which call other functions must first create a stack frame
+   and update the frame pointer.  If a first function doesn't properly
+   create a stack frame before calling a second function, the *caller*

Documentation/stack-validation.txt instructions). Similarly, it knows how to follow switch statements, for · line 63

Quoted 10 lines
Documentation/stack-validation.txt +10 -0
+   of the first function will be skipped on the stack trace.
+
+   The benefit of stackvalidate here is that it ensures that *all*
+   functions honor CONFIG_FRAME_POINTER.  As a result, no functions will
+   ever [*] be skipped on a stack trace.
+
+   [*] unless an interrupt or exception has occurred at the very
+       beginning of a function before the stack frame has been created,
+       or at the very end of the function after the stack frame has been
+       destroyed.  This is an inherent limitation of frame pointers.

What this section does not point out is the actual effects of missing frame pointer annotations. I.e. how about quoting a before/after stack backtrace to demonstrate it?

Thanks,

Ingo

#9 lore raw

Re: [PATCH v10 03/20] x86/stackvalidate: Compile-time stack validation

Quoted 36 lines · Ingo Molnar
Quoted 33 lines · Josh Poimboeuf
(quoted diff) +33 -0
+Why do we need stack validation?
+--------------------------------
+
+Here are some of the benefits of validating stack metadata:
+
+a) More reliable stack traces for frame pointer enabled kernels
+
+   Frame pointers are used for debugging purposes.  They allow runtime
+   code and debug tools to be able to walk the stack to determine the
+   chain of function call sites that led to the currently executing
+   code.
+
+   For some architectures, frame pointers are enabled by
+   CONFIG_FRAME_POINTER.  For some other architectures they may be
+   required by the ABI (sometimes referred to as "backchain pointers").
+
+   For C code, gcc automatically generates instructions for setting up
+   frame pointers when the -fno-omit-frame-pointer option is used.
+
+   But for asm code, the frame setup instructions have to be written by
+   hand, which most people don't do.  So the end result is that
+   CONFIG_FRAME_POINTER is honored for C code but not for most asm code.
+
+   For stack traces based on frame pointers to be reliable, all
+   functions which call other functions must first create a stack frame
+   and update the frame pointer.  If a first function doesn't properly
+   create a stack frame before calling a second function, the *caller*
+   of the first function will be skipped on the stack trace.
+
+   The benefit of stackvalidate here is that it ensures that *all*
+   functions honor CONFIG_FRAME_POINTER.  As a result, no functions will
+   ever [*] be skipped on a stack trace.
+
Quoted 8 lines

Review

Quoted 4 lines
(quoted diff) +4 -0
+   [*] unless an interrupt or exception has occurred at the very
+       beginning of a function before the stack frame has been created,
+       or at the very end of the function after the stack frame has been
+       destroyed.  This is an inherent limitation of frame pointers.

What this section does not point out is the actual effects of missing frame pointer annotations. I.e. how about quoting a before/after stack backtrace to demonstrate it?

How about this (on top of the last one):

---8<---

From: Josh Poimboeuf <[email protected]>
Subject: [PATCH] stackvalidate: Add missing frame pointer example

---
 Documentation/stack-validation.txt | 37 ++++++++++++++++++++++++++++++++++---
 1 file changed, 34 insertions(+), 3 deletions(-)
Documentation/stack-validation.txt +34 -3
index 94dad40..87a5ab8 100644
@@ -53,9 +53,40 @@ a) More reliable stack traces for frame pointer enabled kernels
    create a stack frame before calling a second function, the *caller*
    of the first function will be skipped on the stack trace.
 
-   The benefit of stackvalidate here is that it ensures that *all*
-   functions honor CONFIG_FRAME_POINTER.  As a result, no functions will
-   ever [*] be skipped on a stack trace.
+   For example, consider the following example backtrace with frame
+   pointers enabled:
+
+     [<ffffffff81812584>] dump_stack+0x4b/0x63
+     [<ffffffff812d6dc2>] cmdline_proc_show+0x12/0x30
+     [<ffffffff8127f568>] seq_read+0x108/0x3e0
+     [<ffffffff812cce62>] proc_reg_read+0x42/0x70
+     [<ffffffff81256197>] __vfs_read+0x37/0x100
+     [<ffffffff81256b16>] vfs_read+0x86/0x130
+     [<ffffffff81257898>] SyS_read+0x58/0xd0
+     [<ffffffff8181c1f2>] entry_SYSCALL_64_fastpath+0x12/0x76
+
+   It correctly shows that the caller of cmdline_proc_show() is
+   seq_read().
+
+   If we remove the frame pointer logic from cmdline_proc_show() by
+   replacing the frame pointer related instructions with nops, here's
+   what it looks like instead:
+
+     [<ffffffff81812584>] dump_stack+0x4b/0x63
+     [<ffffffff812d6dc2>] cmdline_proc_show+0x12/0x30
+     [<ffffffff812cce62>] proc_reg_read+0x42/0x70
+     [<ffffffff81256197>] __vfs_read+0x37/0x100
+     [<ffffffff81256b16>] vfs_read+0x86/0x130
+     [<ffffffff81257898>] SyS_read+0x58/0xd0
+     [<ffffffff8181c1f2>] entry_SYSCALL_64_fastpath+0x12/0x76
+
+   Notice that cmdline_proc_show()'s caller, seq_read(), has been
+   skipped.  Instead the stack trace seems to show that
+   cmdline_proc_show() was called by proc_reg_read().
+
+   The benefit of stackvalidate here is that because it ensures that
+   *all* functions honor CONFIG_FRAME_POINTER, no functions will ever[*]
+   be skipped on a stack trace.
 
    [*] unless an interrupt or exception has occurred at the very
        beginning of a function before the stack frame has been created,
Signature · 1 line
2.4.3
#10 lore raw

Re: [PATCH v10 03/20] x86/stackvalidate: Compile-time stack validation

Quoted 93 lines · Josh Poimboeuf
Quoted 36 lines · Ingo Molnar
Quoted 33 lines · Josh Poimboeuf
(quoted diff) +33 -0
+Why do we need stack validation?
+--------------------------------
+
+Here are some of the benefits of validating stack metadata:
+
+a) More reliable stack traces for frame pointer enabled kernels
+
+   Frame pointers are used for debugging purposes.  They allow runtime
+   code and debug tools to be able to walk the stack to determine the
+   chain of function call sites that led to the currently executing
+   code.
+
+   For some architectures, frame pointers are enabled by
+   CONFIG_FRAME_POINTER.  For some other architectures they may be
+   required by the ABI (sometimes referred to as "backchain pointers").
+
+   For C code, gcc automatically generates instructions for setting up
+   frame pointers when the -fno-omit-frame-pointer option is used.
+
+   But for asm code, the frame setup instructions have to be written by
+   hand, which most people don't do.  So the end result is that
+   CONFIG_FRAME_POINTER is honored for C code but not for most asm code.
+
+   For stack traces based on frame pointers to be reliable, all
+   functions which call other functions must first create a stack frame
+   and update the frame pointer.  If a first function doesn't properly
+   create a stack frame before calling a second function, the *caller*
+   of the first function will be skipped on the stack trace.
+
+   The benefit of stackvalidate here is that it ensures that *all*
+   functions honor CONFIG_FRAME_POINTER.  As a result, no functions will
+   ever [*] be skipped on a stack trace.
+
Quoted 8 lines

Review

Quoted 4 lines
(quoted diff) +4 -0
+   [*] unless an interrupt or exception has occurred at the very
+       beginning of a function before the stack frame has been created,
+       or at the very end of the function after the stack frame has been
+       destroyed.  This is an inherent limitation of frame pointers.

What this section does not point out is the actual effects of missing frame pointer annotations. I.e. how about quoting a before/after stack backtrace to demonstrate it?

How about this (on top of the last one):

---8<---

From: Josh Poimboeuf <[email protected]>
Subject: [PATCH] stackvalidate: Add missing frame pointer example

---
 Documentation/stack-validation.txt | 37 ++++++++++++++++++++++++++++++++++---
 1 file changed, 34 insertions(+), 3 deletions(-)
Documentation/stack-validation.txt +24 -3
index 94dad40..87a5ab8 100644
@@ -53,9 +53,40 @@ a) More reliable stack traces for frame pointer enabled kernels
    create a stack frame before calling a second function, the *caller*
    of the first function will be skipped on the stack trace.
 
-   The benefit of stackvalidate here is that it ensures that *all*
-   functions honor CONFIG_FRAME_POINTER.  As a result, no functions will
-   ever [*] be skipped on a stack trace.
+   For example, consider the following example backtrace with frame
+   pointers enabled:
+
+     [<ffffffff81812584>] dump_stack+0x4b/0x63
+     [<ffffffff812d6dc2>] cmdline_proc_show+0x12/0x30
+     [<ffffffff8127f568>] seq_read+0x108/0x3e0
+     [<ffffffff812cce62>] proc_reg_read+0x42/0x70
+     [<ffffffff81256197>] __vfs_read+0x37/0x100
+     [<ffffffff81256b16>] vfs_read+0x86/0x130
+     [<ffffffff81257898>] SyS_read+0x58/0xd0
+     [<ffffffff8181c1f2>] entry_SYSCALL_64_fastpath+0x12/0x76
+
+   It correctly shows that the caller of cmdline_proc_show() is
+   seq_read().
+
+   If we remove the frame pointer logic from cmdline_proc_show() by
+   replacing the frame pointer related instructions with nops, here's
+   what it looks like instead:
+
+     [<ffffffff81812584>] dump_stack+0x4b/0x63
+     [<ffffffff812d6dc2>] cmdline_proc_show+0x12/0x30
+     [<ffffffff812cce62>] proc_reg_read+0x42/0x70
+     [<ffffffff81256197>] __vfs_read+0x37/0x100
+     [<ffffffff81256b16>] vfs_read+0x86/0x130

Documentation/stack-validation.txt a) More reliable stack traces for frame pointer enabled kernels · line 89

Quoted 10 lines
Documentation/stack-validation.txt +10 -0
+     [<ffffffff81257898>] SyS_read+0x58/0xd0
+     [<ffffffff8181c1f2>] entry_SYSCALL_64_fastpath+0x12/0x76
+
+   Notice that cmdline_proc_show()'s caller, seq_read(), has been
+   skipped.  Instead the stack trace seems to show that
+   cmdline_proc_show() was called by proc_reg_read().
+
+   The benefit of stackvalidate here is that because it ensures that
+   *all* functions honor CONFIG_FRAME_POINTER, no functions will ever[*]
+   be skipped on a stack trace.

Ok, this sounds good to me!

Thanks,

Ingo

#11 lore raw

PATCH v10 4/20 x86/stackvalidate: Add file and directory ignores

In reply to Josh Poimboeuf

Tell stackvalidate to skip validation of the following code:

- boot image
- vdso image
- kexec purgatory
- realmode
- efi libstub
- scripts/mod

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.

---
 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 +
 scripts/mod/Makefile                  | 2 ++
 8 files changed, 18 insertions(+), 5 deletions(-)
arch/x86/boot/Makefile +2 -1
index 0d553e5..d31808c 100644
@@ -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
 
arch/x86/boot/compressed/Makefile +2 -1
index 0a291cd..530a46f 100644
@@ -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
arch/x86/entry/vdso/Makefile +4 -1
index a3d0767..b7cbf61 100644
@@ -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
arch/x86/purgatory/Makefile +2 -0
index 2c835e3..a736c19 100644
@@ -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)
arch/x86/realmode/Makefile +3 -1
index e02c2c6..7a2d4df 100644
@@ -6,7 +6,9 @@
 # for more details.
 #
 #
-KASAN_SANITIZE := n
+KASAN_SANITIZE	:= n
+STACKVALIDATE	:= n
+
 subdir- := rm
 
 obj-y += init.o
arch/x86/realmode/rm/Makefile +2 -1
index 2730d77..d462a57 100644
@@ -6,7 +6,8 @@
 # for more details.
 #
 #
-KASAN_SANITIZE := n
+KASAN_SANITIZE	:= n
+STACKVALIDATE	:= n
 
 always := realmode.bin realmode.relocs
 
drivers/firmware/efi/libstub/Makefile +1 -0
index 816dbe9..b392f3f 100644
@@ -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
scripts/mod/Makefile +2 -0
index c11212f..374c413 100644
@@ -1,3 +1,5 @@
+STACKVALIDATE	:= n
+
 hostprogs-y	:= modpost mk_elfconfig
 always		:= $(hostprogs-y) empty.o
 
Signature · 1 line
2.4.3
#12 lore raw

PATCH v10 5/20 x86/stackvalidate: Add ignore macros

In reply to Josh Poimboeuf

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.

---
 arch/x86/include/asm/stackvalidate.h | 45 ++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/vmlinux.lds.S        |  5 +++-
 include/linux/stackvalidate.h        | 28 ++++++++++++++++++++++
 3 files changed, 77 insertions(+), 1 deletion(-)
 create mode 100644 arch/x86/include/asm/stackvalidate.h
 create mode 100644 include/linux/stackvalidate.h
arch/x86/include/asm/stackvalidate.h new file +45 -0
new file mode 100644
index 0000000..95db052
@@ -0,0 +1,45 @@
+#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
+#ifdef CONFIG_STACK_VALIDATION
+	.Lstackvalidate_ignore_\@:
+	.pushsection __stackvalidate_ignore_insn, "a"
+	_ASM_ALIGN
+	.long .Lstackvalidate_ignore_\@ - .
+	.popsection
+#endif
+.endm
+
+#else /* !__ASSEMBLY__ */
+
+#ifdef CONFIG_STACK_VALIDATION
+
+#define STACKVALIDATE_IGNORE_INSN				\
+	"1:\n"							\
+	".pushsection __stackvalidate_ignore_insn, \"a\"\n"	\
+	_ASM_ALIGN "\n"						\
+	".long 1b - .\n"					\
+	".popsection\n"
+
+#else /* !CONFIG_STACK_VALIDATION */
+
+#define STACKVALIDATE_IGNORE_INSN ""
+
+#endif /* CONFIG_STACK_VALIDATION */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_X86_STACKVALIDATE_H */
arch/x86/kernel/vmlinux.lds.S +4 -1
index 00bf300..f2f8d7a 100644
@@ -332,7 +332,10 @@ SECTIONS
 
 	/* Sections to be discarded */
 	DISCARDS
-	/DISCARD/ : { *(.eh_frame) }
+	/DISCARD/ : {
+		*(.eh_frame)
+		*(__stackvalidate_ignore_*)
+	}
 }
 
 
include/linux/stackvalidate.h new file +28 -0
new file mode 100644
index 0000000..4ae242c
@@ -0,0 +1,28 @@
+#ifndef _LINUX_STACKVALIDATE_H
+#define _LINUX_STACKVALIDATE_H
+
+#include <asm/stackvalidate.h>
+
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_STACK_VALIDATION
+/*
+ * 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
+
+#else /* !CONFIG_STACK_VALIDATION */
+
+#define STACKVALIDATE_IGNORE_FUNC(_func)
+
+#endif /* CONFIG_STACK_VALIDATION */
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _LINUX_STACKVALIDATE_H */
Signature · 1 line
2.4.3
#13 lore raw

PATCH v10 6/20 x86/xen: Add stack frame dependency to hypercall inline asm calls

In reply to Josh Poimboeuf

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.

Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Boris Ostrovsky <[email protected]>
Cc David Vrabel <[email protected]>
---
 arch/x86/include/asm/xen/hypercall.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
arch/x86/include/asm/xen/hypercall.h +3 -2
index ca08a27..4488fbc 100644
@@ -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)
Signature · 1 line
2.4.3
#14 lore raw

PATCH v10 7/20 x86/paravirt: Add stack frame dependency to PVOP inline asm calls

In reply to Josh Poimboeuf

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 if CONFIG_FRAME_POINTER is enabled by listing the stack pointer as an output operand for the PVOP inline asm statements.

Cc Jeremy Fitzhardinge <[email protected]>
Cc Chris Wright <[email protected]>
Cc Alok Kataria <[email protected]>
Cc Rusty Russell <[email protected]>
---
 arch/x86/include/asm/paravirt_types.h | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)
arch/x86/include/asm/paravirt_types.h +10 -8
index ce029e4..1812294 100644
@@ -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__				\
Signature · 1 line
2.4.3
#15 lore raw

PATCH v10 8/20 x86/paravirt: Create a stack frame in PV_CALLEE_SAVE_REGS_THUNK

In reply to Josh Poimboeuf

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.

Cc Jeremy Fitzhardinge <[email protected]>
Cc Chris Wright <[email protected]>
Cc Alok Kataria <[email protected]>
Cc Rusty Russell <[email protected]>
---
 arch/x86/include/asm/paravirt.h | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
arch/x86/include/asm/paravirt.h +7 -2
index c2be037..0d28801 100644
@@ -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_BEGIN							\
 	    PV_SAVE_ALL_CALLER_REGS					\
 	    "call " #func ";"						\
 	    PV_RESTORE_ALL_CALLER_REGS					\
+	    FRAME_END							\
 	    "ret;"							\
 	    ".popsection")
 
Signature · 1 line
2.4.3
#16 lore raw

PATCH v10 9/20 x86/amd: Set ELF function type for vide()

In reply to Josh Poimboeuf

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.

---
 arch/x86/kernel/cpu/amd.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
arch/x86/kernel/cpu/amd.c +4 -1
index 51ad2af..d19c9ad 100644
@@ -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\n"
+	".type vide, @function\n"
+	".align 4\n"
+	"vide: ret\n");
 
 static void init_amd_k5(struct cpuinfo_x86 *c)
 {
Signature · 1 line
2.4.3
#17 lore raw

PATCH v10 10/20 x86/reboot: Add ljmp instructions to stackvalidate whitelist

In reply to Josh Poimboeuf

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.

---
 arch/x86/kernel/reboot.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
arch/x86/kernel/reboot.c +5 -2
index 86db4bc..0931d87 100644
@@ -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
Signature · 1 line
2.4.3
#18 lore raw

PATCH v10 11/20 x86/xen: Add xen_cpuid() and xen_setup_gdt() to stackvalidate whitelists

In reply to Josh Poimboeuf

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.

Cc Konrad Rzeszutek Wilk <[email protected]>
Cc Boris Ostrovsky <[email protected]>
Cc David Vrabel <[email protected]>
---
 arch/x86/xen/enlighten.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
arch/x86/xen/enlighten.c +3 -1
index d9cfa45..4ca89ac 100644
@@ -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)
 {
@@ -1443,6 +1444,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
 /*
Signature · 1 line
2.4.3
#19 lore raw

PATCH v10 12/20 x86/asm/crypto: Create stack frames in aesni-intel_asm.S

In reply to Josh Poimboeuf

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.

Cc Herbert Xu <[email protected]>
Cc "David S. Miller" <[email protected]>
---
 arch/x86/crypto/aesni-intel_asm.S | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
arch/x86/crypto/aesni-intel_asm.S +19 -0
index 6bd2c6c..289ef12 100644
@@ -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_BEGIN
 #ifndef __x86_64__
 	pushl KEYP
 	movl 8(%esp), KEYP		# ctx
@@ -1905,6 +1907,7 @@ ENTRY(aesni_set_key)
 #ifndef __x86_64__
 	popl KEYP
 #endif
+	FRAME_END
 	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_BEGIN
 #ifndef __x86_64__
 	pushl KEYP
 	pushl KLEN
@@ -1927,6 +1931,7 @@ ENTRY(aesni_enc)
 	popl KLEN
 	popl KEYP
 #endif
+	FRAME_END
 	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_BEGIN
 #ifndef __x86_64__
 	pushl KEYP
 	pushl KLEN
@@ -2117,6 +2123,7 @@ ENTRY(aesni_dec)
 	popl KLEN
 	popl KEYP
 #endif
+	FRAME_END
 	ret
 ENDPROC(aesni_dec)
 
@@ -2292,6 +2299,7 @@ ENDPROC(_aesni_dec4)
  *		      size_t len)
  */
 ENTRY(aesni_ecb_enc)
+	FRAME_BEGIN
 #ifndef __x86_64__
 	pushl LEN
 	pushl KEYP
@@ -2342,6 +2350,7 @@ ENTRY(aesni_ecb_enc)
 	popl KEYP
 	popl LEN
 #endif
+	FRAME_END
 	ret
 ENDPROC(aesni_ecb_enc)
 
@@ -2350,6 +2359,7 @@ ENDPROC(aesni_ecb_enc)
  *		      size_t len);
  */
 ENTRY(aesni_ecb_dec)
+	FRAME_BEGIN
 #ifndef __x86_64__
 	pushl LEN
 	pushl KEYP
@@ -2401,6 +2411,7 @@ ENTRY(aesni_ecb_dec)
 	popl KEYP
 	popl LEN
 #endif
+	FRAME_END
 	ret
 ENDPROC(aesni_ecb_dec)
 
@@ -2409,6 +2420,7 @@ ENDPROC(aesni_ecb_dec)
  *		      size_t len, u8 *iv)
  */
 ENTRY(aesni_cbc_enc)
+	FRAME_BEGIN
 #ifndef __x86_64__
 	pushl IVP
 	pushl LEN
@@ -2443,6 +2455,7 @@ ENTRY(aesni_cbc_enc)
 	popl LEN
 	popl IVP
 #endif
+	FRAME_END
 	ret
 ENDPROC(aesni_cbc_enc)
 
@@ -2451,6 +2464,7 @@ ENDPROC(aesni_cbc_enc)
  *		      size_t len, u8 *iv)
  */
 ENTRY(aesni_cbc_dec)
+	FRAME_BEGIN
 #ifndef __x86_64__
 	pushl IVP
 	pushl LEN
@@ -2534,6 +2548,7 @@ ENTRY(aesni_cbc_dec)
 	popl LEN
 	popl IVP
 #endif
+	FRAME_END
 	ret
 ENDPROC(aesni_cbc_dec)
 
@@ -2598,6 +2613,7 @@ ENDPROC(_aesni_inc)
  *		      size_t len, u8 *iv)
  */
 ENTRY(aesni_ctr_enc)
+	FRAME_BEGIN
 	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:
+	FRAME_END
 	ret
 ENDPROC(aesni_ctr_enc)
 
@@ -2677,6 +2694,7 @@ ENDPROC(aesni_ctr_enc)
  *			 bool enc, u8 *iv)
  */
 ENTRY(aesni_xts_crypt8)
+	FRAME_BEGIN
 	cmpb $0, %cl
 	movl $0, %ecx
 	movl $240, %r10d
@@ -2777,6 +2795,7 @@ ENTRY(aesni_xts_crypt8)
 	pxor INC, STATE4
 	movdqu STATE4, 0x70(OUTP)
 
+	FRAME_END
 	ret
 ENDPROC(aesni_xts_crypt8)
 
Signature · 1 line
2.4.3
#20 lore raw

PATCH v10 13/20 x86/asm/crypto: Move .Lbswap_mask data to .rodata section

In reply to Josh Poimboeuf

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.

Cc Herbert Xu <[email protected]>
Cc "David S. Miller" <[email protected]>
---
 arch/x86/crypto/aesni-intel_asm.S | 2 ++
 1 file changed, 2 insertions(+)
arch/x86/crypto/aesni-intel_asm.S +2 -0
index 289ef12..18f0ced 100644
@@ -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
Signature · 1 line
2.4.3
#21 lore raw

PATCH v10 14/20 x86/asm/crypto: Move jump_table to .rodata section

In reply to Josh Poimboeuf

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.

Cc Herbert Xu <[email protected]>
Cc "David S. Miller" <[email protected]>
---
 arch/x86/crypto/crc32c-pcl-intel-asm_64.S | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
arch/x86/crypto/crc32c-pcl-intel-asm_64.S +4 -4
index 225be06..dc05f01 100644
@@ -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
Signature · 1 line
2.4.3
#22 lore raw

PATCH v10 15/20 x86/asm/crypto: Create stack frames in clmul_ghash_mul/update()

In reply to Josh Poimboeuf

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.

Cc Herbert Xu <[email protected]>
Cc "David S. Miller" <[email protected]>
---
 arch/x86/crypto/ghash-clmulni-intel_asm.S | 5 +++++
 1 file changed, 5 insertions(+)
arch/x86/crypto/ghash-clmulni-intel_asm.S +5 -0
index 5d1e007..eed55c8 100644
@@ -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_BEGIN
 	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)
+	FRAME_END
 	ret
 ENDPROC(clmul_ghash_mul)
 
@@ -109,6 +112,7 @@ ENDPROC(clmul_ghash_mul)
  *			   const u128 *shash);
  */
 ENTRY(clmul_ghash_update)
+	FRAME_BEGIN
 	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:
+	FRAME_END
 	ret
 ENDPROC(clmul_ghash_update)
Signature · 1 line
2.4.3
#23 lore raw

PATCH v10 16/20 x86/asm/entry: Create stack frames in thunk functions

In reply to Josh Poimboeuf

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.

---
 arch/x86/entry/thunk_64.S | 4 ++++
 1 file changed, 4 insertions(+)
arch/x86/entry/thunk_64.S +4 -0
index efb2b93..98df1fa 100644
@@ -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_BEGIN
 
 	/* this one pushes 9 elems, the next one would be %rIP */
 	pushq %rdi
@@ -62,6 +65,7 @@ restore:
 	popq %rdx
 	popq %rsi
 	popq %rdi
+	FRAME_END
 	ret
 	_ASM_NOKPROBE(restore)
 #endif
Signature · 1 line
2.4.3
#24 lore raw

PATCH v10 17/20 x86/asm/acpi: Create a stack frame in do_suspend_lowlevel()

In reply to Josh Poimboeuf

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.

---
 arch/x86/kernel/acpi/wakeup_64.S | 3 +++
 1 file changed, 3 insertions(+)
arch/x86/kernel/acpi/wakeup_64.S +3 -0
index 8c35df4..169963f 100644
@@ -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 <[email protected]>, distribute under GPLv2
 
@@ -39,6 +40,7 @@ bogus_64_magic:
 	jmp	bogus_64_magic
 
 ENTRY(do_suspend_lowlevel)
+	FRAME_BEGIN
 	subq	$8, %rsp
 	xorl	%eax, %eax
 	call	save_processor_state
@@ -109,6 +111,7 @@ ENTRY(do_suspend_lowlevel)
 
 	xorl	%eax, %eax
 	addq	$8, %rsp
+	FRAME_END
 	jmp	restore_processor_state
 ENDPROC(do_suspend_lowlevel)
 
Signature · 1 line
2.4.3
#25 lore raw

PATCH v10 18/20 x86/asm: Create stack frames in rwsem functions

In reply to Josh Poimboeuf

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.

---
 arch/x86/lib/rwsem.S | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
arch/x86/lib/rwsem.S +10 -1
index 40027db..be110ef 100644
@@ -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_BEGIN
 	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
+	FRAME_END
 	ret
 ENDPROC(call_rwsem_down_read_failed)
 
 ENTRY(call_rwsem_down_write_failed)
+	FRAME_BEGIN
 	save_common_regs
 	movq %rax,%rdi
 	call rwsem_down_write_failed
 	restore_common_regs
+	FRAME_END
 	ret
 ENDPROC(call_rwsem_down_write_failed)
 
 ENTRY(call_rwsem_wake)
+	FRAME_BEGIN
 	/* 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:	FRAME_END
+	ret
 ENDPROC(call_rwsem_wake)
 
 ENTRY(call_rwsem_downgrade_wake)
+	FRAME_BEGIN
 	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
+	FRAME_END
 	ret
 ENDPROC(call_rwsem_downgrade_wake)
Signature · 1 line
2.4.3
#26 lore raw

PATCH v10 19/20 x86/asm/efi: Create a stack frame in efi_call()

In reply to Josh Poimboeuf

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.

---
 arch/x86/platform/efi/efi_stub_64.S | 3 +++
 1 file changed, 3 insertions(+)
arch/x86/platform/efi/efi_stub_64.S +3 -0
index 86d0f9e..0df2dcc 100644
@@ -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_BEGIN
 	SAVE_XMM
 	mov (%rsp), %rax
 	mov 8(%rax), %rax
@@ -88,6 +90,7 @@ ENTRY(efi_call)
 	RESTORE_PGT
 	addq $48, %rsp
 	RESTORE_XMM
+	FRAME_END
 	ret
 ENDPROC(efi_call)
 
Signature · 1 line
2.4.3
Reviewed-by on v10 19/20
#27 lore raw

Re: [PATCH v10 19/20] x86/asm/efi: Create a stack frame in efi_call()

Quoted 32 lines · Josh Poimboeuf

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.

---
 arch/x86/platform/efi/efi_stub_64.S | 3 +++
 1 file changed, 3 insertions(+)
arch/x86/platform/efi/efi_stub_64.S +2 -0
index 86d0f9e..0df2dcc 100644
@@ -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_BEGIN
 	SAVE_XMM
 	mov (%rsp), %rax
 	mov 8(%rax), %rax

arch/x86/platform/efi/efi_stub_64.S ENTRY(efi_call) · line 95

Quoted 6 lines
arch/x86/platform/efi/efi_stub_64.S +1 -0
@@ -88,6 +90,7 @@ ENTRY(efi_call)
 	RESTORE_PGT
 	addq $48, %rsp
 	RESTORE_XMM
+	FRAME_END
 	ret
 ENDPROC(efi_call)

You mention that stackvalidate will recursively validate the frame pointers in all code paths. Since we're calling into firmware code from efi_call(), we don't need to do anything special here right?

I'm guessing stackvalidate would just stop since it has no way of knowing the target address of the %call instruction, but I just wanted to check (especially since the firmware ABI is different).

Signature · 1 line
Matt Fleming, Intel Open Source Technology Center
#28 lore raw

Re: [PATCH v10 19/20] x86/asm/efi: Create a stack frame in efi_call()

Quoted 44 lines · Matt Fleming
Quoted 32 lines · Josh Poimboeuf

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.

---
 arch/x86/platform/efi/efi_stub_64.S | 3 +++
 1 file changed, 3 insertions(+)
arch/x86/platform/efi/efi_stub_64.S +2 -0
index 86d0f9e..0df2dcc 100644
@@ -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_BEGIN
 	SAVE_XMM
 	mov (%rsp), %rax
 	mov 8(%rax), %rax

arch/x86/platform/efi/efi_stub_64.S ENTRY(efi_call) · line 95

Quoted 6 lines
arch/x86/platform/efi/efi_stub_64.S +1 -0
@@ -88,6 +90,7 @@ ENTRY(efi_call)
 	RESTORE_PGT
 	addq $48, %rsp
 	RESTORE_XMM
+	FRAME_END
 	ret
 ENDPROC(efi_call)

You mention that stackvalidate will recursively validate the frame pointers in all code paths. Since we're calling into firmware code from efi_call(), we don't need to do anything special here right?

Quoted 3 lines

I'm guessing stackvalidate would just stop since it has no way of knowing the target address of the %call instruction, but I just wanted to check (especially since the firmware ABI is different).

It recursively follows all code paths *inside* each function, including jumps. It doesn't try to follow calls across functions, which can't be done reliably because of function pointers. Instead it just verifies that each function follows the calling conventions.

The result of creating a stack frame is that the *caller* of the function shows up in the stack trace. So this patch ensures that efi_call()'s caller would show up if, for example, the stack was dumped from an interrupt which occurred in efi_call() between FRAME_BEGIN and FRAME_END.

As to whether it helps in case the stack is dumped from firmware code (or from an interrupt to firmware), it really depends on what the firmware does:

- If it follows frame pointer convention, great (but I'm guessing this is unlikely...)

- If it doesn't follow frame pointer convention, but still leaves rbp alone, then efi_call() would be skipped in the stack trace but efi_call()'s caller and the rest of the stack would still show up.

- If it trashes rbp, then we're out of luck and there's no stack trace.

But regardless of what firmware does, this patch still helps in the case where the stack is dumped starting from efi_call().

Quoted 1 line

Thanks!

Signature · 1 line
Josh
#29 lore raw

PATCH v10 20/20 x86/asm/power: Create stack frames in hibernate_asm_64.S

In reply to Josh Poimboeuf

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.

---
 arch/x86/power/hibernate_asm_64.S | 7 +++++++
 1 file changed, 7 insertions(+)
arch/x86/power/hibernate_asm_64.S +7 -0
index e2386cb..4400a43 100644
@@ -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_BEGIN
 	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
+	FRAME_END
 	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_BEGIN
 	/* 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)
 
+	FRAME_END
 	ret
+ENDPROC(restore_registers)
Signature · 1 line
2.4.3