Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fprobe: Add fprobe_header encoding feature

Fprobe store its data structure address and size on the fgraph return stack
by __fprobe_header. But most 64bit architecture can combine those to
one unsigned long value because 4 MSB in the kernel address are the same.
With this encoding, fprobe can consume less space on ret_stack.

This introduces asm/fprobe.h to define arch dependent encode/decode
macros. Note that since fprobe depends on CONFIG_HAVE_FUNCTION_GRAPH_FREGS,
currently only arm64, loongarch, riscv, s390 and x86 are supported.

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Acked-by: Heiko Carstens <hca@linux.ibm.com> # s390
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Cc: Florent Revest <revest@chromium.org>
Cc: Martin KaFai Lau <martin.lau@linux.dev>
Cc: bpf <bpf@vger.kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Alan Maguire <alan.maguire@oracle.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Huacai Chen <chenhuacai@kernel.org>
Cc: WANG Xuerui <kernel@xen0n.name>
Cc: Paul Walmsley <paul.walmsley@sifive.com>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Albert Ou <aou@eecs.berkeley.edu>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
Cc: Sven Schnelle <svens@linux.ibm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Link: https://lore.kernel.org/173519005783.391279.5307910947400277525.stgit@devnote2
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

authored by

Masami Hiramatsu (Google) and committed by
Steven Rostedt (Google)
b5fa903b 4346ba16

+100
+1
arch/arm64/include/asm/Kbuild
··· 8 8 syscall-y += unistd_compat_32.h 9 9 10 10 generic-y += early_ioremap.h 11 + generic-y += fprobe.h 11 12 generic-y += mcs_spinlock.h 12 13 generic-y += mmzone.h 13 14 generic-y += qrwlock.h
+12
arch/loongarch/include/asm/fprobe.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _ASM_LOONGARCH_FPROBE_H 3 + #define _ASM_LOONGARCH_FPROBE_H 4 + 5 + /* 6 + * Explicitly undef ARCH_DEFINE_ENCODE_FPROBE_HEADER, because loongarch does not 7 + * have enough number of fixed MSBs of the address of kernel objects for 8 + * encoding the size of data in fprobe_header. Use 2-entries encoding instead. 9 + */ 10 + #undef ARCH_DEFINE_ENCODE_FPROBE_HEADER 11 + 12 + #endif /* _ASM_LOONGARCH_FPROBE_H */
+1
arch/riscv/include/asm/Kbuild
··· 4 4 5 5 generic-y += early_ioremap.h 6 6 generic-y += flat.h 7 + generic-y += fprobe.h 7 8 generic-y += kvm_para.h 8 9 generic-y += mmzone.h 9 10 generic-y += mcs_spinlock.h
+10
arch/s390/include/asm/fprobe.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _ASM_S390_FPROBE_H 3 + #define _ASM_S390_FPROBE_H 4 + 5 + #include <asm-generic/fprobe.h> 6 + 7 + #undef FPROBE_HEADER_MSB_PATTERN 8 + #define FPROBE_HEADER_MSB_PATTERN 0 9 + 10 + #endif /* _ASM_S390_FPROBE_H */
+1
arch/x86/include/asm/Kbuild
··· 10 10 generated-y += xen-hypercalls.h 11 11 12 12 generic-y += early_ioremap.h 13 + generic-y += fprobe.h 13 14 generic-y += mcs_spinlock.h 14 15 generic-y += mmzone.h
+46
include/asm-generic/fprobe.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Generic arch dependent fprobe macros. 4 + */ 5 + #ifndef __ASM_GENERIC_FPROBE_H__ 6 + #define __ASM_GENERIC_FPROBE_H__ 7 + 8 + #include <linux/bits.h> 9 + 10 + #ifdef CONFIG_64BIT 11 + /* 12 + * Encoding the size and the address of fprobe into one 64bit entry. 13 + * The 32bit architectures should use 2 entries to store those info. 14 + */ 15 + 16 + #define ARCH_DEFINE_ENCODE_FPROBE_HEADER 17 + 18 + #define FPROBE_HEADER_MSB_SIZE_SHIFT (BITS_PER_LONG - FPROBE_DATA_SIZE_BITS) 19 + #define FPROBE_HEADER_MSB_MASK \ 20 + GENMASK(FPROBE_HEADER_MSB_SIZE_SHIFT - 1, 0) 21 + 22 + /* 23 + * By default, this expects the MSBs in the address of kprobe is 0xf. 24 + * If any arch needs another fixed pattern (e.g. s390 is zero filled), 25 + * override this. 26 + */ 27 + #define FPROBE_HEADER_MSB_PATTERN \ 28 + GENMASK(BITS_PER_LONG - 1, FPROBE_HEADER_MSB_SIZE_SHIFT) 29 + 30 + #define arch_fprobe_header_encodable(fp) \ 31 + (((unsigned long)(fp) & ~FPROBE_HEADER_MSB_MASK) == \ 32 + FPROBE_HEADER_MSB_PATTERN) 33 + 34 + #define arch_encode_fprobe_header(fp, size) \ 35 + (((unsigned long)(fp) & FPROBE_HEADER_MSB_MASK) | \ 36 + ((unsigned long)(size) << FPROBE_HEADER_MSB_SIZE_SHIFT)) 37 + 38 + #define arch_decode_fprobe_header_size(val) \ 39 + ((unsigned long)(val) >> FPROBE_HEADER_MSB_SIZE_SHIFT) 40 + 41 + #define arch_decode_fprobe_header_fp(val) \ 42 + ((struct fprobe *)(((unsigned long)(val) & FPROBE_HEADER_MSB_MASK) | \ 43 + FPROBE_HEADER_MSB_PATTERN)) 44 + #endif /* CONFIG_64BIT */ 45 + 46 + #endif /* __ASM_GENERIC_FPROBE_H__ */
+29
kernel/trace/fprobe.c
··· 13 13 #include <linux/slab.h> 14 14 #include <linux/sort.h> 15 15 16 + #include <asm/fprobe.h> 17 + 16 18 #include "trace.h" 17 19 18 20 #define FPROBE_IP_HASH_BITS 8 ··· 145 143 return 0; 146 144 } 147 145 146 + #ifdef ARCH_DEFINE_ENCODE_FPROBE_HEADER 147 + 148 + /* The arch should encode fprobe_header info into one unsigned long */ 149 + #define FPROBE_HEADER_SIZE_IN_LONG 1 150 + 151 + static inline bool write_fprobe_header(unsigned long *stack, 152 + struct fprobe *fp, unsigned int size_words) 153 + { 154 + if (WARN_ON_ONCE(size_words > MAX_FPROBE_DATA_SIZE_WORD || 155 + !arch_fprobe_header_encodable(fp))) 156 + return false; 157 + 158 + *stack = arch_encode_fprobe_header(fp, size_words); 159 + return true; 160 + } 161 + 162 + static inline void read_fprobe_header(unsigned long *stack, 163 + struct fprobe **fp, unsigned int *size_words) 164 + { 165 + *fp = arch_decode_fprobe_header_fp(*stack); 166 + *size_words = arch_decode_fprobe_header_size(*stack); 167 + } 168 + 169 + #else 170 + 148 171 /* Generic fprobe_header */ 149 172 struct __fprobe_header { 150 173 struct fprobe *fp; ··· 199 172 *fp = fph->fp; 200 173 *size_words = fph->size_words; 201 174 } 175 + 176 + #endif 202 177 203 178 /* 204 179 * fprobe shadow stack management: