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

Configure Feed

Select the types of activity you want to include in your feed.

x86/cfi: Fix CFI rewrite for odd alignments

Rustam reported his clang builds did not boot properly; turns out his
.config has: CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B=y set.

Fix up the FineIBT code to deal with this unusual alignment.

Fixes: 931ab63664f0 ("x86/ibt: Implement FineIBT")
Reported-by: Rustam Kovhaev <rkovhaev@gmail.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: Rustam Kovhaev <rkovhaev@gmail.com>

+34 -24
+8 -4
arch/x86/include/asm/cfi.h
··· 111 111 112 112 struct pt_regs; 113 113 114 + #ifdef CONFIG_CALL_PADDING 115 + #define CFI_OFFSET (CONFIG_FUNCTION_PADDING_CFI+5) 116 + #else 117 + #define CFI_OFFSET 5 118 + #endif 119 + 114 120 #ifdef CONFIG_CFI 115 121 enum bug_trap_type handle_cfi_failure(struct pt_regs *regs); 116 122 #define __bpfcall ··· 125 119 { 126 120 switch (cfi_mode) { 127 121 case CFI_FINEIBT: 128 - return 16; 122 + return /* fineibt_prefix_size */ 16; 129 123 case CFI_KCFI: 130 - if (IS_ENABLED(CONFIG_CALL_PADDING)) 131 - return 16; 132 - return 5; 124 + return CFI_OFFSET; 133 125 default: 134 126 return 0; 135 127 }
+2 -2
arch/x86/include/asm/linkage.h
··· 68 68 * Depending on -fpatchable-function-entry=N,N usage (CONFIG_CALL_PADDING) the 69 69 * CFI symbol layout changes. 70 70 * 71 - * Without CALL_THUNKS: 71 + * Without CALL_PADDING: 72 72 * 73 73 * .align FUNCTION_ALIGNMENT 74 74 * __cfi_##name: ··· 77 77 * .long __kcfi_typeid_##name 78 78 * name: 79 79 * 80 - * With CALL_THUNKS: 80 + * With CALL_PADDING: 81 81 * 82 82 * .align FUNCTION_ALIGNMENT 83 83 * __cfi_##name:
+22 -7
arch/x86/kernel/alternative.c
··· 1182 1182 1183 1183 poison_endbr(addr); 1184 1184 if (IS_ENABLED(CONFIG_FINEIBT)) 1185 - poison_cfi(addr - 16); 1185 + poison_cfi(addr - CFI_OFFSET); 1186 1186 } 1187 1187 } 1188 1188 ··· 1388 1388 #define fineibt_preamble_bhi (fineibt_preamble_bhi - fineibt_preamble_start) 1389 1389 #define fineibt_preamble_ud 0x13 1390 1390 #define fineibt_preamble_hash 5 1391 + 1392 + #define fineibt_prefix_size (fineibt_preamble_size - ENDBR_INSN_SIZE) 1391 1393 1392 1394 /* 1393 1395 * <fineibt_caller_start>: ··· 1636 1634 * have determined there are no indirect calls to it and we 1637 1635 * don't need no CFI either. 1638 1636 */ 1639 - if (!is_endbr(addr + 16)) 1637 + if (!is_endbr(addr + CFI_OFFSET)) 1640 1638 continue; 1641 1639 1642 1640 hash = decode_preamble_hash(addr, &arity); 1643 1641 if (WARN(!hash, "no CFI hash found at: %pS %px %*ph\n", 1644 1642 addr, addr, 5, addr)) 1645 1643 return -EINVAL; 1644 + 1645 + /* 1646 + * FineIBT relies on being at func-16, so if the preamble is 1647 + * actually larger than that, place it the tail end. 1648 + * 1649 + * NOTE: this is possible with things like DEBUG_CALL_THUNKS 1650 + * and DEBUG_FORCE_FUNCTION_ALIGN_64B. 1651 + */ 1652 + addr += CFI_OFFSET - fineibt_prefix_size; 1646 1653 1647 1654 text_poke_early(addr, fineibt_preamble_start, fineibt_preamble_size); 1648 1655 WARN_ON(*(u32 *)(addr + fineibt_preamble_hash) != 0x12345678); ··· 1675 1664 for (s = start; s < end; s++) { 1676 1665 void *addr = (void *)s + *s; 1677 1666 1678 - if (!exact_endbr(addr + 16)) 1667 + if (!exact_endbr(addr + CFI_OFFSET)) 1679 1668 continue; 1680 1669 1681 - poison_endbr(addr + 16); 1670 + poison_endbr(addr + CFI_OFFSET); 1682 1671 } 1683 1672 } 1684 1673 ··· 1783 1772 if (FINEIBT_WARN(fineibt_preamble_size, 20) || 1784 1773 FINEIBT_WARN(fineibt_preamble_bhi + fineibt_bhi1_size, 20) || 1785 1774 FINEIBT_WARN(fineibt_caller_size, 14) || 1786 - FINEIBT_WARN(fineibt_paranoid_size, 20)) 1775 + FINEIBT_WARN(fineibt_paranoid_size, 20) || 1776 + WARN_ON_ONCE(CFI_OFFSET < fineibt_prefix_size)) 1787 1777 return; 1788 1778 1789 1779 if (cfi_mode == CFI_AUTO) { ··· 1898 1886 switch (cfi_mode) { 1899 1887 case CFI_FINEIBT: 1900 1888 /* 1889 + * FineIBT preamble is at func-16. 1890 + */ 1891 + addr += CFI_OFFSET - fineibt_prefix_size; 1892 + 1893 + /* 1901 1894 * FineIBT prefix should start with an ENDBR. 1902 1895 */ 1903 1896 if (!is_endbr(addr)) ··· 1939 1922 break; 1940 1923 } 1941 1924 } 1942 - 1943 - #define fineibt_prefix_size (fineibt_preamble_size - ENDBR_INSN_SIZE) 1944 1925 1945 1926 /* 1946 1927 * When regs->ip points to a 0xD6 byte in the FineIBT preamble,
+2 -11
arch/x86/net/bpf_jit_comp.c
··· 438 438 439 439 EMIT1_off32(0xb8, hash); /* movl $hash, %eax */ 440 440 #ifdef CONFIG_CALL_PADDING 441 - EMIT1(0x90); 442 - EMIT1(0x90); 443 - EMIT1(0x90); 444 - EMIT1(0x90); 445 - EMIT1(0x90); 446 - EMIT1(0x90); 447 - EMIT1(0x90); 448 - EMIT1(0x90); 449 - EMIT1(0x90); 450 - EMIT1(0x90); 451 - EMIT1(0x90); 441 + for (int i = 0; i < CONFIG_FUNCTION_PADDING_CFI; i++) 442 + EMIT1(0x90); 452 443 #endif 453 444 EMIT_ENDBR(); 454 445