Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef _ASM_X86_IBT_H
0003 #define _ASM_X86_IBT_H
0004 
0005 #include <linux/types.h>
0006 
0007 /*
0008  * The rules for enabling IBT are:
0009  *
0010  *  - CC_HAS_IBT:         the toolchain supports it
0011  *  - X86_KERNEL_IBT:     it is selected in Kconfig
0012  *  - !__DISABLE_EXPORTS: this is regular kernel code
0013  *
0014  * Esp. that latter one is a bit non-obvious, but some code like compressed,
0015  * purgatory, realmode etc.. is built with custom CFLAGS that do not include
0016  * -fcf-protection=branch and things will go *bang*.
0017  *
0018  * When all the above are satisfied, HAS_KERNEL_IBT will be 1, otherwise 0.
0019  */
0020 #if defined(CONFIG_X86_KERNEL_IBT) && !defined(__DISABLE_EXPORTS)
0021 
0022 #define HAS_KERNEL_IBT  1
0023 
0024 #ifndef __ASSEMBLY__
0025 
0026 #ifdef CONFIG_X86_64
0027 #define ASM_ENDBR   "endbr64\n\t"
0028 #else
0029 #define ASM_ENDBR   "endbr32\n\t"
0030 #endif
0031 
0032 #define __noendbr   __attribute__((nocf_check))
0033 
0034 /*
0035  * Create a dummy function pointer reference to prevent objtool from marking
0036  * the function as needing to be "sealed" (i.e. ENDBR converted to NOP by
0037  * apply_ibt_endbr()).
0038  */
0039 #define IBT_NOSEAL(fname)               \
0040     ".pushsection .discard.ibt_endbr_noseal\n\t"    \
0041     _ASM_PTR fname "\n\t"               \
0042     ".popsection\n\t"
0043 
0044 static inline __attribute_const__ u32 gen_endbr(void)
0045 {
0046     u32 endbr;
0047 
0048     /*
0049      * Generate ENDBR64 in a way that is sure to not result in
0050      * an ENDBR64 instruction as immediate.
0051      */
0052     asm ( "mov $~0xfa1e0ff3, %[endbr]\n\t"
0053           "not %[endbr]\n\t"
0054            : [endbr] "=&r" (endbr) );
0055 
0056     return endbr;
0057 }
0058 
0059 static inline __attribute_const__ u32 gen_endbr_poison(void)
0060 {
0061     /*
0062      * 4 byte NOP that isn't NOP4 (in fact it is OSP NOP3), such that it
0063      * will be unique to (former) ENDBR sites.
0064      */
0065     return 0x001f0f66; /* osp nopl (%rax) */
0066 }
0067 
0068 static inline bool is_endbr(u32 val)
0069 {
0070     if (val == gen_endbr_poison())
0071         return true;
0072 
0073     val &= ~0x01000000U; /* ENDBR32 -> ENDBR64 */
0074     return val == gen_endbr();
0075 }
0076 
0077 extern __noendbr u64 ibt_save(void);
0078 extern __noendbr void ibt_restore(u64 save);
0079 
0080 #else /* __ASSEMBLY__ */
0081 
0082 #ifdef CONFIG_X86_64
0083 #define ENDBR   endbr64
0084 #else
0085 #define ENDBR   endbr32
0086 #endif
0087 
0088 #endif /* __ASSEMBLY__ */
0089 
0090 #else /* !IBT */
0091 
0092 #define HAS_KERNEL_IBT  0
0093 
0094 #ifndef __ASSEMBLY__
0095 
0096 #define ASM_ENDBR
0097 #define IBT_NOSEAL(name)
0098 
0099 #define __noendbr
0100 
0101 static inline bool is_endbr(u32 val) { return false; }
0102 
0103 static inline u64 ibt_save(void) { return 0; }
0104 static inline void ibt_restore(u64 save) { }
0105 
0106 #else /* __ASSEMBLY__ */
0107 
0108 #define ENDBR
0109 
0110 #endif /* __ASSEMBLY__ */
0111 
0112 #endif /* CONFIG_X86_KERNEL_IBT */
0113 
0114 #define ENDBR_INSN_SIZE     (4*HAS_KERNEL_IBT)
0115 
0116 #endif /* _ASM_X86_IBT_H */