0001
0002
0003
0004
0005 #include "lkdtm.h"
0006 #include <asm/page.h>
0007
0008 static int called_count;
0009
0010
0011 static noinline void lkdtm_increment_void(int *counter)
0012 {
0013 (*counter)++;
0014 }
0015
0016
0017 static noinline int lkdtm_increment_int(int *counter)
0018 {
0019 (*counter)++;
0020
0021 return *counter;
0022 }
0023
0024
0025
0026 static void lkdtm_CFI_FORWARD_PROTO(void)
0027 {
0028
0029
0030
0031
0032 void (*func)(int *);
0033
0034 pr_info("Calling matched prototype ...\n");
0035 func = lkdtm_increment_void;
0036 func(&called_count);
0037
0038 pr_info("Calling mismatched prototype ...\n");
0039 func = (void *)lkdtm_increment_int;
0040 func(&called_count);
0041
0042 pr_err("FAIL: survived mismatched prototype function call!\n");
0043 pr_expected_config(CONFIG_CFI_CLANG);
0044 }
0045
0046
0047
0048
0049
0050 #ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
0051 # ifdef CONFIG_ARM64_BTI_KERNEL
0052 # define __no_pac "branch-protection=bti"
0053 # else
0054 # define __no_pac "branch-protection=none"
0055 # endif
0056 # define __no_ret_protection __noscs __attribute__((__target__(__no_pac)))
0057 #else
0058 # define __no_ret_protection __noscs
0059 #endif
0060
0061 #define no_pac_addr(addr) \
0062 ((__force __typeof__(addr))((uintptr_t)(addr) | PAGE_OFFSET))
0063
0064
0065 static noinline __no_ret_protection
0066 void set_return_addr_unchecked(unsigned long *expected, unsigned long *addr)
0067 {
0068
0069 unsigned long * volatile *ret_addr = (unsigned long **)__builtin_frame_address(0) + 1;
0070
0071
0072 if (no_pac_addr(*ret_addr) == expected)
0073 *ret_addr = (addr);
0074 else
0075
0076 pr_warn("Eek: return address mismatch! %px != %px\n",
0077 *ret_addr, addr);
0078 }
0079
0080 static noinline
0081 void set_return_addr(unsigned long *expected, unsigned long *addr)
0082 {
0083
0084 unsigned long * volatile *ret_addr = (unsigned long **)__builtin_frame_address(0) + 1;
0085
0086
0087 if (no_pac_addr(*ret_addr) == expected)
0088 *ret_addr = (addr);
0089 else
0090
0091 pr_warn("Eek: return address mismatch! %px != %px\n",
0092 *ret_addr, addr);
0093 }
0094
0095 static volatile int force_check;
0096
0097 static void lkdtm_CFI_BACKWARD(void)
0098 {
0099
0100 void *labels[] = { NULL, &&normal, &&redirected, &&check_normal, &&check_redirected };
0101
0102 pr_info("Attempting unchecked stack return address redirection ...\n");
0103
0104
0105 if (force_check) {
0106
0107
0108
0109
0110 set_return_addr_unchecked(NULL, NULL);
0111 set_return_addr(NULL, NULL);
0112 if (force_check)
0113 goto *labels[1];
0114 if (force_check)
0115 goto *labels[2];
0116 if (force_check)
0117 goto *labels[3];
0118 if (force_check)
0119 goto *labels[4];
0120 return;
0121 }
0122
0123
0124
0125
0126
0127 switch (force_check) {
0128 case 0:
0129 set_return_addr_unchecked(&&normal, &&redirected);
0130 fallthrough;
0131 case 1:
0132 normal:
0133
0134 if (!force_check) {
0135 pr_err("FAIL: stack return address manipulation failed!\n");
0136
0137 return;
0138 }
0139 break;
0140 default:
0141 redirected:
0142 pr_info("ok: redirected stack return address.\n");
0143 break;
0144 }
0145
0146 pr_info("Attempting checked stack return address redirection ...\n");
0147
0148 switch (force_check) {
0149 case 0:
0150 set_return_addr(&&check_normal, &&check_redirected);
0151 fallthrough;
0152 case 1:
0153 check_normal:
0154
0155 if (!force_check) {
0156 pr_info("ok: control flow unchanged.\n");
0157 return;
0158 }
0159
0160 check_redirected:
0161 pr_err("FAIL: stack return address was redirected!\n");
0162 break;
0163 }
0164
0165 if (IS_ENABLED(CONFIG_ARM64_PTR_AUTH_KERNEL)) {
0166 pr_expected_config(CONFIG_ARM64_PTR_AUTH_KERNEL);
0167 return;
0168 }
0169 if (IS_ENABLED(CONFIG_SHADOW_CALL_STACK)) {
0170 pr_expected_config(CONFIG_SHADOW_CALL_STACK);
0171 return;
0172 }
0173 pr_warn("This is probably expected, since this %s was built *without* %s=y nor %s=y\n",
0174 lkdtm_kernel_info,
0175 "CONFIG_ARM64_PTR_AUTH_KERNEL", "CONFIG_SHADOW_CALL_STACK");
0176 }
0177
0178 static struct crashtype crashtypes[] = {
0179 CRASHTYPE(CFI_FORWARD_PROTO),
0180 CRASHTYPE(CFI_BACKWARD),
0181 };
0182
0183 struct crashtype_category cfi_crashtypes = {
0184 .crashtypes = crashtypes,
0185 .len = ARRAY_SIZE(crashtypes),
0186 };