~ [ 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-5.16.20)


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

~ [ 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