diff options
-rw-r--r-- | arch/x86/include/asm/mmu_context.h | 15 | ||||
-rw-r--r-- | arch/x86/include/asm/pkeys.h | 11 | ||||
-rw-r--r-- | include/linux/pkeys.h | 12 | ||||
-rw-r--r-- | mm/mprotect.c | 30 |
4 files changed, 45 insertions, 23 deletions
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h index d8abfcf524d1..af0251fc85ed 100644 --- a/arch/x86/include/asm/mmu_context.h +++ b/arch/x86/include/asm/mmu_context.h | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <asm/desc.h> | 4 | #include <asm/desc.h> |
5 | #include <linux/atomic.h> | 5 | #include <linux/atomic.h> |
6 | #include <linux/mm_types.h> | 6 | #include <linux/mm_types.h> |
7 | #include <linux/pkeys.h> | ||
7 | 8 | ||
8 | #include <trace/events/tlb.h> | 9 | #include <trace/events/tlb.h> |
9 | 10 | ||
@@ -195,16 +196,20 @@ static inline void arch_unmap(struct mm_struct *mm, struct vm_area_struct *vma, | |||
195 | mpx_notify_unmap(mm, vma, start, end); | 196 | mpx_notify_unmap(mm, vma, start, end); |
196 | } | 197 | } |
197 | 198 | ||
199 | #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS | ||
198 | static inline int vma_pkey(struct vm_area_struct *vma) | 200 | static inline int vma_pkey(struct vm_area_struct *vma) |
199 | { | 201 | { |
200 | u16 pkey = 0; | ||
201 | #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS | ||
202 | unsigned long vma_pkey_mask = VM_PKEY_BIT0 | VM_PKEY_BIT1 | | 202 | unsigned long vma_pkey_mask = VM_PKEY_BIT0 | VM_PKEY_BIT1 | |
203 | VM_PKEY_BIT2 | VM_PKEY_BIT3; | 203 | VM_PKEY_BIT2 | VM_PKEY_BIT3; |
204 | pkey = (vma->vm_flags & vma_pkey_mask) >> VM_PKEY_SHIFT; | 204 | |
205 | #endif | 205 | return (vma->vm_flags & vma_pkey_mask) >> VM_PKEY_SHIFT; |
206 | return pkey; | 206 | } |
207 | #else | ||
208 | static inline int vma_pkey(struct vm_area_struct *vma) | ||
209 | { | ||
210 | return 0; | ||
207 | } | 211 | } |
212 | #endif | ||
208 | 213 | ||
209 | static inline bool __pkru_allows_pkey(u16 pkey, bool write) | 214 | static inline bool __pkru_allows_pkey(u16 pkey, bool write) |
210 | { | 215 | { |
diff --git a/arch/x86/include/asm/pkeys.h b/arch/x86/include/asm/pkeys.h index 7b84565c916c..33777c291a85 100644 --- a/arch/x86/include/asm/pkeys.h +++ b/arch/x86/include/asm/pkeys.h | |||
@@ -1,7 +1,12 @@ | |||
1 | #ifndef _ASM_X86_PKEYS_H | 1 | #ifndef _ASM_X86_PKEYS_H |
2 | #define _ASM_X86_PKEYS_H | 2 | #define _ASM_X86_PKEYS_H |
3 | 3 | ||
4 | #define arch_max_pkey() (boot_cpu_has(X86_FEATURE_OSPKE) ? 16 : 1) | 4 | #define PKEY_DEDICATED_EXECUTE_ONLY 15 |
5 | /* | ||
6 | * Consider the PKEY_DEDICATED_EXECUTE_ONLY key unavailable. | ||
7 | */ | ||
8 | #define arch_max_pkey() (boot_cpu_has(X86_FEATURE_OSPKE) ? \ | ||
9 | PKEY_DEDICATED_EXECUTE_ONLY : 1) | ||
5 | 10 | ||
6 | extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, | 11 | extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, |
7 | unsigned long init_val); | 12 | unsigned long init_val); |
@@ -10,7 +15,6 @@ extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, | |||
10 | * Try to dedicate one of the protection keys to be used as an | 15 | * Try to dedicate one of the protection keys to be used as an |
11 | * execute-only protection key. | 16 | * execute-only protection key. |
12 | */ | 17 | */ |
13 | #define PKEY_DEDICATED_EXECUTE_ONLY 15 | ||
14 | extern int __execute_only_pkey(struct mm_struct *mm); | 18 | extern int __execute_only_pkey(struct mm_struct *mm); |
15 | static inline int execute_only_pkey(struct mm_struct *mm) | 19 | static inline int execute_only_pkey(struct mm_struct *mm) |
16 | { | 20 | { |
@@ -31,4 +35,7 @@ static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma, | |||
31 | return __arch_override_mprotect_pkey(vma, prot, pkey); | 35 | return __arch_override_mprotect_pkey(vma, prot, pkey); |
32 | } | 36 | } |
33 | 37 | ||
38 | extern int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey, | ||
39 | unsigned long init_val); | ||
40 | |||
34 | #endif /*_ASM_X86_PKEYS_H */ | 41 | #endif /*_ASM_X86_PKEYS_H */ |
diff --git a/include/linux/pkeys.h b/include/linux/pkeys.h index 1d405a2b7272..0030b4024559 100644 --- a/include/linux/pkeys.h +++ b/include/linux/pkeys.h | |||
@@ -18,16 +18,4 @@ | |||
18 | #define PKEY_DEDICATED_EXECUTE_ONLY 0 | 18 | #define PKEY_DEDICATED_EXECUTE_ONLY 0 |
19 | #endif /* ! CONFIG_ARCH_HAS_PKEYS */ | 19 | #endif /* ! CONFIG_ARCH_HAS_PKEYS */ |
20 | 20 | ||
21 | /* | ||
22 | * This is called from mprotect_pkey(). | ||
23 | * | ||
24 | * Returns true if the protection keys is valid. | ||
25 | */ | ||
26 | static inline bool validate_pkey(int pkey) | ||
27 | { | ||
28 | if (pkey < 0) | ||
29 | return false; | ||
30 | return (pkey < arch_max_pkey()); | ||
31 | } | ||
32 | |||
33 | #endif /* _LINUX_PKEYS_H */ | 21 | #endif /* _LINUX_PKEYS_H */ |
diff --git a/mm/mprotect.c b/mm/mprotect.c index a4830f0325fe..dd3f40a2935f 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c | |||
@@ -352,8 +352,11 @@ fail: | |||
352 | return error; | 352 | return error; |
353 | } | 353 | } |
354 | 354 | ||
355 | SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, | 355 | /* |
356 | unsigned long, prot) | 356 | * pkey==-1 when doing a legacy mprotect() |
357 | */ | ||
358 | static int do_mprotect_pkey(unsigned long start, size_t len, | ||
359 | unsigned long prot, int pkey) | ||
357 | { | 360 | { |
358 | unsigned long nstart, end, tmp, reqprot; | 361 | unsigned long nstart, end, tmp, reqprot; |
359 | struct vm_area_struct *vma, *prev; | 362 | struct vm_area_struct *vma, *prev; |
@@ -361,6 +364,12 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, | |||
361 | const int grows = prot & (PROT_GROWSDOWN|PROT_GROWSUP); | 364 | const int grows = prot & (PROT_GROWSDOWN|PROT_GROWSUP); |
362 | const bool rier = (current->personality & READ_IMPLIES_EXEC) && | 365 | const bool rier = (current->personality & READ_IMPLIES_EXEC) && |
363 | (prot & PROT_READ); | 366 | (prot & PROT_READ); |
367 | /* | ||
368 | * A temporary safety check since we are not validating | ||
369 | * the pkey before we introduce the allocation code. | ||
370 | */ | ||
371 | if (pkey != -1) | ||
372 | return -EINVAL; | ||
364 | 373 | ||
365 | prot &= ~(PROT_GROWSDOWN|PROT_GROWSUP); | 374 | prot &= ~(PROT_GROWSDOWN|PROT_GROWSUP); |
366 | if (grows == (PROT_GROWSDOWN|PROT_GROWSUP)) /* can't be both */ | 375 | if (grows == (PROT_GROWSDOWN|PROT_GROWSUP)) /* can't be both */ |
@@ -409,7 +418,7 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, | |||
409 | 418 | ||
410 | for (nstart = start ; ; ) { | 419 | for (nstart = start ; ; ) { |
411 | unsigned long newflags; | 420 | unsigned long newflags; |
412 | int pkey = arch_override_mprotect_pkey(vma, prot, -1); | 421 | int new_vma_pkey; |
413 | 422 | ||
414 | /* Here we know that vma->vm_start <= nstart < vma->vm_end. */ | 423 | /* Here we know that vma->vm_start <= nstart < vma->vm_end. */ |
415 | 424 | ||
@@ -417,7 +426,8 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, | |||
417 | if (rier && (vma->vm_flags & VM_MAYEXEC)) | 426 | if (rier && (vma->vm_flags & VM_MAYEXEC)) |
418 | prot |= PROT_EXEC; | 427 | prot |= PROT_EXEC; |
419 | 428 | ||
420 | newflags = calc_vm_prot_bits(prot, pkey); | 429 | new_vma_pkey = arch_override_mprotect_pkey(vma, prot, pkey); |
430 | newflags = calc_vm_prot_bits(prot, new_vma_pkey); | ||
421 | newflags |= (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC)); | 431 | newflags |= (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC)); |
422 | 432 | ||
423 | /* newflags >> 4 shift VM_MAY% in place of VM_% */ | 433 | /* newflags >> 4 shift VM_MAY% in place of VM_% */ |
@@ -454,3 +464,15 @@ out: | |||
454 | up_write(¤t->mm->mmap_sem); | 464 | up_write(¤t->mm->mmap_sem); |
455 | return error; | 465 | return error; |
456 | } | 466 | } |
467 | |||
468 | SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, | ||
469 | unsigned long, prot) | ||
470 | { | ||
471 | return do_mprotect_pkey(start, len, prot, -1); | ||
472 | } | ||
473 | |||
474 | SYSCALL_DEFINE4(pkey_mprotect, unsigned long, start, size_t, len, | ||
475 | unsigned long, prot, int, pkey) | ||
476 | { | ||
477 | return do_mprotect_pkey(start, len, prot, pkey); | ||
478 | } | ||