ibt.h 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #ifndef _ASM_X86_IBT_H
  3. #define _ASM_X86_IBT_H
  4. #include <linux/types.h>
  5. /*
  6. * The rules for enabling IBT are:
  7. *
  8. * - CC_HAS_IBT: the toolchain supports it
  9. * - X86_KERNEL_IBT: it is selected in Kconfig
  10. * - !__DISABLE_EXPORTS: this is regular kernel code
  11. *
  12. * Esp. that latter one is a bit non-obvious, but some code like compressed,
  13. * purgatory, realmode etc.. is built with custom CFLAGS that do not include
  14. * -fcf-protection=branch and things will go *bang*.
  15. *
  16. * When all the above are satisfied, HAS_KERNEL_IBT will be 1, otherwise 0.
  17. */
  18. #if defined(CONFIG_X86_KERNEL_IBT) && !defined(__DISABLE_EXPORTS)
  19. #define HAS_KERNEL_IBT 1
  20. #ifndef __ASSEMBLY__
  21. #ifdef CONFIG_X86_64
  22. #define ASM_ENDBR "endbr64\n\t"
  23. #else
  24. #define ASM_ENDBR "endbr32\n\t"
  25. #endif
  26. #define __noendbr __attribute__((nocf_check))
  27. /*
  28. * Create a dummy function pointer reference to prevent objtool from marking
  29. * the function as needing to be "sealed" (i.e. ENDBR converted to NOP by
  30. * apply_ibt_endbr()).
  31. */
  32. #define IBT_NOSEAL(fname) \
  33. ".pushsection .discard.ibt_endbr_noseal\n\t" \
  34. _ASM_PTR fname "\n\t" \
  35. ".popsection\n\t"
  36. static inline __attribute_const__ u32 gen_endbr(void)
  37. {
  38. u32 endbr;
  39. /*
  40. * Generate ENDBR64 in a way that is sure to not result in
  41. * an ENDBR64 instruction as immediate.
  42. */
  43. asm ( "mov $~0xfa1e0ff3, %[endbr]\n\t"
  44. "not %[endbr]\n\t"
  45. : [endbr] "=&r" (endbr) );
  46. return endbr;
  47. }
  48. static inline __attribute_const__ u32 gen_endbr_poison(void)
  49. {
  50. /*
  51. * 4 byte NOP that isn't NOP4 (in fact it is OSP NOP3), such that it
  52. * will be unique to (former) ENDBR sites.
  53. */
  54. return 0x001f0f66; /* osp nopl (%rax) */
  55. }
  56. static inline bool is_endbr(u32 val)
  57. {
  58. if (val == gen_endbr_poison())
  59. return true;
  60. val &= ~0x01000000U; /* ENDBR32 -> ENDBR64 */
  61. return val == gen_endbr();
  62. }
  63. extern __noendbr u64 ibt_save(void);
  64. extern __noendbr void ibt_restore(u64 save);
  65. #else /* __ASSEMBLY__ */
  66. #ifdef CONFIG_X86_64
  67. #define ENDBR endbr64
  68. #else
  69. #define ENDBR endbr32
  70. #endif
  71. #endif /* __ASSEMBLY__ */
  72. #else /* !IBT */
  73. #define HAS_KERNEL_IBT 0
  74. #ifndef __ASSEMBLY__
  75. #define ASM_ENDBR
  76. #define IBT_NOSEAL(name)
  77. #define __noendbr
  78. static inline bool is_endbr(u32 val) { return false; }
  79. static inline u64 ibt_save(void) { return 0; }
  80. static inline void ibt_restore(u64 save) { }
  81. #else /* __ASSEMBLY__ */
  82. #define ENDBR
  83. #endif /* __ASSEMBLY__ */
  84. #endif /* CONFIG_X86_KERNEL_IBT */
  85. #define ENDBR_INSN_SIZE (4*HAS_KERNEL_IBT)
  86. #endif /* _ASM_X86_IBT_H */