powerpc/pkeys: copy pkey-tracking-information at fork()
PATCH 1/1 powerpc/pkeys: copy pkey-tracking-information at fork()
At fork(), the pkey tracking information is not copied over to the mm_struct of the child. This can cause the child to erroneously allocate keys that were already allocated. Any allocated execute-only key is lost aswell.
Add code; called by dup_mmap(), to copy the pkey state from parent to child explicitly.
This problem was originally found by Dave Hansen on x86, which turns out to be a problem on powerpc aswell.
Testing:
Passes the new selftest added by Dave Hansen. I have temporarily captured that selftest at
https://github.com/rampai/memorykeys/ -b memkey.v15-rc6
--- arch/powerpc/include/asm/mmu_context.h | 15 +++++++++------ arch/powerpc/mm/pkeys.c | 7 +++++++ 2 files changed, 16 insertions(+), 6 deletions(-)
arch/powerpc/include/asm/mmu_context.h +9 -6
@@ -217,12 +217,6 @@ static inline void enter_lazy_tlb(struct mm_struct *mm,#endif } -static inline int arch_dup_mmap (struct mm_struct *oldmm, -struct mm_struct *mm) -{ -return 0 ; -} -#ifndef CONFIG_PPC_BOOK3S_64 static inline void arch_exit_mmap (struct mm_struct *mm) {
@@ -247,6 +241,7 @@ static inline void arch_bprm_mm_init(struct mm_struct *mm,#ifdef CONFIG_PPC_MEM_KEYS bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write,bool execute,bool foreign); +void arch_dup_pkeys (struct mm_struct *oldmm,struct mm_struct *mm);#else /* CONFIG_PPC_MEM_KEYS */ static inline bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write,bool execute,bool foreign)
@@ -259,6 +254,7 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,#define thread_pkey_regs_save (thread)#define thread_pkey_regs_restore (new_thread, old_thread)#define thread_pkey_regs_init (thread) +#define arch_dup_pkeys (oldmm, mm)static inline u64 pte_to_hpte_pkey_bits (u64 pteflags) {
@@ -267,5 +263,12 @@ static inline u64 pte_to_hpte_pkey_bits(u64 pteflags)#endif /* CONFIG_PPC_MEM_KEYS */ +static inline int arch_dup_mmap (struct mm_struct *oldmm, +struct mm_struct *mm) +{ +arch_dup_pkeys (oldmm, mm); +return 0 ; +} +#endif /* __KERNEL__ */ #endif /* __ASM_POWERPC_MMU_CONTEXT_H */
arch/powerpc/mm/pkeys.c +7 -0
@@ -414,3 +414,10 @@ bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write,return pkey_access_permitted (vma_pkey (vma), write, execute); } + +void arch_dup_pkeys (struct mm_struct *oldmm,struct mm_struct *mm) +{ +/* Duplicate the oldmm pkey state in mm: */ +mm_pkey_allocation_map (mm) =mm_pkey_allocation_map (oldmm); + mm->context.execute_only_pkey = oldmm->context.execute_only_pkey; +}
Signature · 1 line
1.7.1
Quoted 73 lines · Ram Pai
At
fork(), the pkey tracking information is not copied over to themm_structof the child. This can cause the child to erroneously allocate keys that were already allocated. Any allocated execute-only key is lost aswell.Add code; called by
dup_mmap(), to copy the pkey state from parent to child explicitly.This problem was originally found by Dave Hansen on x86, which turns out to be a problem on powerpc aswell.
Testing:
Passes the new selftest added by Dave Hansen. I have temporarily captured that selftest at
https://github.com/rampai/memorykeys/ -b memkey.v15-rc6Signed-off-by Ram Pai <[email protected]>--- arch/powerpc/include/asm/mmu_context.h | 15 +++++++++------ arch/powerpc/mm/pkeys.c | 7 +++++++ 2 files changed, 16 insertions(+), 6 deletions(-)arch/powerpc/include/asm/mmu_context.h +9
-6@@ -217,12 +217,6 @@ static inline void enter_lazy_tlb(struct mm_struct *mm,#endif } -static inline int arch_dup_mmap (struct mm_struct *oldmm, -struct mm_struct *mm) -{ -return 0 ; -} -#ifndef CONFIG_PPC_BOOK3S_64 static inline void arch_exit_mmap (struct mm_struct *mm) {@@ -247,6 +241,7 @@ static inline void arch_bprm_mm_init(struct mm_struct *mm,#ifdef CONFIG_PPC_MEM_KEYS bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write,bool execute,bool foreign); +void arch_dup_pkeys (struct mm_struct *oldmm,struct mm_struct *mm);#else /* CONFIG_PPC_MEM_KEYS */ static inline bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write,bool execute,bool foreign)@@ -259,6 +254,7 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,#define thread_pkey_regs_save (thread)#define thread_pkey_regs_restore (new_thread, old_thread)#define thread_pkey_regs_init (thread) +#define arch_dup_pkeys (oldmm, mm)static inline u64 pte_to_hpte_pkey_bits (u64 pteflags) {@@ -267,5 +263,12 @@ static inline u64 pte_to_hpte_pkey_bits(u64 pteflags)#endif /* CONFIG_PPC_MEM_KEYS */ +static inline int arch_dup_mmap (struct mm_struct *oldmm, +struct mm_struct *mm) +{ +arch_dup_pkeys (oldmm, mm); +return 0 ; +} +#endif /* __KERNEL__ */ #endif /* __ASM_POWERPC_MMU_CONTEXT_H */ arch/powerpc/mm/pkeys.c +0
-0
arch/powerpc/mm/pkeys.c bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write, · line 423
Quoted 10 lines
arch/powerpc/mm/pkeys.c +7
-0@@ -414,3 +414,10 @@ bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write,return pkey_access_permitted (vma_pkey (vma), write, execute); } + +void arch_dup_pkeys (struct mm_struct *oldmm,struct mm_struct *mm) +{ +/* Duplicate the oldmm pkey state in mm: */ +mm_pkey_allocation_map (mm) =mm_pkey_allocation_map (oldmm); + mm->context.execute_only_pkey = oldmm->context.execute_only_pkey; +}
This function is small and perhaps could have been a static inline in <asm/mmu_context.h>, but arch_dup_mmap() doesn't seem to be in a hot path so the segregation of implementation details to pkeys.c is nice from an organization point of view.
--
Thiago Jung Bauermann
IBM Linux Technology Center
* Ram Pai:
arch/powerpc/mm/pkeys.c bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write, · line 423
Quoted 6 lines
arch/powerpc/mm/pkeys.c +6
-0+void arch_dup_pkeys (struct mm_struct *oldmm,struct mm_struct *mm) +{ +/* Duplicate the oldmm pkey state in mm: */ +mm_pkey_allocation_map (mm) =mm_pkey_allocation_map (oldmm); + mm->context.execute_only_pkey = oldmm->context.execute_only_pkey; +}
Looks reasonable to me.
Thanks,
Florian (who is not a kernel developer though)
Michael Ellerman
reviewerHi Ram,
Thanks for fixing this.
Quoted 5 lines · Ram Pai
arch/powerpc/mm/pkeys.c +0
-0
arch/powerpc/mm/pkeys.c bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write, · line 423
Quoted 10 lines
arch/powerpc/mm/pkeys.c +7
-0@@ -414,3 +414,10 @@ bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write,return pkey_access_permitted (vma_pkey (vma), write, execute); } + +void arch_dup_pkeys (struct mm_struct *oldmm,struct mm_struct *mm) +{ +/* Duplicate the oldmm pkey state in mm: */ +mm_pkey_allocation_map (mm) =mm_pkey_allocation_map (oldmm); + mm->context.execute_only_pkey = oldmm->context.execute_only_pkey; +}
Shouldn't this check if pkeys are actually in use?
eg:
arch/powerpc/mm/pkeys.c +3 -0
@@ -418,6 +418,9 @@ bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write,void arch_dup_pkeys (struct mm_struct *oldmm,struct mm_struct *mm) { +if (static_branch_likely (&pkey_disabled)) +return ; +/* Duplicate the oldmm pkey state in mm: */ mm_pkey_allocation_map (mm) =mm_pkey_allocation_map (oldmm); mm->context.execute_only_pkey = oldmm->context.execute_only_pkey;
Ideally we'd actually do it in the inline so that the function call to arch_dup_pkeys() can be avoided. But it looks like header dependencies might make that hard.
cheers
Quoted 11 lines · Michael Ellerman
Hi Ram,
Thanks for fixing this.
Quoted 6 lines · Ram Pai
arch/powerpc/mm/pkeys.c +0
-0@@ -414,3 +414,10 @@ bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write,
Quoted 11 lines
arch/powerpc/mm/pkeys.c bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write, · line 423
Quoted 9 lines
arch/powerpc/mm/pkeys.c +7
-0return pkey_access_permitted (vma_pkey (vma), write, execute); } + +void arch_dup_pkeys (struct mm_struct *oldmm,struct mm_struct *mm) +{ +/* Duplicate the oldmm pkey state in mm: */ +mm_pkey_allocation_map (mm) =mm_pkey_allocation_map (oldmm); + mm->context.execute_only_pkey = oldmm->context.execute_only_pkey; +}Shouldn't this check if pkeys are actually in use?
Yes. That will make it better. However not checking it, will not hurt. Just that it will do some unnecessary copying.
Will spin out a new patch with the fix, and send it your way. RP
Quoted 24 lines
eg:
arch/powerpc/mm/pkeys.c +3
-0@@ -418,6 +418,9 @@ bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write,void arch_dup_pkeys (struct mm_struct *oldmm,struct mm_struct *mm) { +if (static_branch_likely (&pkey_disabled)) +return ; +/* Duplicate the oldmm pkey state in mm: */ mm_pkey_allocation_map (mm) =mm_pkey_allocation_map (oldmm); mm->context.execute_only_pkey = oldmm->context.execute_only_pkey;Ideally we'd actually do it in the inline so that the function call to
arch_dup_pkeys()can be avoided. But it looks like header dependencies might make that hard.cheers
Signature · 1 line
Ram Pai
PATCH v2 1/1 powerpc/pkeys: copy pkey-tracking-information at fork()
In reply to Michael EllermanPkey tracking information is not copied over to the mm_struct of the child during fork(). This can cause the child to erroneously allocate keys that were already allocated. Any allocated execute-only key is lost aswell.
Add code; called by dup_mmap(), to copy the pkey state from parent to child explicitly.
This problem was originally found by Dave Hansen on x86, which turns out to be a problem on powerpc aswell.
v2: do not copy if pkeys is disabled.
-- comment by Michael Ellermen
arch/powerpc/include/asm/mmu_context.h +9 -6
@@ -217,12 +217,6 @@ static inline void enter_lazy_tlb(struct mm_struct *mm,#endif } -static inline int arch_dup_mmap (struct mm_struct *oldmm, -struct mm_struct *mm) -{ -return 0 ; -} -#ifndef CONFIG_PPC_BOOK3S_64 static inline void arch_exit_mmap (struct mm_struct *mm) {
@@ -247,6 +241,7 @@ static inline void arch_bprm_mm_init(struct mm_struct *mm,#ifdef CONFIG_PPC_MEM_KEYS bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write,bool execute,bool foreign); +void arch_dup_pkeys (struct mm_struct *oldmm,struct mm_struct *mm);#else /* CONFIG_PPC_MEM_KEYS */ static inline bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write,bool execute,bool foreign)
@@ -259,6 +254,7 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,#define thread_pkey_regs_save (thread)#define thread_pkey_regs_restore (new_thread, old_thread)#define thread_pkey_regs_init (thread) +#define arch_dup_pkeys (oldmm, mm)static inline u64 pte_to_hpte_pkey_bits (u64 pteflags) {
@@ -267,5 +263,12 @@ static inline u64 pte_to_hpte_pkey_bits(u64 pteflags)#endif /* CONFIG_PPC_MEM_KEYS */ +static inline int arch_dup_mmap (struct mm_struct *oldmm, +struct mm_struct *mm) +{ +arch_dup_pkeys (oldmm, mm); +return 0 ; +} +#endif /* __KERNEL__ */ #endif /* __ASM_POWERPC_MMU_CONTEXT_H */
arch/powerpc/mm/pkeys.c +10 -0
@@ -414,3 +414,13 @@ bool arch_vma_access_permitted(struct vm_area_struct *vma, bool write,return pkey_access_permitted (vma_pkey (vma), write, execute); } + +void arch_dup_pkeys (struct mm_struct *oldmm,struct mm_struct *mm) +{ +if (static_branch_likely (&pkey_disabled)) +return ; + +/* Duplicate the oldmm pkey state in mm: */ +mm_pkey_allocation_map (mm) =mm_pkey_allocation_map (oldmm); + mm->context.execute_only_pkey = oldmm->context.execute_only_pkey; +}
Michael Ellerman
reviewerQuoted 8 lines · Ram Pai
Pkey tracking information is not copied over to the
mm_structof the child duringfork(). This can cause the child to erroneously allocate keys that were already allocated. Any allocated execute-only key is lost aswell.Add code; called by
dup_mmap(), to copy the pkey state from parent to child explicitly.
Quoted 8 lines
This problem was originally found by Dave Hansen on x86, which turns out to be a problem on powerpc aswell.
Reviewed-by Thiago Jung Bauermann <[email protected]>Signed-off-by Ram Pai <[email protected]>v2: do not copy if pkeys is disabled.
-- comment by Michael Ellermen
Thanks.
I changed the subject to:
powerpc/pkeys: Fix handling of pkey state across fork()
And added tags:
cheers
Michael Ellerman
AppliedQuoted 5 lines · Ram Pai
Pkey tracking information is not copied over to the
mm_structof the child duringfork(). This can cause the child to erroneously allocate keys that were already allocated. Any allocated execute-only key is lost aswell.
Quoted 8 lines
Add code; called by
dup_mmap(), to copy the pkey state from parent to child explicitly.This problem was originally found by Dave Hansen on x86, which turns out to be a problem on powerpc aswell.
Reviewed-by Thiago Jung Bauermann <[email protected]>Signed-off-by Ram Pai <[email protected]>
Applied to powerpc next, thanks.
https://git.kernel.org/powerpc/c/2cd4bd192ee94848695c1c052d8791
cheers