1b0eb93cfSKees Cook // SPDX-License-Identifier: GPL-2.0
2b0eb93cfSKees Cook /*
3b0eb93cfSKees Cook * This is for all the tests relating directly to Control Flow Integrity.
4b0eb93cfSKees Cook */
5b0eb93cfSKees Cook #include "lkdtm.h"
62e53b877SKees Cook #include <asm/page.h>
7b0eb93cfSKees Cook
8b0eb93cfSKees Cook static int called_count;
9b0eb93cfSKees Cook
10b0eb93cfSKees Cook /* Function taking one argument, without a return value. */
lkdtm_increment_void(int * counter)11b0eb93cfSKees Cook static noinline void lkdtm_increment_void(int *counter)
12b0eb93cfSKees Cook {
13b0eb93cfSKees Cook (*counter)++;
14b0eb93cfSKees Cook }
15b0eb93cfSKees Cook
16b0eb93cfSKees Cook /* Function taking one argument, returning int. */
lkdtm_increment_int(int * counter)17b0eb93cfSKees Cook static noinline int lkdtm_increment_int(int *counter)
18b0eb93cfSKees Cook {
19b0eb93cfSKees Cook (*counter)++;
20b0eb93cfSKees Cook
21b0eb93cfSKees Cook return *counter;
22b0eb93cfSKees Cook }
23cf90d038SSami Tolvanen
24cf90d038SSami Tolvanen /* Don't allow the compiler to inline the calls. */
lkdtm_indirect_call(void (* func)(int *))25cf90d038SSami Tolvanen static noinline void lkdtm_indirect_call(void (*func)(int *))
26cf90d038SSami Tolvanen {
27cf90d038SSami Tolvanen func(&called_count);
28cf90d038SSami Tolvanen }
29cf90d038SSami Tolvanen
30b0eb93cfSKees Cook /*
31b0eb93cfSKees Cook * This tries to call an indirect function with a mismatched prototype.
32b0eb93cfSKees Cook */
lkdtm_CFI_FORWARD_PROTO(void)3373f62e60SKees Cook static void lkdtm_CFI_FORWARD_PROTO(void)
34b0eb93cfSKees Cook {
35b0eb93cfSKees Cook /*
36b0eb93cfSKees Cook * Matches lkdtm_increment_void()'s prototype, but not
37b0eb93cfSKees Cook * lkdtm_increment_int()'s prototype.
38b0eb93cfSKees Cook */
39b0eb93cfSKees Cook pr_info("Calling matched prototype ...\n");
40cf90d038SSami Tolvanen lkdtm_indirect_call(lkdtm_increment_void);
41b0eb93cfSKees Cook
42b0eb93cfSKees Cook pr_info("Calling mismatched prototype ...\n");
43cf90d038SSami Tolvanen lkdtm_indirect_call((void *)lkdtm_increment_int);
44b0eb93cfSKees Cook
455b777131SKees Cook pr_err("FAIL: survived mismatched prototype function call!\n");
465b777131SKees Cook pr_expected_config(CONFIG_CFI_CLANG);
47b0eb93cfSKees Cook }
4873f62e60SKees Cook
492e53b877SKees Cook /*
502e53b877SKees Cook * This can stay local to LKDTM, as there should not be a production reason
512e53b877SKees Cook * to disable PAC && SCS.
522e53b877SKees Cook */
532e53b877SKees Cook #ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
542e53b877SKees Cook # ifdef CONFIG_ARM64_BTI_KERNEL
552e53b877SKees Cook # define __no_pac "branch-protection=bti"
562e53b877SKees Cook # else
57*f68022aeSKristina Martsenko # ifdef CONFIG_CC_HAS_BRANCH_PROT_PAC_RET
582e53b877SKees Cook # define __no_pac "branch-protection=none"
59*f68022aeSKristina Martsenko # else
60*f68022aeSKristina Martsenko # define __no_pac "sign-return-address=none"
61*f68022aeSKristina Martsenko # endif
622e53b877SKees Cook # endif
632e53b877SKees Cook # define __no_ret_protection __noscs __attribute__((__target__(__no_pac)))
642e53b877SKees Cook #else
652e53b877SKees Cook # define __no_ret_protection __noscs
662e53b877SKees Cook #endif
672e53b877SKees Cook
682e53b877SKees Cook #define no_pac_addr(addr) \
6977acbdc0SKees Cook ((__force __typeof__(addr))((uintptr_t)(addr) | PAGE_OFFSET))
702e53b877SKees Cook
712e53b877SKees Cook /* The ultimate ROP gadget. */
722e53b877SKees Cook static noinline __no_ret_protection
set_return_addr_unchecked(unsigned long * expected,unsigned long * addr)732e53b877SKees Cook void set_return_addr_unchecked(unsigned long *expected, unsigned long *addr)
742e53b877SKees Cook {
752e53b877SKees Cook /* Use of volatile is to make sure final write isn't seen as a dead store. */
762e53b877SKees Cook unsigned long * volatile *ret_addr = (unsigned long **)__builtin_frame_address(0) + 1;
772e53b877SKees Cook
782e53b877SKees Cook /* Make sure we've found the right place on the stack before writing it. */
792e53b877SKees Cook if (no_pac_addr(*ret_addr) == expected)
802e53b877SKees Cook *ret_addr = (addr);
812e53b877SKees Cook else
822e53b877SKees Cook /* Check architecture, stack layout, or compiler behavior... */
832e53b877SKees Cook pr_warn("Eek: return address mismatch! %px != %px\n",
842e53b877SKees Cook *ret_addr, addr);
852e53b877SKees Cook }
862e53b877SKees Cook
872e53b877SKees Cook static noinline
set_return_addr(unsigned long * expected,unsigned long * addr)882e53b877SKees Cook void set_return_addr(unsigned long *expected, unsigned long *addr)
892e53b877SKees Cook {
902e53b877SKees Cook /* Use of volatile is to make sure final write isn't seen as a dead store. */
912e53b877SKees Cook unsigned long * volatile *ret_addr = (unsigned long **)__builtin_frame_address(0) + 1;
922e53b877SKees Cook
932e53b877SKees Cook /* Make sure we've found the right place on the stack before writing it. */
942e53b877SKees Cook if (no_pac_addr(*ret_addr) == expected)
952e53b877SKees Cook *ret_addr = (addr);
962e53b877SKees Cook else
972e53b877SKees Cook /* Check architecture, stack layout, or compiler behavior... */
982e53b877SKees Cook pr_warn("Eek: return address mismatch! %px != %px\n",
992e53b877SKees Cook *ret_addr, addr);
1002e53b877SKees Cook }
1012e53b877SKees Cook
1022e53b877SKees Cook static volatile int force_check;
1032e53b877SKees Cook
lkdtm_CFI_BACKWARD(void)1042e53b877SKees Cook static void lkdtm_CFI_BACKWARD(void)
1052e53b877SKees Cook {
1062e53b877SKees Cook /* Use calculated gotos to keep labels addressable. */
1075afbfa8cSColin Ian King void *labels[] = { NULL, &&normal, &&redirected, &&check_normal, &&check_redirected };
1082e53b877SKees Cook
1092e53b877SKees Cook pr_info("Attempting unchecked stack return address redirection ...\n");
1102e53b877SKees Cook
1112e53b877SKees Cook /* Always false */
1122e53b877SKees Cook if (force_check) {
1132e53b877SKees Cook /*
1142e53b877SKees Cook * Prepare to call with NULLs to avoid parameters being treated as
1152e53b877SKees Cook * constants in -02.
1162e53b877SKees Cook */
1172e53b877SKees Cook set_return_addr_unchecked(NULL, NULL);
1182e53b877SKees Cook set_return_addr(NULL, NULL);
1192e53b877SKees Cook if (force_check)
1202e53b877SKees Cook goto *labels[1];
1212e53b877SKees Cook if (force_check)
1222e53b877SKees Cook goto *labels[2];
1232e53b877SKees Cook if (force_check)
1242e53b877SKees Cook goto *labels[3];
1252e53b877SKees Cook if (force_check)
1262e53b877SKees Cook goto *labels[4];
1272e53b877SKees Cook return;
1282e53b877SKees Cook }
1292e53b877SKees Cook
1302e53b877SKees Cook /*
1312e53b877SKees Cook * Use fallthrough switch case to keep basic block ordering between
1322e53b877SKees Cook * set_return_addr*() and the label after it.
1332e53b877SKees Cook */
1342e53b877SKees Cook switch (force_check) {
1352e53b877SKees Cook case 0:
1362e53b877SKees Cook set_return_addr_unchecked(&&normal, &&redirected);
1372e53b877SKees Cook fallthrough;
1382e53b877SKees Cook case 1:
1392e53b877SKees Cook normal:
1402e53b877SKees Cook /* Always true */
1412e53b877SKees Cook if (!force_check) {
1422e53b877SKees Cook pr_err("FAIL: stack return address manipulation failed!\n");
1432e53b877SKees Cook /* If we can't redirect "normally", we can't test mitigations. */
1442e53b877SKees Cook return;
1452e53b877SKees Cook }
1462e53b877SKees Cook break;
1472e53b877SKees Cook default:
1482e53b877SKees Cook redirected:
1492e53b877SKees Cook pr_info("ok: redirected stack return address.\n");
1502e53b877SKees Cook break;
1512e53b877SKees Cook }
1522e53b877SKees Cook
1532e53b877SKees Cook pr_info("Attempting checked stack return address redirection ...\n");
1542e53b877SKees Cook
1552e53b877SKees Cook switch (force_check) {
1562e53b877SKees Cook case 0:
1572e53b877SKees Cook set_return_addr(&&check_normal, &&check_redirected);
1582e53b877SKees Cook fallthrough;
1592e53b877SKees Cook case 1:
1602e53b877SKees Cook check_normal:
1612e53b877SKees Cook /* Always true */
1622e53b877SKees Cook if (!force_check) {
1632e53b877SKees Cook pr_info("ok: control flow unchanged.\n");
1642e53b877SKees Cook return;
1652e53b877SKees Cook }
1662e53b877SKees Cook
1672e53b877SKees Cook check_redirected:
1682e53b877SKees Cook pr_err("FAIL: stack return address was redirected!\n");
1692e53b877SKees Cook break;
1702e53b877SKees Cook }
1712e53b877SKees Cook
1722e53b877SKees Cook if (IS_ENABLED(CONFIG_ARM64_PTR_AUTH_KERNEL)) {
1732e53b877SKees Cook pr_expected_config(CONFIG_ARM64_PTR_AUTH_KERNEL);
1742e53b877SKees Cook return;
1752e53b877SKees Cook }
1762e53b877SKees Cook if (IS_ENABLED(CONFIG_SHADOW_CALL_STACK)) {
1772e53b877SKees Cook pr_expected_config(CONFIG_SHADOW_CALL_STACK);
1782e53b877SKees Cook return;
1792e53b877SKees Cook }
1802e53b877SKees Cook pr_warn("This is probably expected, since this %s was built *without* %s=y nor %s=y\n",
1812e53b877SKees Cook lkdtm_kernel_info,
1822e53b877SKees Cook "CONFIG_ARM64_PTR_AUTH_KERNEL", "CONFIG_SHADOW_CALL_STACK");
1832e53b877SKees Cook }
1842e53b877SKees Cook
18573f62e60SKees Cook static struct crashtype crashtypes[] = {
18673f62e60SKees Cook CRASHTYPE(CFI_FORWARD_PROTO),
1872e53b877SKees Cook CRASHTYPE(CFI_BACKWARD),
18873f62e60SKees Cook };
18973f62e60SKees Cook
19073f62e60SKees Cook struct crashtype_category cfi_crashtypes = {
19173f62e60SKees Cook .crashtypes = crashtypes,
19273f62e60SKees Cook .len = ARRAY_SIZE(crashtypes),
19373f62e60SKees Cook };
194