arm64: mte: Add asynchronous mode support
[linux-2.6-microblaze.git] / arch / arm64 / kernel / mte.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2020 ARM Ltd.
4  */
5
6 #include <linux/bitops.h>
7 #include <linux/kernel.h>
8 #include <linux/mm.h>
9 #include <linux/prctl.h>
10 #include <linux/sched.h>
11 #include <linux/sched/mm.h>
12 #include <linux/string.h>
13 #include <linux/swap.h>
14 #include <linux/swapops.h>
15 #include <linux/thread_info.h>
16 #include <linux/types.h>
17 #include <linux/uio.h>
18
19 #include <asm/barrier.h>
20 #include <asm/cpufeature.h>
21 #include <asm/mte.h>
22 #include <asm/ptrace.h>
23 #include <asm/sysreg.h>
24
25 u64 gcr_kernel_excl __ro_after_init;
26
27 static bool report_fault_once = true;
28
29 static void mte_sync_page_tags(struct page *page, pte_t *ptep, bool check_swap)
30 {
31         pte_t old_pte = READ_ONCE(*ptep);
32
33         if (check_swap && is_swap_pte(old_pte)) {
34                 swp_entry_t entry = pte_to_swp_entry(old_pte);
35
36                 if (!non_swap_entry(entry) && mte_restore_tags(entry, page))
37                         return;
38         }
39
40         page_kasan_tag_reset(page);
41         /*
42          * We need smp_wmb() in between setting the flags and clearing the
43          * tags because if another thread reads page->flags and builds a
44          * tagged address out of it, there is an actual dependency to the
45          * memory access, but on the current thread we do not guarantee that
46          * the new page->flags are visible before the tags were updated.
47          */
48         smp_wmb();
49         mte_clear_page_tags(page_address(page));
50 }
51
52 void mte_sync_tags(pte_t *ptep, pte_t pte)
53 {
54         struct page *page = pte_page(pte);
55         long i, nr_pages = compound_nr(page);
56         bool check_swap = nr_pages == 1;
57
58         /* if PG_mte_tagged is set, tags have already been initialised */
59         for (i = 0; i < nr_pages; i++, page++) {
60                 if (!test_and_set_bit(PG_mte_tagged, &page->flags))
61                         mte_sync_page_tags(page, ptep, check_swap);
62         }
63 }
64
65 int memcmp_pages(struct page *page1, struct page *page2)
66 {
67         char *addr1, *addr2;
68         int ret;
69
70         addr1 = page_address(page1);
71         addr2 = page_address(page2);
72         ret = memcmp(addr1, addr2, PAGE_SIZE);
73
74         if (!system_supports_mte() || ret)
75                 return ret;
76
77         /*
78          * If the page content is identical but at least one of the pages is
79          * tagged, return non-zero to avoid KSM merging. If only one of the
80          * pages is tagged, set_pte_at() may zero or change the tags of the
81          * other page via mte_sync_tags().
82          */
83         if (test_bit(PG_mte_tagged, &page1->flags) ||
84             test_bit(PG_mte_tagged, &page2->flags))
85                 return addr1 != addr2;
86
87         return ret;
88 }
89
90 void mte_init_tags(u64 max_tag)
91 {
92         static bool gcr_kernel_excl_initialized;
93
94         if (!gcr_kernel_excl_initialized) {
95                 /*
96                  * The format of the tags in KASAN is 0xFF and in MTE is 0xF.
97                  * This conversion extracts an MTE tag from a KASAN tag.
98                  */
99                 u64 incl = GENMASK(FIELD_GET(MTE_TAG_MASK >> MTE_TAG_SHIFT,
100                                              max_tag), 0);
101
102                 gcr_kernel_excl = ~incl & SYS_GCR_EL1_EXCL_MASK;
103                 gcr_kernel_excl_initialized = true;
104         }
105
106         /* Enable the kernel exclude mask for random tags generation. */
107         write_sysreg_s(SYS_GCR_EL1_RRND | gcr_kernel_excl, SYS_GCR_EL1);
108 }
109
110 static inline void __mte_enable_kernel(const char *mode, unsigned long tcf)
111 {
112         /* Enable MTE Sync Mode for EL1. */
113         sysreg_clear_set(sctlr_el1, SCTLR_ELx_TCF_MASK, tcf);
114         isb();
115
116         pr_info_once("MTE: enabled in %s mode at EL1\n", mode);
117 }
118
119 void mte_enable_kernel_sync(void)
120 {
121         __mte_enable_kernel("synchronous", SCTLR_ELx_TCF_SYNC);
122 }
123
124 void mte_enable_kernel_async(void)
125 {
126         __mte_enable_kernel("asynchronous", SCTLR_ELx_TCF_ASYNC);
127 }
128
129 void mte_set_report_once(bool state)
130 {
131         WRITE_ONCE(report_fault_once, state);
132 }
133
134 bool mte_report_once(void)
135 {
136         return READ_ONCE(report_fault_once);
137 }
138
139 static void update_sctlr_el1_tcf0(u64 tcf0)
140 {
141         /* ISB required for the kernel uaccess routines */
142         sysreg_clear_set(sctlr_el1, SCTLR_EL1_TCF0_MASK, tcf0);
143         isb();
144 }
145
146 static void set_sctlr_el1_tcf0(u64 tcf0)
147 {
148         /*
149          * mte_thread_switch() checks current->thread.sctlr_tcf0 as an
150          * optimisation. Disable preemption so that it does not see
151          * the variable update before the SCTLR_EL1.TCF0 one.
152          */
153         preempt_disable();
154         current->thread.sctlr_tcf0 = tcf0;
155         update_sctlr_el1_tcf0(tcf0);
156         preempt_enable();
157 }
158
159 static void update_gcr_el1_excl(u64 excl)
160 {
161
162         /*
163          * Note that the mask controlled by the user via prctl() is an
164          * include while GCR_EL1 accepts an exclude mask.
165          * No need for ISB since this only affects EL0 currently, implicit
166          * with ERET.
167          */
168         sysreg_clear_set_s(SYS_GCR_EL1, SYS_GCR_EL1_EXCL_MASK, excl);
169 }
170
171 static void set_gcr_el1_excl(u64 excl)
172 {
173         current->thread.gcr_user_excl = excl;
174
175         /*
176          * SYS_GCR_EL1 will be set to current->thread.gcr_user_excl value
177          * by mte_set_user_gcr() in kernel_exit,
178          */
179 }
180
181 void flush_mte_state(void)
182 {
183         if (!system_supports_mte())
184                 return;
185
186         /* clear any pending asynchronous tag fault */
187         dsb(ish);
188         write_sysreg_s(0, SYS_TFSRE0_EL1);
189         clear_thread_flag(TIF_MTE_ASYNC_FAULT);
190         /* disable tag checking */
191         set_sctlr_el1_tcf0(SCTLR_EL1_TCF0_NONE);
192         /* reset tag generation mask */
193         set_gcr_el1_excl(SYS_GCR_EL1_EXCL_MASK);
194 }
195
196 void mte_thread_switch(struct task_struct *next)
197 {
198         if (!system_supports_mte())
199                 return;
200
201         /* avoid expensive SCTLR_EL1 accesses if no change */
202         if (current->thread.sctlr_tcf0 != next->thread.sctlr_tcf0)
203                 update_sctlr_el1_tcf0(next->thread.sctlr_tcf0);
204 }
205
206 void mte_suspend_exit(void)
207 {
208         if (!system_supports_mte())
209                 return;
210
211         update_gcr_el1_excl(gcr_kernel_excl);
212 }
213
214 long set_mte_ctrl(struct task_struct *task, unsigned long arg)
215 {
216         u64 tcf0;
217         u64 gcr_excl = ~((arg & PR_MTE_TAG_MASK) >> PR_MTE_TAG_SHIFT) &
218                        SYS_GCR_EL1_EXCL_MASK;
219
220         if (!system_supports_mte())
221                 return 0;
222
223         switch (arg & PR_MTE_TCF_MASK) {
224         case PR_MTE_TCF_NONE:
225                 tcf0 = SCTLR_EL1_TCF0_NONE;
226                 break;
227         case PR_MTE_TCF_SYNC:
228                 tcf0 = SCTLR_EL1_TCF0_SYNC;
229                 break;
230         case PR_MTE_TCF_ASYNC:
231                 tcf0 = SCTLR_EL1_TCF0_ASYNC;
232                 break;
233         default:
234                 return -EINVAL;
235         }
236
237         if (task != current) {
238                 task->thread.sctlr_tcf0 = tcf0;
239                 task->thread.gcr_user_excl = gcr_excl;
240         } else {
241                 set_sctlr_el1_tcf0(tcf0);
242                 set_gcr_el1_excl(gcr_excl);
243         }
244
245         return 0;
246 }
247
248 long get_mte_ctrl(struct task_struct *task)
249 {
250         unsigned long ret;
251         u64 incl = ~task->thread.gcr_user_excl & SYS_GCR_EL1_EXCL_MASK;
252
253         if (!system_supports_mte())
254                 return 0;
255
256         ret = incl << PR_MTE_TAG_SHIFT;
257
258         switch (task->thread.sctlr_tcf0) {
259         case SCTLR_EL1_TCF0_NONE:
260                 ret |= PR_MTE_TCF_NONE;
261                 break;
262         case SCTLR_EL1_TCF0_SYNC:
263                 ret |= PR_MTE_TCF_SYNC;
264                 break;
265         case SCTLR_EL1_TCF0_ASYNC:
266                 ret |= PR_MTE_TCF_ASYNC;
267                 break;
268         }
269
270         return ret;
271 }
272
273 /*
274  * Access MTE tags in another process' address space as given in mm. Update
275  * the number of tags copied. Return 0 if any tags copied, error otherwise.
276  * Inspired by __access_remote_vm().
277  */
278 static int __access_remote_tags(struct mm_struct *mm, unsigned long addr,
279                                 struct iovec *kiov, unsigned int gup_flags)
280 {
281         struct vm_area_struct *vma;
282         void __user *buf = kiov->iov_base;
283         size_t len = kiov->iov_len;
284         int ret;
285         int write = gup_flags & FOLL_WRITE;
286
287         if (!access_ok(buf, len))
288                 return -EFAULT;
289
290         if (mmap_read_lock_killable(mm))
291                 return -EIO;
292
293         while (len) {
294                 unsigned long tags, offset;
295                 void *maddr;
296                 struct page *page = NULL;
297
298                 ret = get_user_pages_remote(mm, addr, 1, gup_flags, &page,
299                                             &vma, NULL);
300                 if (ret <= 0)
301                         break;
302
303                 /*
304                  * Only copy tags if the page has been mapped as PROT_MTE
305                  * (PG_mte_tagged set). Otherwise the tags are not valid and
306                  * not accessible to user. Moreover, an mprotect(PROT_MTE)
307                  * would cause the existing tags to be cleared if the page
308                  * was never mapped with PROT_MTE.
309                  */
310                 if (!(vma->vm_flags & VM_MTE)) {
311                         ret = -EOPNOTSUPP;
312                         put_page(page);
313                         break;
314                 }
315                 WARN_ON_ONCE(!test_bit(PG_mte_tagged, &page->flags));
316
317                 /* limit access to the end of the page */
318                 offset = offset_in_page(addr);
319                 tags = min(len, (PAGE_SIZE - offset) / MTE_GRANULE_SIZE);
320
321                 maddr = page_address(page);
322                 if (write) {
323                         tags = mte_copy_tags_from_user(maddr + offset, buf, tags);
324                         set_page_dirty_lock(page);
325                 } else {
326                         tags = mte_copy_tags_to_user(buf, maddr + offset, tags);
327                 }
328                 put_page(page);
329
330                 /* error accessing the tracer's buffer */
331                 if (!tags)
332                         break;
333
334                 len -= tags;
335                 buf += tags;
336                 addr += tags * MTE_GRANULE_SIZE;
337         }
338         mmap_read_unlock(mm);
339
340         /* return an error if no tags copied */
341         kiov->iov_len = buf - kiov->iov_base;
342         if (!kiov->iov_len) {
343                 /* check for error accessing the tracee's address space */
344                 if (ret <= 0)
345                         return -EIO;
346                 else
347                         return -EFAULT;
348         }
349
350         return 0;
351 }
352
353 /*
354  * Copy MTE tags in another process' address space at 'addr' to/from tracer's
355  * iovec buffer. Return 0 on success. Inspired by ptrace_access_vm().
356  */
357 static int access_remote_tags(struct task_struct *tsk, unsigned long addr,
358                               struct iovec *kiov, unsigned int gup_flags)
359 {
360         struct mm_struct *mm;
361         int ret;
362
363         mm = get_task_mm(tsk);
364         if (!mm)
365                 return -EPERM;
366
367         if (!tsk->ptrace || (current != tsk->parent) ||
368             ((get_dumpable(mm) != SUID_DUMP_USER) &&
369              !ptracer_capable(tsk, mm->user_ns))) {
370                 mmput(mm);
371                 return -EPERM;
372         }
373
374         ret = __access_remote_tags(mm, addr, kiov, gup_flags);
375         mmput(mm);
376
377         return ret;
378 }
379
380 int mte_ptrace_copy_tags(struct task_struct *child, long request,
381                          unsigned long addr, unsigned long data)
382 {
383         int ret;
384         struct iovec kiov;
385         struct iovec __user *uiov = (void __user *)data;
386         unsigned int gup_flags = FOLL_FORCE;
387
388         if (!system_supports_mte())
389                 return -EIO;
390
391         if (get_user(kiov.iov_base, &uiov->iov_base) ||
392             get_user(kiov.iov_len, &uiov->iov_len))
393                 return -EFAULT;
394
395         if (request == PTRACE_POKEMTETAGS)
396                 gup_flags |= FOLL_WRITE;
397
398         /* align addr to the MTE tag granule */
399         addr &= MTE_GRANULE_MASK;
400
401         ret = access_remote_tags(child, addr, &kiov, gup_flags);
402         if (!ret)
403                 ret = put_user(kiov.iov_len, &uiov->iov_len);
404
405         return ret;
406 }