Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * This is for all the tests relating directly to Control Flow Integrity.
0004  */
0005 #include "lkdtm.h"
0006 #include <asm/page.h>
0007 
0008 static int called_count;
0009 
0010 /* Function taking one argument, without a return value. */
0011 static noinline void lkdtm_increment_void(int *counter)
0012 {
0013     (*counter)++;
0014 }
0015 
0016 /* Function taking one argument, returning int. */
0017 static noinline int lkdtm_increment_int(int *counter)
0018 {
0019     (*counter)++;
0020 
0021     return *counter;
0022 }
0023 /*
0024  * This tries to call an indirect function with a mismatched prototype.
0025  */
0026 static void lkdtm_CFI_FORWARD_PROTO(void)
0027 {
0028     /*
0029      * Matches lkdtm_increment_void()'s prototype, but not
0030      * lkdtm_increment_int()'s prototype.
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  * This can stay local to LKDTM, as there should not be a production reason
0048  * to disable PAC && SCS.
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 /* The ultimate ROP gadget. */
0065 static noinline __no_ret_protection
0066 void set_return_addr_unchecked(unsigned long *expected, unsigned long *addr)
0067 {
0068     /* Use of volatile is to make sure final write isn't seen as a dead store. */
0069     unsigned long * volatile *ret_addr = (unsigned long **)__builtin_frame_address(0) + 1;
0070 
0071     /* Make sure we've found the right place on the stack before writing it. */
0072     if (no_pac_addr(*ret_addr) == expected)
0073         *ret_addr = (addr);
0074     else
0075         /* Check architecture, stack layout, or compiler behavior... */
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     /* Use of volatile is to make sure final write isn't seen as a dead store. */
0084     unsigned long * volatile *ret_addr = (unsigned long **)__builtin_frame_address(0) + 1;
0085 
0086     /* Make sure we've found the right place on the stack before writing it. */
0087     if (no_pac_addr(*ret_addr) == expected)
0088         *ret_addr = (addr);
0089     else
0090         /* Check architecture, stack layout, or compiler behavior... */
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     /* Use calculated gotos to keep labels addressable. */
0100     void *labels[] = { NULL, &&normal, &&redirected, &&check_normal, &&check_redirected };
0101 
0102     pr_info("Attempting unchecked stack return address redirection ...\n");
0103 
0104     /* Always false */
0105     if (force_check) {
0106         /*
0107          * Prepare to call with NULLs to avoid parameters being treated as
0108          * constants in -02.
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      * Use fallthrough switch case to keep basic block ordering between
0125      * set_return_addr*() and the label after it.
0126      */
0127     switch (force_check) {
0128     case 0:
0129         set_return_addr_unchecked(&&normal, &&redirected);
0130         fallthrough;
0131     case 1:
0132 normal:
0133         /* Always true */
0134         if (!force_check) {
0135             pr_err("FAIL: stack return address manipulation failed!\n");
0136             /* If we can't redirect "normally", we can't test mitigations. */
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         /* Always true */
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 };