cfi.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Clang Control Flow Integrity (CFI) error handling.
  4. *
  5. * Copyright (C) 2022 Google LLC
  6. */
  7. #include <linux/cfi.h>
  8. enum bug_trap_type report_cfi_failure(struct pt_regs *regs, unsigned long addr,
  9. unsigned long *target, u32 type)
  10. {
  11. if (target)
  12. pr_err("CFI failure at %pS (target: %pS; expected type: 0x%08x)\n",
  13. (void *)addr, (void *)*target, type);
  14. else
  15. pr_err("CFI failure at %pS (no target information)\n",
  16. (void *)addr);
  17. if (IS_ENABLED(CONFIG_CFI_PERMISSIVE)) {
  18. __warn(NULL, 0, (void *)addr, 0, regs, NULL);
  19. return BUG_TRAP_TYPE_WARN;
  20. }
  21. return BUG_TRAP_TYPE_BUG;
  22. }
  23. #ifdef CONFIG_ARCH_USES_CFI_TRAPS
  24. static inline unsigned long trap_address(s32 *p)
  25. {
  26. return (unsigned long)((long)p + (long)*p);
  27. }
  28. static bool is_trap(unsigned long addr, s32 *start, s32 *end)
  29. {
  30. s32 *p;
  31. for (p = start; p < end; ++p) {
  32. if (trap_address(p) == addr)
  33. return true;
  34. }
  35. return false;
  36. }
  37. #ifdef CONFIG_MODULES
  38. /* Populates `kcfi_trap(_end)?` fields in `struct module`. */
  39. void module_cfi_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
  40. struct module *mod)
  41. {
  42. char *secstrings;
  43. unsigned int i;
  44. mod->kcfi_traps = NULL;
  45. mod->kcfi_traps_end = NULL;
  46. secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
  47. for (i = 1; i < hdr->e_shnum; i++) {
  48. if (strcmp(secstrings + sechdrs[i].sh_name, "__kcfi_traps"))
  49. continue;
  50. mod->kcfi_traps = (s32 *)sechdrs[i].sh_addr;
  51. mod->kcfi_traps_end = (s32 *)(sechdrs[i].sh_addr + sechdrs[i].sh_size);
  52. break;
  53. }
  54. }
  55. static bool is_module_cfi_trap(unsigned long addr)
  56. {
  57. struct module *mod;
  58. bool found = false;
  59. rcu_read_lock_sched_notrace();
  60. mod = __module_address(addr);
  61. if (mod)
  62. found = is_trap(addr, mod->kcfi_traps, mod->kcfi_traps_end);
  63. rcu_read_unlock_sched_notrace();
  64. return found;
  65. }
  66. #else /* CONFIG_MODULES */
  67. static inline bool is_module_cfi_trap(unsigned long addr)
  68. {
  69. return false;
  70. }
  71. #endif /* CONFIG_MODULES */
  72. extern s32 __start___kcfi_traps[];
  73. extern s32 __stop___kcfi_traps[];
  74. bool is_cfi_trap(unsigned long addr)
  75. {
  76. if (is_trap(addr, __start___kcfi_traps, __stop___kcfi_traps))
  77. return true;
  78. return is_module_cfi_trap(addr);
  79. }
  80. #endif /* CONFIG_ARCH_USES_CFI_TRAPS */