~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/kernel/scs.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /kernel/scs.c (Version linux-6.12-rc7) and /kernel/scs.c (Version linux-6.2.16)


  1 // SPDX-License-Identifier: GPL-2.0                 1 // SPDX-License-Identifier: GPL-2.0
  2 /*                                                  2 /*
  3  * Shadow Call Stack support.                       3  * Shadow Call Stack support.
  4  *                                                  4  *
  5  * Copyright (C) 2019 Google LLC                    5  * Copyright (C) 2019 Google LLC
  6  */                                                 6  */
  7                                                     7 
  8 #include <linux/cpuhotplug.h>                       8 #include <linux/cpuhotplug.h>
  9 #include <linux/kasan.h>                            9 #include <linux/kasan.h>
 10 #include <linux/mm.h>                              10 #include <linux/mm.h>
 11 #include <linux/scs.h>                             11 #include <linux/scs.h>
 12 #include <linux/vmalloc.h>                         12 #include <linux/vmalloc.h>
 13 #include <linux/vmstat.h>                          13 #include <linux/vmstat.h>
 14                                                    14 
 15 #ifdef CONFIG_DYNAMIC_SCS                          15 #ifdef CONFIG_DYNAMIC_SCS
 16 DEFINE_STATIC_KEY_FALSE(dynamic_scs_enabled);      16 DEFINE_STATIC_KEY_FALSE(dynamic_scs_enabled);
 17 #endif                                             17 #endif
 18                                                    18 
 19 static void __scs_account(void *s, int account     19 static void __scs_account(void *s, int account)
 20 {                                                  20 {
 21         struct page *scs_page = vmalloc_to_pag     21         struct page *scs_page = vmalloc_to_page(s);
 22                                                    22 
 23         mod_node_page_state(page_pgdat(scs_pag     23         mod_node_page_state(page_pgdat(scs_page), NR_KERNEL_SCS_KB,
 24                             account * (SCS_SIZ     24                             account * (SCS_SIZE / SZ_1K));
 25 }                                                  25 }
 26                                                    26 
 27 /* Matches NR_CACHED_STACKS for VMAP_STACK */      27 /* Matches NR_CACHED_STACKS for VMAP_STACK */
 28 #define NR_CACHED_SCS 2                            28 #define NR_CACHED_SCS 2
 29 static DEFINE_PER_CPU(void *, scs_cache[NR_CAC     29 static DEFINE_PER_CPU(void *, scs_cache[NR_CACHED_SCS]);
 30                                                    30 
 31 static void *__scs_alloc(int node)                 31 static void *__scs_alloc(int node)
 32 {                                                  32 {
 33         int i;                                     33         int i;
 34         void *s;                                   34         void *s;
 35                                                    35 
 36         for (i = 0; i < NR_CACHED_SCS; i++) {      36         for (i = 0; i < NR_CACHED_SCS; i++) {
 37                 s = this_cpu_xchg(scs_cache[i]     37                 s = this_cpu_xchg(scs_cache[i], NULL);
 38                 if (s) {                           38                 if (s) {
 39                         s = kasan_unpoison_vma     39                         s = kasan_unpoison_vmalloc(s, SCS_SIZE,
 40                                                    40                                                    KASAN_VMALLOC_PROT_NORMAL);
 41                         memset(s, 0, SCS_SIZE)     41                         memset(s, 0, SCS_SIZE);
 42                         goto out;                  42                         goto out;
 43                 }                                  43                 }
 44         }                                          44         }
 45                                                    45 
 46         s = __vmalloc_node_range(SCS_SIZE, 1,      46         s = __vmalloc_node_range(SCS_SIZE, 1, VMALLOC_START, VMALLOC_END,
 47                                     GFP_SCS, P     47                                     GFP_SCS, PAGE_KERNEL, 0, node,
 48                                     __builtin_     48                                     __builtin_return_address(0));
 49                                                    49 
 50 out:                                               50 out:
 51         return kasan_reset_tag(s);                 51         return kasan_reset_tag(s);
 52 }                                                  52 }
 53                                                    53 
 54 void *scs_alloc(int node)                          54 void *scs_alloc(int node)
 55 {                                                  55 {
 56         void *s;                                   56         void *s;
 57                                                    57 
 58         s = __scs_alloc(node);                     58         s = __scs_alloc(node);
 59         if (!s)                                    59         if (!s)
 60                 return NULL;                       60                 return NULL;
 61                                                    61 
 62         *__scs_magic(s) = SCS_END_MAGIC;           62         *__scs_magic(s) = SCS_END_MAGIC;
 63                                                    63 
 64         /*                                         64         /*
 65          * Poison the allocation to catch unin     65          * Poison the allocation to catch unintentional accesses to
 66          * the shadow stack when KASAN is enab     66          * the shadow stack when KASAN is enabled.
 67          */                                        67          */
 68         kasan_poison_vmalloc(s, SCS_SIZE);         68         kasan_poison_vmalloc(s, SCS_SIZE);
 69         __scs_account(s, 1);                       69         __scs_account(s, 1);
 70         return s;                                  70         return s;
 71 }                                                  71 }
 72                                                    72 
 73 void scs_free(void *s)                             73 void scs_free(void *s)
 74 {                                                  74 {
 75         int i;                                     75         int i;
 76                                                    76 
 77         __scs_account(s, -1);                      77         __scs_account(s, -1);
 78                                                    78 
 79         /*                                         79         /*
 80          * We cannot sleep as this can be call     80          * We cannot sleep as this can be called in interrupt context,
 81          * so use this_cpu_cmpxchg to update t     81          * so use this_cpu_cmpxchg to update the cache, and vfree_atomic
 82          * to free the stack.                      82          * to free the stack.
 83          */                                        83          */
 84                                                    84 
 85         for (i = 0; i < NR_CACHED_SCS; i++)        85         for (i = 0; i < NR_CACHED_SCS; i++)
 86                 if (this_cpu_cmpxchg(scs_cache     86                 if (this_cpu_cmpxchg(scs_cache[i], 0, s) == NULL)
 87                         return;                    87                         return;
 88                                                    88 
 89         kasan_unpoison_vmalloc(s, SCS_SIZE, KA     89         kasan_unpoison_vmalloc(s, SCS_SIZE, KASAN_VMALLOC_PROT_NORMAL);
 90         vfree_atomic(s);                           90         vfree_atomic(s);
 91 }                                                  91 }
 92                                                    92 
 93 static int scs_cleanup(unsigned int cpu)           93 static int scs_cleanup(unsigned int cpu)
 94 {                                                  94 {
 95         int i;                                     95         int i;
 96         void **cache = per_cpu_ptr(scs_cache,      96         void **cache = per_cpu_ptr(scs_cache, cpu);
 97                                                    97 
 98         for (i = 0; i < NR_CACHED_SCS; i++) {      98         for (i = 0; i < NR_CACHED_SCS; i++) {
 99                 vfree(cache[i]);                   99                 vfree(cache[i]);
100                 cache[i] = NULL;                  100                 cache[i] = NULL;
101         }                                         101         }
102                                                   102 
103         return 0;                                 103         return 0;
104 }                                                 104 }
105                                                   105 
106 void __init scs_init(void)                        106 void __init scs_init(void)
107 {                                                 107 {
108         if (!scs_is_enabled())                    108         if (!scs_is_enabled())
109                 return;                           109                 return;
110         cpuhp_setup_state(CPUHP_BP_PREPARE_DYN    110         cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "scs:scs_cache", NULL,
111                           scs_cleanup);           111                           scs_cleanup);
112 }                                                 112 }
113                                                   113 
114 int scs_prepare(struct task_struct *tsk, int n    114 int scs_prepare(struct task_struct *tsk, int node)
115 {                                                 115 {
116         void *s;                                  116         void *s;
117                                                   117 
118         if (!scs_is_enabled())                    118         if (!scs_is_enabled())
119                 return 0;                         119                 return 0;
120                                                   120 
121         s = scs_alloc(node);                      121         s = scs_alloc(node);
122         if (!s)                                   122         if (!s)
123                 return -ENOMEM;                   123                 return -ENOMEM;
124                                                   124 
125         task_scs(tsk) = task_scs_sp(tsk) = s;     125         task_scs(tsk) = task_scs_sp(tsk) = s;
126         return 0;                                 126         return 0;
127 }                                                 127 }
128                                                   128 
129 static void scs_check_usage(struct task_struct    129 static void scs_check_usage(struct task_struct *tsk)
130 {                                                 130 {
131         static unsigned long highest;             131         static unsigned long highest;
132                                                   132 
133         unsigned long *p, prev, curr = highest    133         unsigned long *p, prev, curr = highest, used = 0;
134                                                   134 
135         if (!IS_ENABLED(CONFIG_DEBUG_STACK_USA    135         if (!IS_ENABLED(CONFIG_DEBUG_STACK_USAGE))
136                 return;                           136                 return;
137                                                   137 
138         for (p = task_scs(tsk); p < __scs_magi    138         for (p = task_scs(tsk); p < __scs_magic(tsk); ++p) {
139                 if (!READ_ONCE_NOCHECK(*p))       139                 if (!READ_ONCE_NOCHECK(*p))
140                         break;                    140                         break;
141                 used += sizeof(*p);               141                 used += sizeof(*p);
142         }                                         142         }
143                                                   143 
144         while (used > curr) {                     144         while (used > curr) {
145                 prev = cmpxchg_relaxed(&highes    145                 prev = cmpxchg_relaxed(&highest, curr, used);
146                                                   146 
147                 if (prev == curr) {               147                 if (prev == curr) {
148                         pr_info("%s (%d): high    148                         pr_info("%s (%d): highest shadow stack usage: %lu bytes\n",
149                                 tsk->comm, tas    149                                 tsk->comm, task_pid_nr(tsk), used);
150                         break;                    150                         break;
151                 }                                 151                 }
152                                                   152 
153                 curr = prev;                      153                 curr = prev;
154         }                                         154         }
155 }                                                 155 }
156                                                   156 
157 void scs_release(struct task_struct *tsk)         157 void scs_release(struct task_struct *tsk)
158 {                                                 158 {
159         void *s = task_scs(tsk);                  159         void *s = task_scs(tsk);
160                                                   160 
161         if (!scs_is_enabled() || !s)              161         if (!scs_is_enabled() || !s)
162                 return;                           162                 return;
163                                                   163 
164         WARN(task_scs_end_corrupted(tsk),         164         WARN(task_scs_end_corrupted(tsk),
165              "corrupted shadow stack detected     165              "corrupted shadow stack detected when freeing task\n");
166         scs_check_usage(tsk);                     166         scs_check_usage(tsk);
167         scs_free(s);                              167         scs_free(s);
168 }                                                 168 }
169                                                   169 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php