1 /*
2 * Copyright (c) 2025 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 /**
7 * @file
8 * @brief Indirect Branch Tracking
9 *
10 * Indirect Branch Tracking (IBT) setup routines.
11 */
12
13 #include <zephyr/kernel.h>
14 #include <zephyr/arch/x86/msr.h>
15 #include <zephyr/arch/x86/cet.h>
16 #include <zephyr/logging/log_ctrl.h>
17 #include <zephyr/logging/log.h>
18
19 #include <kernel_arch_data.h>
20 LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
21
22 #ifdef CONFIG_X86_64
23 #define TOKEN_OFFSET 5
24 #else
25 #define TOKEN_OFFSET 4
26 #endif
27
28 #ifdef CONFIG_HW_SHADOW_STACK
29 #ifdef CONFIG_HW_SHADOW_STACK_ALLOW_REUSE
30 extern void arch_shadow_stack_reset(k_tid_t thread);
31 #endif /* CONFIG_HW_SHADOW_STACK_ALLOW_REUSE */
32
arch_thread_hw_shadow_stack_attach(k_tid_t thread,arch_thread_hw_shadow_stack_t * stack,size_t stack_size)33 int arch_thread_hw_shadow_stack_attach(k_tid_t thread,
34 arch_thread_hw_shadow_stack_t *stack,
35 size_t stack_size)
36 {
37 /* Can't attach to NULL */
38 if (stack == NULL) {
39 LOG_ERR("Can't set NULL shadow stack for thread %p\n", thread);
40 return -EINVAL;
41 }
42
43 /* Or if the thread already has a shadow stack. */
44 if (thread->arch.shstk_addr != NULL) {
45 #ifdef CONFIG_HW_SHADOW_STACK_ALLOW_REUSE
46 /* Allow reuse of the shadow stack if the base and size are the same */
47 if (thread->arch.shstk_base == stack &&
48 thread->arch.shstk_size == stack_size) {
49 unsigned int key;
50
51 key = arch_irq_lock();
52 arch_shadow_stack_reset(thread);
53 arch_irq_unlock(key);
54
55 return 0;
56 }
57 #endif
58 LOG_ERR("Shadow stack already set up for thread %p\n", thread);
59 return -EINVAL;
60 }
61
62 thread->arch.shstk_addr = stack + (stack_size -
63 TOKEN_OFFSET * sizeof(*stack)) / sizeof(*stack);
64 thread->arch.shstk_size = stack_size;
65 thread->arch.shstk_base = stack;
66
67 return 0;
68 }
69 #endif
70
z_x86_cet_enable(void)71 void z_x86_cet_enable(void)
72 {
73 #ifdef CONFIG_X86_64
74 __asm volatile (
75 "movq %cr4, %rax\n\t"
76 "orq $0x800000, %rax\n\t"
77 "movq %rax, %cr4\n\t"
78 );
79 #else
80 __asm volatile (
81 "movl %cr4, %eax\n\t"
82 "orl $0x800000, %eax\n\t"
83 "movl %eax, %cr4\n\t"
84 );
85 #endif
86 }
87
88 #ifdef CONFIG_X86_CET_IBT
z_x86_ibt_enable(void)89 void z_x86_ibt_enable(void)
90 {
91 uint64_t msr = z_x86_msr_read(X86_S_CET_MSR);
92
93 msr |= X86_S_CET_MSR_ENDBR | X86_S_CET_MSR_NO_TRACK;
94 z_x86_msr_write(X86_S_CET_MSR, msr);
95 }
96 #endif
97
98 #ifdef CONFIG_X86_CET_VERIFY_KERNEL_SHADOW_STACK
z_x86_cet_shadow_stack_panic(k_tid_t * thread)99 void z_x86_cet_shadow_stack_panic(k_tid_t *thread)
100 {
101 LOG_ERR("Shadow stack enabled, but outgoing thread [%p] struct "
102 "missing shadow stack pointer", thread);
103
104 k_panic();
105 }
106 #endif
107