GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / misc / lkdtm / cfi.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * This is for all the tests relating directly to Control Flow Integrity.
4  */
5 #include "lkdtm.h"
6 #include <asm/page.h>
7
8 static int called_count;
9
10 /* Function taking one argument, without a return value. */
11 static noinline void lkdtm_increment_void(int *counter)
12 {
13         (*counter)++;
14 }
15
16 /* Function taking one argument, returning int. */
17 static noinline int lkdtm_increment_int(int *counter)
18 {
19         (*counter)++;
20
21         return *counter;
22 }
23 /*
24  * This tries to call an indirect function with a mismatched prototype.
25  */
26 static void lkdtm_CFI_FORWARD_PROTO(void)
27 {
28         /*
29          * Matches lkdtm_increment_void()'s prototype, but not
30          * lkdtm_increment_int()'s prototype.
31          */
32         void (*func)(int *);
33
34         pr_info("Calling matched prototype ...\n");
35         func = lkdtm_increment_void;
36         func(&called_count);
37
38         pr_info("Calling mismatched prototype ...\n");
39         func = (void *)lkdtm_increment_int;
40         func(&called_count);
41
42         pr_err("FAIL: survived mismatched prototype function call!\n");
43         pr_expected_config(CONFIG_CFI_CLANG);
44 }
45
46 /*
47  * This can stay local to LKDTM, as there should not be a production reason
48  * to disable PAC && SCS.
49  */
50 #ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
51 # ifdef CONFIG_ARM64_BTI_KERNEL
52 #  define __no_pac             "branch-protection=bti"
53 # else
54 #  define __no_pac             "branch-protection=none"
55 # endif
56 # define __no_ret_protection   __noscs __attribute__((__target__(__no_pac)))
57 #else
58 # define __no_ret_protection   __noscs
59 #endif
60
61 #define no_pac_addr(addr)      \
62         ((__force __typeof__(addr))((uintptr_t)(addr) | PAGE_OFFSET))
63
64 /* The ultimate ROP gadget. */
65 static noinline __no_ret_protection
66 void set_return_addr_unchecked(unsigned long *expected, unsigned long *addr)
67 {
68         /* Use of volatile is to make sure final write isn't seen as a dead store. */
69         unsigned long * volatile *ret_addr = (unsigned long **)__builtin_frame_address(0) + 1;
70
71         /* Make sure we've found the right place on the stack before writing it. */
72         if (no_pac_addr(*ret_addr) == expected)
73                 *ret_addr = (addr);
74         else
75                 /* Check architecture, stack layout, or compiler behavior... */
76                 pr_warn("Eek: return address mismatch! %px != %px\n",
77                         *ret_addr, addr);
78 }
79
80 static noinline
81 void set_return_addr(unsigned long *expected, unsigned long *addr)
82 {
83         /* Use of volatile is to make sure final write isn't seen as a dead store. */
84         unsigned long * volatile *ret_addr = (unsigned long **)__builtin_frame_address(0) + 1;
85
86         /* Make sure we've found the right place on the stack before writing it. */
87         if (no_pac_addr(*ret_addr) == expected)
88                 *ret_addr = (addr);
89         else
90                 /* Check architecture, stack layout, or compiler behavior... */
91                 pr_warn("Eek: return address mismatch! %px != %px\n",
92                         *ret_addr, addr);
93 }
94
95 static volatile int force_check;
96
97 static void lkdtm_CFI_BACKWARD(void)
98 {
99         /* Use calculated gotos to keep labels addressable. */
100         void *labels[] = {0, &&normal, &&redirected, &&check_normal, &&check_redirected};
101
102         pr_info("Attempting unchecked stack return address redirection ...\n");
103
104         /* Always false */
105         if (force_check) {
106                 /*
107                  * Prepare to call with NULLs to avoid parameters being treated as
108                  * constants in -02.
109                  */
110                 set_return_addr_unchecked(NULL, NULL);
111                 set_return_addr(NULL, NULL);
112                 if (force_check)
113                         goto *labels[1];
114                 if (force_check)
115                         goto *labels[2];
116                 if (force_check)
117                         goto *labels[3];
118                 if (force_check)
119                         goto *labels[4];
120                 return;
121         }
122
123         /*
124          * Use fallthrough switch case to keep basic block ordering between
125          * set_return_addr*() and the label after it.
126          */
127         switch (force_check) {
128         case 0:
129                 set_return_addr_unchecked(&&normal, &&redirected);
130                 fallthrough;
131         case 1:
132 normal:
133                 /* Always true */
134                 if (!force_check) {
135                         pr_err("FAIL: stack return address manipulation failed!\n");
136                         /* If we can't redirect "normally", we can't test mitigations. */
137                         return;
138                 }
139                 break;
140         default:
141 redirected:
142                 pr_info("ok: redirected stack return address.\n");
143                 break;
144         }
145
146         pr_info("Attempting checked stack return address redirection ...\n");
147
148         switch (force_check) {
149         case 0:
150                 set_return_addr(&&check_normal, &&check_redirected);
151                 fallthrough;
152         case 1:
153 check_normal:
154                 /* Always true */
155                 if (!force_check) {
156                         pr_info("ok: control flow unchanged.\n");
157                         return;
158                 }
159
160 check_redirected:
161                 pr_err("FAIL: stack return address was redirected!\n");
162                 break;
163         }
164
165         if (IS_ENABLED(CONFIG_ARM64_PTR_AUTH_KERNEL)) {
166                 pr_expected_config(CONFIG_ARM64_PTR_AUTH_KERNEL);
167                 return;
168         }
169         if (IS_ENABLED(CONFIG_SHADOW_CALL_STACK)) {
170                 pr_expected_config(CONFIG_SHADOW_CALL_STACK);
171                 return;
172         }
173         pr_warn("This is probably expected, since this %s was built *without* %s=y nor %s=y\n",
174                 lkdtm_kernel_info,
175                 "CONFIG_ARM64_PTR_AUTH_KERNEL", "CONFIG_SHADOW_CALL_STACK");
176 }
177
178 static struct crashtype crashtypes[] = {
179         CRASHTYPE(CFI_FORWARD_PROTO),
180         CRASHTYPE(CFI_BACKWARD),
181 };
182
183 struct crashtype_category cfi_crashtypes = {
184         .crashtypes = crashtypes,
185         .len        = ARRAY_SIZE(crashtypes),
186 };