Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * mm/mprotect.c
4 : : *
5 : : * (C) Copyright 1994 Linus Torvalds
6 : : * (C) Copyright 2002 Christoph Hellwig
7 : : *
8 : : * Address space accounting code <alan@lxorguk.ukuu.org.uk>
9 : : * (C) Copyright 2002 Red Hat Inc, All Rights Reserved
10 : : */
11 : :
12 : : #include <linux/pagewalk.h>
13 : : #include <linux/hugetlb.h>
14 : : #include <linux/shm.h>
15 : : #include <linux/mman.h>
16 : : #include <linux/fs.h>
17 : : #include <linux/highmem.h>
18 : : #include <linux/security.h>
19 : : #include <linux/mempolicy.h>
20 : : #include <linux/personality.h>
21 : : #include <linux/syscalls.h>
22 : : #include <linux/swap.h>
23 : : #include <linux/swapops.h>
24 : : #include <linux/mmu_notifier.h>
25 : : #include <linux/migrate.h>
26 : : #include <linux/perf_event.h>
27 : : #include <linux/pkeys.h>
28 : : #include <linux/ksm.h>
29 : : #include <linux/uaccess.h>
30 : : #include <linux/mm_inline.h>
31 : : #include <asm/pgtable.h>
32 : : #include <asm/cacheflush.h>
33 : : #include <asm/mmu_context.h>
34 : : #include <asm/tlbflush.h>
35 : :
36 : : #include "internal.h"
37 : :
38 : 5738708 : static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
39 : : unsigned long addr, unsigned long end, pgprot_t newprot,
40 : : int dirty_accountable, int prot_numa)
41 : : {
42 : : pte_t *pte, oldpte;
43 : : spinlock_t *ptl;
44 : : unsigned long pages = 0;
45 : : int target_node = NUMA_NO_NODE;
46 : :
47 : : /*
48 : : * Can be called with only the mmap_sem for reading by
49 : : * prot_numa so we must check the pmd isn't constantly
50 : : * changing from under us from pmd_none to pmd_trans_huge
51 : : * and/or the other way around.
52 : : */
53 : : if (pmd_trans_unstable(pmd))
54 : : return 0;
55 : :
56 : : /*
57 : : * The pmd points to a regular pte so the pmd can't change
58 : : * from under us even if the mmap_sem is only hold for
59 : : * reading.
60 : : */
61 : 5738708 : pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
62 : :
63 : : /* Get target node for single threaded private VMAs */
64 [ - + # # : 5738740 : if (prot_numa && !(vma->vm_flags & VM_SHARED) &&
# # ]
65 : 0 : atomic_read(&vma->vm_mm->mm_users) == 1)
66 : : target_node = numa_node_id();
67 : :
68 : : flush_tlb_batched_pending(vma->vm_mm);
69 : : arch_enter_lazy_mmu_mode();
70 : : do {
71 : 47666208 : oldpte = *pte;
72 [ + + ]: 47666208 : if (pte_present(oldpte)) {
73 : : pte_t ptent;
74 [ - + # # ]: 5698324 : bool preserve_write = prot_numa && pte_write(oldpte);
75 : :
76 : : /*
77 : : * Avoid trapping faults against the zero or KSM
78 : : * pages. See similar comment in change_huge_pmd.
79 : : */
80 [ - + ]: 5698324 : if (prot_numa) {
81 : : struct page *page;
82 : :
83 : 0 : page = vm_normal_page(vma, addr, oldpte);
84 [ # # ]: 0 : if (!page || PageKsm(page))
85 : 0 : continue;
86 : :
87 : : /* Also skip shared copy-on-write pages */
88 [ # # # # ]: 0 : if (is_cow_mapping(vma->vm_flags) &&
89 : 0 : page_mapcount(page) != 1)
90 : 0 : continue;
91 : :
92 : : /*
93 : : * While migration can move some dirty pages,
94 : : * it cannot move them all from MIGRATE_ASYNC
95 : : * context.
96 : : */
97 [ # # # # ]: 0 : if (page_is_file_cache(page) && PageDirty(page))
98 : 0 : continue;
99 : :
100 : : /* Avoid TLB flush if possible */
101 : : if (pte_protnone(oldpte))
102 : : continue;
103 : :
104 : : /*
105 : : * Don't mess with PTEs if page is already on the node
106 : : * a single-threaded process is running on.
107 : : */
108 [ # # ]: 0 : if (target_node == page_to_nid(page))
109 : 0 : continue;
110 : : }
111 : :
112 : : oldpte = ptep_modify_prot_start(vma, addr, pte);
113 : : ptent = pte_modify(oldpte, newprot);
114 [ - + ]: 5698336 : if (preserve_write)
115 : : ptent = pte_mk_savedwrite(ptent);
116 : :
117 : : /* Avoid taking write faults for known dirty pages */
118 [ - + # # ]: 5698336 : if (dirty_accountable && pte_dirty(ptent) &&
119 : : (pte_soft_dirty(ptent) ||
120 : : !(vma->vm_flags & VM_SOFTDIRTY))) {
121 : : ptent = pte_mkwrite(ptent);
122 : : }
123 : : ptep_modify_prot_commit(vma, addr, pte, oldpte, ptent);
124 : 5698294 : pages++;
125 : : } else if (IS_ENABLED(CONFIG_MIGRATION)) {
126 : : swp_entry_t entry = pte_to_swp_entry(oldpte);
127 : :
128 [ - + ]: 41967884 : if (is_write_migration_entry(entry)) {
129 : : pte_t newpte;
130 : : /*
131 : : * A protection check is difficult so
132 : : * just be safe and disable write
133 : : */
134 : : make_migration_entry_read(&entry);
135 : : newpte = swp_entry_to_pte(entry);
136 : : if (pte_swp_soft_dirty(oldpte))
137 : : newpte = pte_swp_mksoft_dirty(newpte);
138 : 0 : set_pte_at(vma->vm_mm, addr, pte, newpte);
139 : :
140 : 0 : pages++;
141 : : }
142 : :
143 : : if (is_write_device_private_entry(entry)) {
144 : : pte_t newpte;
145 : :
146 : : /*
147 : : * We do not preserve soft-dirtiness. See
148 : : * copy_one_pte() for explanation.
149 : : */
150 : : make_device_private_entry_read(&entry);
151 : : newpte = swp_entry_to_pte(entry);
152 : : set_pte_at(vma->vm_mm, addr, pte, newpte);
153 : :
154 : : pages++;
155 : : }
156 : : }
157 [ + + ]: 47666178 : } while (pte++, addr += PAGE_SIZE, addr != end);
158 : : arch_leave_lazy_mmu_mode();
159 : : pte_unmap_unlock(pte - 1, ptl);
160 : :
161 : 5738626 : return pages;
162 : : }
163 : :
164 : : /*
165 : : * Used when setting automatic NUMA hinting protection where it is
166 : : * critical that a numa hinting PMD is not confused with a bad PMD.
167 : : */
168 : : static inline int pmd_none_or_clear_bad_unless_trans_huge(pmd_t *pmd)
169 : : {
170 : : pmd_t pmdval = pmd_read_atomic(pmd);
171 : :
172 : : /* See pmd_none_or_trans_huge_or_clear_bad for info on barrier */
173 : : #ifdef CONFIG_TRANSPARENT_HUGEPAGE
174 : : barrier();
175 : : #endif
176 : :
177 [ + + ]: 5954248 : if (pmd_none(pmdval))
178 : : return 1;
179 : : if (pmd_trans_huge(pmdval))
180 : : return 0;
181 [ - + ]: 5738702 : if (unlikely(pmd_bad(pmdval))) {
182 : 0 : pmd_clear_bad(pmd);
183 : : return 1;
184 : : }
185 : :
186 : : return 0;
187 : : }
188 : :
189 : 5954248 : static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
190 : : pud_t *pud, unsigned long addr, unsigned long end,
191 : : pgprot_t newprot, int dirty_accountable, int prot_numa)
192 : : {
193 : : pmd_t *pmd;
194 : : unsigned long next;
195 : : unsigned long pages = 0;
196 : : unsigned long nr_huge_updates = 0;
197 : : struct mmu_notifier_range range;
198 : :
199 : : range.start = 0;
200 : :
201 : : pmd = pmd_offset(pud, addr);
202 : : do {
203 : : unsigned long this_pages;
204 : :
205 : : next = pmd_addr_end(addr, end);
206 : :
207 : : /*
208 : : * Automatic NUMA balancing walks the tables with mmap_sem
209 : : * held for read. It's possible a parallel update to occur
210 : : * between pmd_trans_huge() and a pmd_none_or_clear_bad()
211 : : * check leading to a false positive and clearing.
212 : : * Hence, it's necessary to atomically read the PMD value
213 : : * for all the checks.
214 : : */
215 [ + + ]: 5954450 : if (!is_swap_pmd(*pmd) && !pmd_devmap(*pmd) &&
216 : : pmd_none_or_clear_bad_unless_trans_huge(pmd))
217 : : goto next;
218 : :
219 : : /* invoke the mmu notifier if the pmd is populated */
220 : : if (!range.start) {
221 : : mmu_notifier_range_init(&range,
222 : : MMU_NOTIFY_PROTECTION_VMA, 0,
223 : : vma, vma->vm_mm, addr, end);
224 : : mmu_notifier_invalidate_range_start(&range);
225 : : }
226 : :
227 : : if (is_swap_pmd(*pmd) || pmd_trans_huge(*pmd) || pmd_devmap(*pmd)) {
228 : : if (next - addr != HPAGE_PMD_SIZE) {
229 : : __split_huge_pmd(vma, pmd, addr, false, NULL);
230 : : } else {
231 : : int nr_ptes = change_huge_pmd(vma, pmd, addr,
232 : : newprot, prot_numa);
233 : :
234 : : if (nr_ptes) {
235 : : if (nr_ptes == HPAGE_PMD_NR) {
236 : : pages += HPAGE_PMD_NR;
237 : : nr_huge_updates++;
238 : : }
239 : :
240 : : /* huge pmd was handled */
241 : : goto next;
242 : : }
243 : : }
244 : : /* fall through, the trans huge pmd just split */
245 : : }
246 : 5738740 : this_pages = change_pte_range(vma, pmd, addr, next, newprot,
247 : : dirty_accountable, prot_numa);
248 : 5738632 : pages += this_pages;
249 : : next:
250 : 5954342 : cond_resched();
251 : : } while (pmd++, addr = next, addr != end);
252 : :
253 : : if (range.start)
254 : : mmu_notifier_invalidate_range_end(&range);
255 : :
256 : : if (nr_huge_updates)
257 : : count_vm_numa_events(NUMA_HUGE_PTE_UPDATES, nr_huge_updates);
258 : 5954438 : return pages;
259 : : }
260 : :
261 : : static inline unsigned long change_pud_range(struct vm_area_struct *vma,
262 : : p4d_t *p4d, unsigned long addr, unsigned long end,
263 : : pgprot_t newprot, int dirty_accountable, int prot_numa)
264 : : {
265 : : pud_t *pud;
266 : : unsigned long next;
267 : : unsigned long pages = 0;
268 : :
269 : : pud = pud_offset(p4d, addr);
270 : : do {
271 : : next = pud_addr_end(addr, end);
272 : : if (pud_none_or_clear_bad(pud))
273 : : continue;
274 : 5954454 : pages += change_pmd_range(vma, pud, addr, next, newprot,
275 : : dirty_accountable, prot_numa);
276 : : } while (pud++, addr = next, addr != end);
277 : :
278 : : return pages;
279 : : }
280 : :
281 : : static inline unsigned long change_p4d_range(struct vm_area_struct *vma,
282 : : pgd_t *pgd, unsigned long addr, unsigned long end,
283 : : pgprot_t newprot, int dirty_accountable, int prot_numa)
284 : : {
285 : : p4d_t *p4d;
286 : : unsigned long next;
287 : : unsigned long pages = 0;
288 : :
289 : : p4d = p4d_offset(pgd, addr);
290 : : do {
291 : : next = p4d_addr_end(addr, end);
292 : : if (p4d_none_or_clear_bad(p4d))
293 : : continue;
294 : : pages += change_pud_range(vma, p4d, addr, next, newprot,
295 : : dirty_accountable, prot_numa);
296 : : } while (p4d++, addr = next, addr != end);
297 : :
298 : : return pages;
299 : : }
300 : :
301 : 5795394 : static unsigned long change_protection_range(struct vm_area_struct *vma,
302 : : unsigned long addr, unsigned long end, pgprot_t newprot,
303 : : int dirty_accountable, int prot_numa)
304 : : {
305 : 5795394 : struct mm_struct *mm = vma->vm_mm;
306 : : pgd_t *pgd;
307 : : unsigned long next;
308 : : unsigned long start = addr;
309 : : unsigned long pages = 0;
310 : :
311 [ - + ]: 5795394 : BUG_ON(addr >= end);
312 : 5795394 : pgd = pgd_offset(mm, addr);
313 : 5795394 : flush_cache_range(vma, addr, end);
314 : : inc_tlb_flush_pending(mm);
315 : : do {
316 [ + + ]: 5954454 : next = pgd_addr_end(addr, end);
317 : : if (pgd_none_or_clear_bad(pgd))
318 : : continue;
319 : 5954402 : pages += change_p4d_range(vma, pgd, addr, next, newprot,
320 : : dirty_accountable, prot_numa);
321 [ + + ]: 5954402 : } while (pgd++, addr = next, addr != end);
322 : :
323 : : /* Only flush the TLB if we actually modified any entries: */
324 [ + + ]: 5795348 : if (pages)
325 : 3296260 : flush_tlb_range(vma, start, end);
326 : : dec_tlb_flush_pending(mm);
327 : :
328 : 5795094 : return pages;
329 : : }
330 : :
331 : 0 : unsigned long change_protection(struct vm_area_struct *vma, unsigned long start,
332 : : unsigned long end, pgprot_t newprot,
333 : : int dirty_accountable, int prot_numa)
334 : : {
335 : : unsigned long pages;
336 : :
337 : : if (is_vm_hugetlb_page(vma))
338 : : pages = hugetlb_change_protection(vma, start, end, newprot);
339 : : else
340 : 5795448 : pages = change_protection_range(vma, start, end, newprot, dirty_accountable, prot_numa);
341 : :
342 : 0 : return pages;
343 : : }
344 : :
345 : : static int prot_none_pte_entry(pte_t *pte, unsigned long addr,
346 : : unsigned long next, struct mm_walk *walk)
347 : : {
348 : : return pfn_modify_allowed(pte_pfn(*pte), *(pgprot_t *)(walk->private)) ?
349 : : 0 : -EACCES;
350 : : }
351 : :
352 : : static int prot_none_hugetlb_entry(pte_t *pte, unsigned long hmask,
353 : : unsigned long addr, unsigned long next,
354 : : struct mm_walk *walk)
355 : : {
356 : : return pfn_modify_allowed(pte_pfn(*pte), *(pgprot_t *)(walk->private)) ?
357 : : 0 : -EACCES;
358 : : }
359 : :
360 : : static int prot_none_test(unsigned long addr, unsigned long next,
361 : : struct mm_walk *walk)
362 : : {
363 : : return 0;
364 : : }
365 : :
366 : : static const struct mm_walk_ops prot_none_walk_ops = {
367 : : .pte_entry = prot_none_pte_entry,
368 : : .hugetlb_entry = prot_none_hugetlb_entry,
369 : : .test_walk = prot_none_test,
370 : : };
371 : :
372 : : int
373 : 6245978 : mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
374 : : unsigned long start, unsigned long end, unsigned long newflags)
375 : : {
376 : 6245978 : struct mm_struct *mm = vma->vm_mm;
377 : 6245978 : unsigned long oldflags = vma->vm_flags;
378 : 6245978 : long nrpages = (end - start) >> PAGE_SHIFT;
379 : : unsigned long charged = 0;
380 : : pgoff_t pgoff;
381 : : int error;
382 : : int dirty_accountable = 0;
383 : :
384 [ + + ]: 6245978 : if (newflags == oldflags) {
385 : 450566 : *pprev = vma;
386 : 450566 : return 0;
387 : : }
388 : :
389 : : /*
390 : : * Do PROT_NONE PFN permission checks here when we can still
391 : : * bail out without undoing a lot of state. This is a rather
392 : : * uncommon case, so doesn't need to be very optimized.
393 : : */
394 : : if (arch_has_pfn_modify_check() &&
395 : : (vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP)) &&
396 : : (newflags & (VM_READ|VM_WRITE|VM_EXEC)) == 0) {
397 : : pgprot_t new_pgprot = vm_get_page_prot(newflags);
398 : :
399 : : error = walk_page_range(current->mm, start, end,
400 : : &prot_none_walk_ops, &new_pgprot);
401 : : if (error)
402 : : return error;
403 : : }
404 : :
405 : : /*
406 : : * If we make a private mapping writable we increase our commit;
407 : : * but (without finer accounting) cannot reduce our commit if we
408 : : * make it unwritable again. hugetlb mapping were accounted for
409 : : * even if read-only so there is no need to account for them here
410 : : */
411 [ + + ]: 5795412 : if (newflags & VM_WRITE) {
412 : : /* Check space limits when area turns into data. */
413 [ - + # # ]: 101760 : if (!may_expand_vm(mm, newflags, nrpages) &&
414 : 0 : may_expand_vm(mm, oldflags, nrpages))
415 : : return -ENOMEM;
416 [ + + ]: 101760 : if (!(oldflags & (VM_ACCOUNT|VM_WRITE|VM_HUGETLB|
417 : : VM_SHARED|VM_NORESERVE))) {
418 : : charged = nrpages;
419 [ + - ]: 31396 : if (security_vm_enough_memory_mm(mm, charged))
420 : : return -ENOMEM;
421 : 31396 : newflags |= VM_ACCOUNT;
422 : : }
423 : : }
424 : :
425 : : /*
426 : : * First try to merge with previous and/or next vma.
427 : : */
428 : 5795412 : pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
429 : 5795412 : *pprev = vma_merge(mm, *pprev, start, end, newflags,
430 : : vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma),
431 : : vma->vm_userfaultfd_ctx);
432 [ + + ]: 5795352 : if (*pprev) {
433 : : vma = *pprev;
434 : : VM_WARN_ON((vma->vm_flags ^ newflags) & ~VM_SOFTDIRTY);
435 : : goto success;
436 : : }
437 : :
438 : 5753340 : *pprev = vma;
439 : :
440 [ + + ]: 5753340 : if (start != vma->vm_start) {
441 : 2428738 : error = split_vma(mm, vma, start, 1);
442 [ + + ]: 2428928 : if (error)
443 : : goto fail;
444 : : }
445 : :
446 [ + + ]: 5753346 : if (end != vma->vm_end) {
447 : 5725642 : error = split_vma(mm, vma, end, 0);
448 [ + + ]: 5725758 : if (error)
449 : : goto fail;
450 : : }
451 : :
452 : : success:
453 : : /*
454 : : * vm_flags and vm_page_prot are protected by the mmap_sem
455 : : * held in write mode.
456 : : */
457 : 5795432 : vma->vm_flags = newflags;
458 : 5795432 : dirty_accountable = vma_wants_writenotify(vma, vma->vm_page_prot);
459 : 5795448 : vma_set_page_prot(vma);
460 : :
461 : 5795448 : change_protection(vma, start, end, vma->vm_page_prot,
462 : : dirty_accountable, 0);
463 : :
464 : : /*
465 : : * Private VM_LOCKED VMA becoming writable: trigger COW to avoid major
466 : : * fault on access.
467 : : */
468 [ - + # # ]: 5795410 : if ((oldflags & (VM_WRITE | VM_SHARED | VM_LOCKED)) == VM_LOCKED &&
469 : 0 : (newflags & VM_WRITE)) {
470 : 0 : populate_vma_page_range(vma, start, end, NULL);
471 : : }
472 : :
473 : 5795410 : vm_stat_account(mm, oldflags, -nrpages);
474 : 5795428 : vm_stat_account(mm, newflags, nrpages);
475 : 5795360 : perf_event_mmap(vma);
476 : 5795432 : return 0;
477 : :
478 : : fail:
479 : 262 : vm_unacct_memory(charged);
480 : 0 : return error;
481 : : }
482 : :
483 : : /*
484 : : * pkey==-1 when doing a legacy mprotect()
485 : : */
486 : 5795428 : static int do_mprotect_pkey(unsigned long start, size_t len,
487 : : unsigned long prot, int pkey)
488 : : {
489 : : unsigned long nstart, end, tmp, reqprot;
490 : : struct vm_area_struct *vma, *prev;
491 : : int error = -EINVAL;
492 : 5795428 : const int grows = prot & (PROT_GROWSDOWN|PROT_GROWSUP);
493 [ - + # # ]: 5795428 : const bool rier = (current->personality & READ_IMPLIES_EXEC) &&
494 : 0 : (prot & PROT_READ);
495 : :
496 : : start = untagged_addr(start);
497 : :
498 : 5795428 : prot &= ~(PROT_GROWSDOWN|PROT_GROWSUP);
499 [ + + ]: 5795428 : if (grows == (PROT_GROWSDOWN|PROT_GROWSUP)) /* can't be both */
500 : : return -EINVAL;
501 : :
502 [ + + ]: 5795388 : if (start & ~PAGE_MASK)
503 : : return -EINVAL;
504 [ + + ]: 5795418 : if (!len)
505 : : return 0;
506 : 5795410 : len = PAGE_ALIGN(len);
507 : 5795410 : end = start + len;
508 [ + + ]: 5795410 : if (end <= start)
509 : : return -ENOMEM;
510 [ + + ]: 5795410 : if (!arch_validate_prot(prot, start))
511 : : return -EINVAL;
512 : :
513 : : reqprot = prot;
514 : :
515 [ + + ]: 5795414 : if (down_write_killable(¤t->mm->mmap_sem))
516 : : return -EINTR;
517 : :
518 : : /*
519 : : * If userspace did not allocate the pkey, do not let
520 : : * them use it here.
521 : : */
522 : : error = -EINVAL;
523 [ - + # # ]: 5795414 : if ((pkey != -1) && !mm_pkey_is_allocated(current->mm, pkey))
524 : : goto out;
525 : :
526 : 5795414 : vma = find_vma(current->mm, start);
527 : : error = -ENOMEM;
528 [ + + ]: 5795410 : if (!vma)
529 : : goto out;
530 : 5795420 : prev = vma->vm_prev;
531 [ + + ]: 5795420 : if (unlikely(grows & PROT_GROWSDOWN)) {
532 [ + - ]: 2 : if (vma->vm_start >= end)
533 : : goto out;
534 : : start = vma->vm_start;
535 : : error = -EINVAL;
536 [ + - ]: 2 : if (!(vma->vm_flags & VM_GROWSDOWN))
537 : : goto out;
538 : : } else {
539 [ + + ]: 5795418 : if (vma->vm_start > start)
540 : : goto out;
541 [ + + ]: 5795418 : if (unlikely(grows & PROT_GROWSUP)) {
542 : : end = vma->vm_end;
543 : : error = -EINVAL;
544 : : if (!(vma->vm_flags & VM_GROWSUP))
545 : : goto out;
546 : : }
547 : : }
548 [ + + ]: 5795346 : if (start > vma->vm_start)
549 : 2429766 : prev = vma;
550 : :
551 : : for (nstart = start ; ; ) {
552 : : unsigned long mask_off_old_flags;
553 : : unsigned long newflags;
554 : : int new_vma_pkey;
555 : :
556 : : /* Here we know that vma->vm_start <= nstart < vma->vm_end. */
557 : :
558 : : /* Does the application expect PROT_READ to imply PROT_EXEC */
559 [ - + # # ]: 5795346 : if (rier && (vma->vm_flags & VM_MAYEXEC))
560 : 0 : prot |= PROT_EXEC;
561 : :
562 : : /*
563 : : * Each mprotect() call explicitly passes r/w/x permissions.
564 : : * If a permission is not passed to mprotect(), it must be
565 : : * cleared from the VMA.
566 : : */
567 : : mask_off_old_flags = VM_READ | VM_WRITE | VM_EXEC |
568 : : VM_FLAGS_CLEAR;
569 : :
570 : : new_vma_pkey = arch_override_mprotect_pkey(vma, prot, pkey);
571 : : newflags = calc_vm_prot_bits(prot, new_vma_pkey);
572 : 5795346 : newflags |= (vma->vm_flags & ~mask_off_old_flags);
573 : :
574 : : /* newflags >> 4 shift VM_MAY% in place of VM_% */
575 [ + + ]: 5795346 : if ((newflags & ~(newflags >> 4)) & (VM_READ | VM_WRITE | VM_EXEC)) {
576 : : error = -EACCES;
577 : : goto out;
578 : : }
579 : :
580 : 5795338 : error = security_file_mprotect(vma, reqprot, prot);
581 [ + + ]: 5795426 : if (error)
582 : : goto out;
583 : :
584 : 5795392 : tmp = vma->vm_end;
585 [ + + ]: 5795392 : if (tmp > end)
586 : : tmp = end;
587 : 5795392 : error = mprotect_fixup(vma, &prev, nstart, tmp, newflags);
588 [ + + ]: 5795338 : if (error)
589 : : goto out;
590 : : nstart = tmp;
591 : :
592 [ + + ]: 5795266 : if (nstart < prev->vm_end)
593 : : nstart = prev->vm_end;
594 [ - + ]: 5795266 : if (nstart >= end)
595 : : goto out;
596 : :
597 : 0 : vma = prev->vm_next;
598 [ # # # # ]: 0 : if (!vma || vma->vm_start != nstart) {
599 : : error = -ENOMEM;
600 : : goto out;
601 : : }
602 : : prot = reqprot;
603 : : }
604 : : out:
605 : 5795444 : up_write(¤t->mm->mmap_sem);
606 : 5795416 : return error;
607 : : }
608 : :
609 : 11590790 : SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
610 : : unsigned long, prot)
611 : : {
612 : 5795428 : return do_mprotect_pkey(start, len, prot, -1);
613 : : }
614 : :
615 : : #ifdef CONFIG_ARCH_HAS_PKEYS
616 : :
617 : : SYSCALL_DEFINE4(pkey_mprotect, unsigned long, start, size_t, len,
618 : : unsigned long, prot, int, pkey)
619 : : {
620 : : return do_mprotect_pkey(start, len, prot, pkey);
621 : : }
622 : :
623 : : SYSCALL_DEFINE2(pkey_alloc, unsigned long, flags, unsigned long, init_val)
624 : : {
625 : : int pkey;
626 : : int ret;
627 : :
628 : : /* No flags supported yet. */
629 : : if (flags)
630 : : return -EINVAL;
631 : : /* check for unsupported init values */
632 : : if (init_val & ~PKEY_ACCESS_MASK)
633 : : return -EINVAL;
634 : :
635 : : down_write(¤t->mm->mmap_sem);
636 : : pkey = mm_pkey_alloc(current->mm);
637 : :
638 : : ret = -ENOSPC;
639 : : if (pkey == -1)
640 : : goto out;
641 : :
642 : : ret = arch_set_user_pkey_access(current, pkey, init_val);
643 : : if (ret) {
644 : : mm_pkey_free(current->mm, pkey);
645 : : goto out;
646 : : }
647 : : ret = pkey;
648 : : out:
649 : : up_write(¤t->mm->mmap_sem);
650 : : return ret;
651 : : }
652 : :
653 : : SYSCALL_DEFINE1(pkey_free, int, pkey)
654 : : {
655 : : int ret;
656 : :
657 : : down_write(¤t->mm->mmap_sem);
658 : : ret = mm_pkey_free(current->mm, pkey);
659 : : up_write(¤t->mm->mmap_sem);
660 : :
661 : : /*
662 : : * We could provie warnings or errors if any VMA still
663 : : * has the pkey set here.
664 : : */
665 : : return ret;
666 : : }
667 : :
668 : : #endif /* CONFIG_ARCH_HAS_PKEYS */
|