x86: Memory Protection Keys (v10)
Subsystems (43)
cover x86: Memory Protection Keys (v10)
Memory Protection Keys for User pages is a CPU feature which will first appear on Skylake Servers, but will also be supported on future non-server parts (there is also a QEMU implementation). It provides a mechanism for enforcing page-based protections, but without requiring modification of the page tables when an application changes wishes to change permissions.
This set introduces supported limited to:
1. Allows "execute-only" memory
2. Enables KVM to run Protection-Key-enabled guests
This set contains the vast majority of of the code, with the small but tricky explicit user interface parts left off. We can have a more focused review on those at a later time in a (much smaller) follow-on series.
Changes from v9:
* Added macros to allow some source-level backward compatability between the old-style get_user_pages*() calls taking tsk/mm and the new-style which assumes the current tsk/mm.
* renamed the new gup variant to get_user_pages_remote() instead of get_user_pages_foreign()
* rebased against 4.5-rc3
Changes from v8:
* Reorganization of get_user_pages() patch with awesome feedback from Vlastimil Babka and suggestions from Jan Kara.
* fix EXPORT_SYMBOL() and use get_current_user_page() in nommu.c
Changes from v7:
* Fixed merge issue with cpu feature bitmap definitions
* Fixed up some comments in get_user_pages() and smaps patches (thanks Vlastimil!)
Changes from v6:
* fix up ??'s showing up in in smaps' VmFlags field
* added execute-only support
* removed all the new syscalls from this set. We can discuss them in detail after this is merged.
Changes from v5:
* make types in read_pkru() u32's, not ints
* rework VM_* bits to avoid using __ffsl() and clean up vma_pkey()
* rework pte_allows_gup() to use p??_val() instead of passing around p{te,md,ud}_t types.
* Fix up some inconsistent bool vs. int usage
* corrected name of ARCH_VM_PKEY_FLAGS in patch description
* remove NR_PKEYS... config option. Just define it directly
Changes from v4:
* Made "allow setting of XSAVE state" safe if we got preempted between when we saved our FPU state and when we restore it. (I would appreciate a look from Ingo on this patch).
* Fixed up a few things from Thomas's latest comments: splt up siginfo in to x86 and generic, removed extra 'eax' variable in rdpkru function, reworked vm_flags assignment, reworded a comment in pte_allows_gup()
* Add missing DISABLED/REQUIRED_MASK14 in cpufeature.h
* Added comment about compile optimization in fault path
* Left get_user_pages_locked() alone. Andrea thinks we need it.
Changes from RFCv3:
* Added 'current' and 'foreign' variants of get_user_pages() to help indicate whether protection keys should be enforced. Thanks to Jerome Glisse for pointing out this issue.
* Added "allocation" and set/get system calls so that we can do management of proection keys in the kernel. This opens the door to use of specific protection keys for kernel use in the future, such as for execute-only memory.
* Removed the kselftest code for the moment. It will be submitted separately.
Thanks Ingo and Thomas for most of these):
Changes from RFCv2 (Thanks Ingo and Thomas for most of these):
* few minor compile warnings
* changed 'nopku' interaction with cpuid bits. Now, we do not clear the PKU cpuid bit, we just skip enabling it.
* changed __pkru_allows_write() to also check access disable bit
* removed the unused write_pkru()
* made si_pkey a u64 and added some patch description details. Also made it share space in siginfo with MPX and clarified comments.
* give some real text for the Processor Trace xsave state
* made vma_pkey() less ugly (and much more optimized actually)
* added SEGV_PKUERR to copy_siginfo_to_user()
* remove page table walk when filling in si_pkey, added some big fat comments about it being inherently racy.
* added self test code
This code is not runnable to anyone outside of Intel unless they have some special hardware or a fancy simulator. There is a qemu model to emulate the feature, but it is not currently implemented fully enough to be usable. If you are interested in running this for real, please get in touch with me. Hardware is available to a very small but nonzero number of people.
This set is also available here:
git://git.kernel.org/pub/scm/linux/kernel/git/daveh/x86-pkeys.git pkeys-v024
=== diffstat ===
Dave Hansen (33):
mm: introduce get_user_pages_remote()
mm: overload get_user_pages() functions
mm, gup: switch callers of get_user_pages() to not pass tsk/mm x86, fpu: add placeholder for Processor Trace XSAVE state x86, pkeys: Add Kconfig option
x86, pkeys: cpuid bit definition
x86, pkeys: define new CR4 bit
x86, pkeys: add PKRU xsave fields and data structure(s) x86, pkeys: PTE bits for storing protection key
x86, pkeys: new page fault error code bit: PF_PK
x86, pkeys: store protection in high VMA flags
x86, pkeys: arch-specific protection bits
x86, pkeys: pass VMA down in to fault signal generation code signals, pkeys: notify userspace about protection key faults x86, pkeys: fill in pkey field in siginfo
x86, pkeys: add functions to fetch PKRU
mm: factor out VMA fault permission checking
x86, mm: simplify get_user_pages() PTE bit handling x86, pkeys: check VMAs and PTEs for protection keys
mm: do not enforce PKEY permissions on "foreign" mm access x86, pkeys: optimize fault handling in access_error() x86, pkeys: differentiate instruction fetches
x86, pkeys: dump PKRU with other kernel registers x86, pkeys: dump pkey from VMA in /proc/pid/smaps x86, pkeys: add Kconfig prompt to existing config option x86, pkeys: actually enable Memory Protection Keys in CPU mm, multi-arch: pass a protection key in to calc_vm_flag_bits() x86, pkeys: add arch_validate_pkey()
x86: separate out LDT init from context init
x86, fpu: allow setting of XSAVE state
x86, pkeys: allow kernel to modify user pkey rights register x86, pkeys: create an x86 arch_calc_vm_prot_bits() for VMA flags x86, pkeys: execute-only support
Documentation/kernel-parameters.txt | 3 + arch/cris/arch-v32/drivers/cryptocop.c | 8 +- arch/ia64/kernel/err_inject.c | 3 +- arch/mips/mm/gup.c | 3 +- arch/powerpc/include/asm/mman.h | 5 +- arch/powerpc/include/asm/mmu_context.h | 12 ++ arch/s390/include/asm/mmu_context.h | 12 ++ arch/s390/mm/gup.c | 4 +- arch/sh/mm/gup.c | 2 +- arch/sparc/mm/gup.c | 2 +- arch/unicore32/include/asm/mmu_context.h | 12 ++ arch/x86/Kconfig | 16 ++ arch/x86/include/asm/cpufeature.h | 61 ++++--- arch/x86/include/asm/disabled-features.h | 15 ++ arch/x86/include/asm/fpu/internal.h | 2 + arch/x86/include/asm/fpu/types.h | 12 ++ arch/x86/include/asm/fpu/xstate.h | 3 +- arch/x86/include/asm/mmu_context.h | 85 ++++++++- arch/x86/include/asm/pgtable.h | 38 ++++ arch/x86/include/asm/pgtable_types.h | 39 ++++- arch/x86/include/asm/pkeys.h | 34 ++++ arch/x86/include/asm/required-features.h | 7 + arch/x86/include/asm/special_insns.h | 22 +++ arch/x86/include/uapi/asm/mman.h | 22 +++ arch/x86/include/uapi/asm/processor-flags.h | 2 + arch/x86/kernel/cpu/common.c | 42 +++++ arch/x86/kernel/fpu/core.c | 63 +++++++ arch/x86/kernel/fpu/xstate.c | 185 +++++++++++++++++++- arch/x86/kernel/ldt.c | 4 +- arch/x86/kernel/process_64.c | 2 + arch/x86/kernel/setup.c | 9 + arch/x86/mm/Makefile | 2 + arch/x86/mm/fault.c | 168 +++++++++++++++--- arch/x86/mm/gup.c | 45 +++-- arch/x86/mm/mpx.c | 4 +- arch/x86/mm/pkeys.c | 101 +++++++++++ drivers/char/agp/frontend.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 3 +- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 6 +- drivers/gpu/drm/i915/i915_gem_userptr.c | 10 +- drivers/gpu/drm/radeon/radeon_ttm.c | 3 +- drivers/gpu/drm/via/via_dmablit.c | 3 +- drivers/infiniband/core/umem.c | 2 +- drivers/infiniband/core/umem_odp.c | 8 +- drivers/infiniband/hw/mthca/mthca_memfree.c | 3 +- drivers/infiniband/hw/qib/qib_user_pages.c | 3 +- drivers/infiniband/hw/usnic/usnic_uiom.c | 2 +- drivers/iommu/amd_iommu_v2.c | 1 + drivers/media/pci/ivtv/ivtv-udma.c | 4 +- drivers/media/pci/ivtv/ivtv-yuv.c | 10 +- drivers/media/v4l2-core/videobuf-dma-sg.c | 3 +- drivers/misc/mic/scif/scif_rma.c | 2 - drivers/misc/sgi-gru/grufault.c | 3 +- drivers/scsi/st.c | 2 - drivers/staging/android/ashmem.c | 4 +- drivers/video/fbdev/pvr2fb.c | 4 +- drivers/virt/fsl_hypervisor.c | 5 +- fs/exec.c | 8 +- fs/proc/task_mmu.c | 14 ++ include/asm-generic/mm_hooks.h | 12 ++ include/linux/mm.h | 102 +++++++++-- include/linux/mman.h | 6 +- include/linux/pkeys.h | 33 ++++ include/uapi/asm-generic/siginfo.h | 17 +- kernel/events/uprobes.c | 10 +- kernel/signal.c | 4 + mm/Kconfig | 5 + mm/frame_vector.c | 2 +- mm/gup.c | 127 +++++++++++--- mm/ksm.c | 12 +- mm/memory.c | 8 +- mm/mempolicy.c | 6 +- mm/mmap.c | 10 +- mm/mprotect.c | 8 +- mm/nommu.c | 66 ++++--- mm/process_vm_access.c | 11 +- mm/util.c | 4 +- net/ceph/pagevec.c | 2 +- security/tomoyo/domain.c | 9 +- virt/kvm/async_pf.c | 8 +- virt/kvm/kvm_main.c | 10 +- 81 files changed, 1393 insertions(+), 233 deletions(-)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/33 mm: introduce get_user_pages_remote()
From: Dave Hansen <[email protected]>
For protection keys, we need to understand whether protections should be enforced in software or not. In general, we enforce protections when working on our own task, but not when on others. We call these "current" and "remote" operations.
This patch introduces a new get_user_pages() variant:
get_user_pages_remote()
Which is a replacement for when get_user_pages() is called on non-current tsk/mm.
We also introduce a new gup flag: FOLL_REMOTE which can be used for the "__" gup variants to get this new behavior.
The uprobes is_trap_at_addr() location holds mmap_sem and calls get_user_pages(current->mm) on an instruction address. This makes it a pretty unique gup caller. Being an instruction access and also really originating from the kernel (vs. the app), I opted to consider this a 'remote' access where protection keys will not be enforced.
Without protection keys, this patch should not change any behavior.
---
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c | 6 +++--- b/drivers/gpu/drm/i915/i915_gem_userptr.c | 10 +++++----- b/drivers/infiniband/core/umem_odp.c | 8 ++++---- b/fs/exec.c | 8 ++++++-- b/include/linux/mm.h | 5 +++++ b/kernel/events/uprobes.c | 10 ++++++++-- b/mm/gup.c | 27 ++++++++++++++++++++++----- b/mm/memory.c | 2 +- b/mm/process_vm_access.c | 11 ++++++++--- b/security/tomoyo/domain.c | 9 ++++++++- b/virt/kvm/async_pf.c | 8 +++++++- 11 files changed, 77 insertions(+), 27 deletions(-)
drivers/gpu/drm/etnaviv/etnaviv_gem.c renamed from drivers/gpu/drm/etnaviv/etnaviv_gem.c~introduce-get_user_pages_remote +3 -3
@@ -753,9 +753,9 @@ static struct page **etnaviv_gem_userptrdown_read (&mm->mmap_sem);while (pinned < npages) { - ret =get_user_pages (task, mm, ptr, npages - pinned, - !etnaviv_obj->userptr.ro,0 , - pvec + pinned,NULL ); + ret =get_user_pages_remote (task, mm, ptr, npages - pinned, + !etnaviv_obj->userptr.ro,0 , + pvec + pinned,NULL );if (ret <0 )break ;
drivers/gpu/drm/i915/i915_gem_userptr.c renamed from drivers/gpu/drm/i915/i915_gem_userptr.c~introduce-get_user_pages_remote +5 -5
@@ -584,11 +584,11 @@ __i915_gem_userptr_get_pages_worker(strudown_read (&mm->mmap_sem);while (pinned < npages) { - ret =get_user_pages (work->task, mm, - obj->userptr.ptr + pinned *PAGE_SIZE , - npages - pinned, - !obj->userptr.read_only,0 , - pvec + pinned,NULL ); + ret =get_user_pages_remote (work->task, mm, + obj->userptr.ptr + pinned *PAGE_SIZE , + npages - pinned, + !obj->userptr.read_only,0 , + pvec + pinned,NULL );if (ret <0 )break ;
drivers/infiniband/core/umem_odp.c renamed from drivers/infiniband/core/umem_odp.c~introduce-get_user_pages_remote +4 -4
@@ -572,10 +572,10 @@ int ib_umem_odp_map_dma_pages(struct ib_* complex (and doesn't gain us much performance in most use * cases). */ - npages =get_user_pages (owning_process, owning_mm, user_virt, - gup_num_pages, - access_mask &ODP_WRITE_ALLOWED_BIT ,0 , - local_page_list,NULL ); + npages =get_user_pages_remote (owning_process, owning_mm, + user_virt, gup_num_pages, + access_mask &ODP_WRITE_ALLOWED_BIT , +0 , local_page_list,NULL );up_read (&owning_mm->mmap_sem);if (npages <0 )
fs/exec.c renamed from fs/exec.c~introduce-get_user_pages_remote +6 -2
@@ -198,8 +198,12 @@ static struct page *get_arg_page(struct return NULL; }#endif - ret =get_user_pages (current, bprm->mm, pos, -1 , write,1 , &page,NULL ); +/* +* We are doing an exec(). 'current' is the process +* doing the exec and bprm->mm is the new process's mm. +*/ + ret =get_user_pages_remote (current, bprm->mm, pos,1 , write, +1 , &page,NULL );if (ret <=0 )return NULL ;
include/linux/mm.h renamed from include/linux/mm.h~introduce-get_user_pages_remote +5 -0
@@ -1225,6 +1225,10 @@ long __get_user_pages(struct task_struct unsigned long start, unsigned long nr_pages, unsigned int foll_flags, struct page **pages, struct vm_area_struct **vmas, int *nonblocking); +long get_user_pages_remote (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages, +struct vm_area_struct **vmas); long get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, int write, int force, struct page **pages,
@@ -2168,6 +2172,7 @@ static inline struct page *follow_page(s#define FOLL_MIGRATION 0x400/* wait for page to replace migration entry */ #define FOLL_TRIED 0x800/* a retry, previous pass started an IO */ #define FOLL_MLOCK 0x1000/* lock present pages */ +#define FOLL_REMOTE 0x2000/* we are working on non-current tsk/mm */ typedef int (*pte_fn_t )(pte_t *pte,pgtable_t token,unsigned long addr,void *data);
kernel/events/uprobes.c renamed from kernel/events/uprobes.c~introduce-get_user_pages_remote +8 -2
@@ -299,7 +299,7 @@ int uprobe_write_opcode(struct mm_struct retry:/* Read the page with vaddr into memory */ - ret =get_user_pages (NULL , mm, vaddr,1 ,0 ,1 , &old_page, &vma); + ret =get_user_pages_remote (NULL , mm, vaddr,1 ,0 ,1 , &old_page, &vma);if (ret <=0 )return ret;
@@ -1700,7 +1700,13 @@ static int is_trap_at_addr(struct mm_strif (likely (result ==0 )) goto out; - result =get_user_pages (NULL , mm, vaddr,1 ,0 ,1 , &page,NULL ); +/* +* The NULL 'tsk' here ensures that any faults that occur here +* will not be accounted to the task. 'mm' *is* current->mm, +* but we treat this as a 'remote' access since it is +* essentially a kernel access to the memory. +*/ + result =get_user_pages_remote (NULL , mm, vaddr,1 ,0 ,1 , &page,NULL );if (result <0 )return result;
mm/gup.c renamed from mm/gup.c~introduce-get_user_pages_remote +22 -5
@@ -870,7 +870,7 @@ long get_user_pages_unlocked(struct taskEXPORT_SYMBOL (get_user_pages_unlocked);/* -* get_user_pages() - pin user pages in memory +* get_user_pages_remote() - pin user pages in memory * @tsk: the task_struct to use for page fault accounting, or * NULL if faults are not to be recorded. * @mm: mm_struct of target mm
@@ -924,12 +924,29 @@ EXPORT_SYMBOL(get_user_pages_unlocked);* should use get_user_pages because it cannot pass * FAULT_FLAG_ALLOW_RETRY to handle_mm_fault. */ -long get_user_pages (struct task_struct *tsk,struct mm_struct *mm, -unsigned long start,unsigned long nr_pages,int write, -int force,struct page **pages,struct vm_area_struct **vmas) +long get_user_pages_remote (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages, +struct vm_area_struct **vmas) {return __get_user_pages_locked (tsk, mm, start, nr_pages, write, force, - pages, vmas,NULL , false,FOLL_TOUCH ); + pages, vmas,NULL , false, +FOLL_TOUCH |FOLL_REMOTE ); +} +EXPORT_SYMBOL (get_user_pages_remote); + +/* +* This is the same as get_user_pages_remote() for the time +* being. +*/ +long get_user_pages (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages, +struct vm_area_struct **vmas) +{ +return __get_user_pages_locked (tsk, mm, start, nr_pages, + write, force, pages, vmas,NULL , false, +FOLL_TOUCH ); }EXPORT_SYMBOL (get_user_pages);
mm/memory.c renamed from mm/memory.c~introduce-get_user_pages_remote +1 -1
@@ -3664,7 +3664,7 @@ static int __access_remote_vm(struct tasvoid *maddr;struct page *page =NULL ; - ret =get_user_pages (tsk, mm, addr,1 , + ret =get_user_pages_remote (tsk, mm, addr,1 , write,1 , &page, &vma);if (ret <=0 ) {#ifndef CONFIG_HAVE_IOREMAP_PROT
mm/process_vm_access.c renamed from mm/process_vm_access.c~introduce-get_user_pages_remote +8 -3
@@ -98,9 +98,14 @@ static int process_vm_rw_single_vec(unsiint pages =min (nr_pages, max_pages_per_loop);size_t bytes; -/* Get the pages we're interested in */ - pages =get_user_pages_unlocked (task, mm, pa, pages, - vm_write,0 , process_pages); +/* +* Get the pages we're interested in. We must +* add FOLL_REMOTE because task/mm might not +* current/current->mm +*/ + pages =__get_user_pages_unlocked (task, mm, pa, pages, + vm_write,0 , process_pages, +FOLL_REMOTE );if (pages <=0 )return -EFAULT ;
security/tomoyo/domain.c renamed from security/tomoyo/domain.c~introduce-get_user_pages_remote +8 -1
@@ -874,7 +874,14 @@ bool tomoyo_dump_page(struct linux_binpr }/* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */ #ifdef CONFIG_MMU -if (get_user_pages (current, bprm->mm, pos,1 ,0 ,1 , &page,NULL ) <=0 ) +/* +* This is called at execve() time in order to dig around +* in the argv/environment of the new proceess +* (represented by bprm). 'current' is the process doing +* the execve(). +*/ +if (get_user_pages_remote (current, bprm->mm, pos,1 , +0 ,1 , &page,NULL ) <=0 )return false;#else page = bprm->page[pos /PAGE_SIZE ];
virt/kvm/async_pf.c renamed from virt/kvm/async_pf.c~introduce-get_user_pages_remote +7 -1
@@ -79,7 +79,13 @@ static void async_pf_execute(struct workmight_sleep (); -get_user_pages_unlocked (NULL , mm, addr,1 ,1 ,0 ,NULL ); +/* +* This work is run asynchromously to the task which owns +* mm and might be done in another context, so we must +* use FOLL_REMOTE. +*/ +__get_user_pages_unlocked (NULL , mm, addr,1 ,1 ,0 ,NULL ,FOLL_REMOTE ); +kvm_async_page_present_sync (vcpu, apf);spin_lock (&vcpu->async_pf.lock);
_
Re: [PATCH 01/33] mm: introduce get_user_pages_remote()
Quoted 7 lines · Dave Hansen
From: Dave Hansen <[email protected]>
For protection keys, we need to understand whether protections should be enforced in software or not.A A In general, we enforce protections when working on our own task, but not when on others. We call these "current" and "remote" operations.
Quoted 7 lines
This patch introduces a new
get_user_pages()variant:A A A A A A A A
get_user_pages_remote()Which is a replacement for when
get_user_pages()is called on non-current tsk/mm.
In summary then get_user_pages_remote() do not enforce protections?
Balbir Singh.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 01/33] mm: introduce get_user_pages_remote()
Quoted 5 lines · Balbir Singh
Quoted 5 lines
Quoted 5 lines
For protection keys, we need to understand whether protections should be enforced in software or not. In general, we enforce protections when working on our own task, but not when on others. We call these "current" and "remote" operations.
Quoted 8 lines
Quoted 7 lines
Quoted 7 lines
This patch introduces a new
get_user_pages()variant:
get_user_pages_remote()Which is a replacement for when
get_user_pages()is called on non-current tsk/mm.In summary then
get_user_pages_remote()do not enforce protections?
Yes, exactly.
Re: [PATCH 01/33] mm: introduce get_user_pages_remote()
In reply to Dave HansenQuoted 17 lines
diff -puN
kernel/events/uprobes.c~introduce-get_user_pages_remotekernel/events/uprobes.ckernel/events/uprobes.c renamed from kernel/events/uprobes.c~introduce-get_user_pages_remote +1
-2@@ -299,7 +299,7 @@ int uprobe_write_opcode(struct mm_struct retry:/* Read the page with vaddr into memory */ - ret =get_user_pages (NULL , mm, vaddr,1 ,0 ,1 , &old_page, &vma); + ret =get_user_pages_remote (NULL , mm, vaddr,1 ,0 ,1 , &old_page, &vma);if (ret <=0 )return ret;@@ -1700,7 +1700,13 @@ static int is_trap_at_addr(struct mm_strif (likely (result ==0 )) goto out; - result =get_user_pages (NULL , mm, vaddr,1 ,0 ,1 , &page,NULL );
kernel/events/uprobes.c static int is_trap_at_addr(struct mm_str · line 1712
Quoted 10 lines
kernel/events/uprobes.c renamed from kernel/events/uprobes.c~introduce-get_user_pages_remote +7
-0+/* +* The NULL 'tsk' here ensures that any faults that occur here +* will not be accounted to the task. 'mm' *is* current->mm, +* but we treat this as a 'remote' access since it is +* essentially a kernel access to the memory. +*/ + result =get_user_pages_remote (NULL , mm, vaddr,1 ,0 ,1 , &page,NULL );if (result <0 )return result;
Signature · 8 lines
Thanks and Regards Srikar Dronamraju -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:x86/pkeys] mm/gup: Introduce get_user_pages_remote()
In reply to Dave Hansenmm/gup: Introduce get_user_pages_remote()
Commit-ID: 1e9877902dc7e11d2be038371c6fbf2dfcd469d7 Gitweb: http://git.kernel.org/tip/1e9877902dc7e11d2be038371c6fbf2dfcd469d7 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:01:54 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 16 Feb 2016 10:04:09 +0100
mm/gup: Introduce get_user_pages_remote()
For protection keys, we need to understand whether protections should be enforced in software or not. In general, we enforce protections when working on our own task, but not when on others. We call these "current" and "remote" operations.
This patch introduces a new get_user_pages() variant:
get_user_pages_remote()
Which is a replacement for when get_user_pages() is called on non-current tsk/mm.
We also introduce a new gup flag: FOLL_REMOTE which can be used for the "__" gup variants to get this new behavior.
The uprobes is_trap_at_addr() location holds mmap_sem and calls get_user_pages(current->mm) on an instruction address. This makes it a pretty unique gup caller. Being an instruction access and also really originating from the kernel (vs. the app), I opted to consider this a 'remote' access where protection keys will not be enforced.
Without protection keys, this patch should not change any behavior.
--- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 6 +++--- drivers/gpu/drm/i915/i915_gem_userptr.c | 10 +++++----- drivers/infiniband/core/umem_odp.c | 8 ++++---- fs/exec.c | 8 ++++++-- include/linux/mm.h | 5 +++++ kernel/events/uprobes.c | 10 ++++++++-- mm/gup.c | 27 ++++++++++++++++++++++----- mm/memory.c | 2 +- mm/process_vm_access.c | 11 ++++++++--- security/tomoyo/domain.c | 9 ++++++++- virt/kvm/async_pf.c | 8 +++++++- 11 files changed, 77 insertions(+), 27 deletions(-)
drivers/gpu/drm/etnaviv/etnaviv_gem.c +3 -3
@@ -753,9 +753,9 @@ static struct page **etnaviv_gem_userptr_do_get_pages(down_read (&mm->mmap_sem);while (pinned < npages) { - ret =get_user_pages (task, mm, ptr, npages - pinned, - !etnaviv_obj->userptr.ro,0 , - pvec + pinned,NULL ); + ret =get_user_pages_remote (task, mm, ptr, npages - pinned, + !etnaviv_obj->userptr.ro,0 , + pvec + pinned,NULL );if (ret <0 )break ;
drivers/gpu/drm/i915/i915_gem_userptr.c +5 -5
@@ -584,11 +584,11 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)down_read (&mm->mmap_sem);while (pinned < npages) { - ret =get_user_pages (work->task, mm, - obj->userptr.ptr + pinned *PAGE_SIZE , - npages - pinned, - !obj->userptr.read_only,0 , - pvec + pinned,NULL ); + ret =get_user_pages_remote (work->task, mm, + obj->userptr.ptr + pinned *PAGE_SIZE , + npages - pinned, + !obj->userptr.read_only,0 , + pvec + pinned,NULL );if (ret <0 )break ;
drivers/infiniband/core/umem_odp.c +4 -4
@@ -572,10 +572,10 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,* complex (and doesn't gain us much performance in most use * cases). */ - npages =get_user_pages (owning_process, owning_mm, user_virt, - gup_num_pages, - access_mask &ODP_WRITE_ALLOWED_BIT ,0 , - local_page_list,NULL ); + npages =get_user_pages_remote (owning_process, owning_mm, + user_virt, gup_num_pages, + access_mask &ODP_WRITE_ALLOWED_BIT , +0 , local_page_list,NULL );up_read (&owning_mm->mmap_sem);if (npages <0 )
fs/exec.c +6 -2
@@ -198,8 +198,12 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, return NULL; }#endif - ret =get_user_pages (current, bprm->mm, pos, -1 , write,1 , &page,NULL ); +/* +* We are doing an exec(). 'current' is the process +* doing the exec and bprm->mm is the new process's mm. +*/ + ret =get_user_pages_remote (current, bprm->mm, pos,1 , write, +1 , &page,NULL );if (ret <=0 )return NULL ;
include/linux/mm.h +5 -0
@@ -1225,6 +1225,10 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, unsigned int foll_flags, struct page **pages, struct vm_area_struct **vmas, int *nonblocking); +long get_user_pages_remote (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages, +struct vm_area_struct **vmas); long get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, int write, int force, struct page **pages,
@@ -2170,6 +2174,7 @@ static inline struct page *follow_page(struct vm_area_struct *vma,#define FOLL_MIGRATION 0x400/* wait for page to replace migration entry */ #define FOLL_TRIED 0x800/* a retry, previous pass started an IO */ #define FOLL_MLOCK 0x1000/* lock present pages */ +#define FOLL_REMOTE 0x2000/* we are working on non-current tsk/mm */ typedef int (*pte_fn_t )(pte_t *pte,pgtable_t token,unsigned long addr,void *data);
kernel/events/uprobes.c +8 -2
@@ -299,7 +299,7 @@ int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, retry:/* Read the page with vaddr into memory */ - ret =get_user_pages (NULL , mm, vaddr,1 ,0 ,1 , &old_page, &vma); + ret =get_user_pages_remote (NULL , mm, vaddr,1 ,0 ,1 , &old_page, &vma);if (ret <=0 )return ret;
@@ -1700,7 +1700,13 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)if (likely (result ==0 )) goto out; - result =get_user_pages (NULL , mm, vaddr,1 ,0 ,1 , &page,NULL ); +/* +* The NULL 'tsk' here ensures that any faults that occur here +* will not be accounted to the task. 'mm' *is* current->mm, +* but we treat this as a 'remote' access since it is +* essentially a kernel access to the memory. +*/ + result =get_user_pages_remote (NULL , mm, vaddr,1 ,0 ,1 , &page,NULL );if (result <0 )return result;
mm/gup.c +22 -5
@@ -870,7 +870,7 @@ long get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,EXPORT_SYMBOL (get_user_pages_unlocked);/* -* get_user_pages() - pin user pages in memory +* get_user_pages_remote() - pin user pages in memory * @tsk: the task_struct to use for page fault accounting, or * NULL if faults are not to be recorded. * @mm: mm_struct of target mm
@@ -924,12 +924,29 @@ EXPORT_SYMBOL(get_user_pages_unlocked);* should use get_user_pages because it cannot pass * FAULT_FLAG_ALLOW_RETRY to handle_mm_fault. */ -long get_user_pages (struct task_struct *tsk,struct mm_struct *mm, -unsigned long start,unsigned long nr_pages,int write, -int force,struct page **pages,struct vm_area_struct **vmas) +long get_user_pages_remote (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages, +struct vm_area_struct **vmas) {return __get_user_pages_locked (tsk, mm, start, nr_pages, write, force, - pages, vmas,NULL , false,FOLL_TOUCH ); + pages, vmas,NULL , false, +FOLL_TOUCH |FOLL_REMOTE ); +} +EXPORT_SYMBOL (get_user_pages_remote); + +/* +* This is the same as get_user_pages_remote() for the time +* being. +*/ +long get_user_pages (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages, +struct vm_area_struct **vmas) +{ +return __get_user_pages_locked (tsk, mm, start, nr_pages, + write, force, pages, vmas,NULL , false, +FOLL_TOUCH ); }EXPORT_SYMBOL (get_user_pages);
mm/memory.c +1 -1
@@ -3685,7 +3685,7 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,void *maddr;struct page *page =NULL ; - ret =get_user_pages (tsk, mm, addr,1 , + ret =get_user_pages_remote (tsk, mm, addr,1 , write,1 , &page, &vma);if (ret <=0 ) {#ifndef CONFIG_HAVE_IOREMAP_PROT
mm/process_vm_access.c +8 -3
@@ -98,9 +98,14 @@ static int process_vm_rw_single_vec(unsigned long addr,int pages =min (nr_pages, max_pages_per_loop);size_t bytes; -/* Get the pages we're interested in */ - pages =get_user_pages_unlocked (task, mm, pa, pages, - vm_write,0 , process_pages); +/* +* Get the pages we're interested in. We must +* add FOLL_REMOTE because task/mm might not +* current/current->mm +*/ + pages =__get_user_pages_unlocked (task, mm, pa, pages, + vm_write,0 , process_pages, +FOLL_REMOTE );if (pages <=0 )return -EFAULT ;
security/tomoyo/domain.c +8 -1
@@ -874,7 +874,14 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos, }/* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */ #ifdef CONFIG_MMU -if (get_user_pages (current, bprm->mm, pos,1 ,0 ,1 , &page,NULL ) <=0 ) +/* +* This is called at execve() time in order to dig around +* in the argv/environment of the new proceess +* (represented by bprm). 'current' is the process doing +* the execve(). +*/ +if (get_user_pages_remote (current, bprm->mm, pos,1 , +0 ,1 , &page,NULL ) <=0 )return false;#else page = bprm->page[pos /PAGE_SIZE ];
virt/kvm/async_pf.c +7 -1
@@ -79,7 +79,13 @@ static void async_pf_execute(struct work_struct *work)might_sleep (); -get_user_pages_unlocked (NULL , mm, addr,1 ,1 ,0 ,NULL ); +/* +* This work is run asynchromously to the task which owns +* mm and might be done in another context, so we must +* use FOLL_REMOTE. +*/ +__get_user_pages_unlocked (NULL , mm, addr,1 ,1 ,0 ,NULL ,FOLL_REMOTE ); +kvm_async_page_present_sync (vcpu, apf);spin_lock (&vcpu->async_pf.lock);
Re: [tip:x86/pkeys] mm/gup: Introduce get_user_pages_remote()
Quoted 14 lines · tip-bot for Dave Hansen
Commit-ID: 1e9877902dc7e11d2be038371c6fbf2dfcd469d7 Gitweb: http://git.kernel.org/tip/1e9877902dc7e11d2be038371c6fbf2dfcd469d7 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:01:54 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 16 Feb 2016 10:04:09 +0100mm/gup: Introduce
get_user_pages_remote()For protection keys, we need to understand whether protections should be enforced in software or not. In general, we enforce protections when working on our own task, but not when on others. We call these "current" and "remote" operations.
Quoted 6 lines
This patch introduces a new
get_user_pages()variant:
get_user_pages_remote()Which is a replacement for when
get_user_pages()is called on non-current tsk/mm.
As I see task-struct argument could be NULL as well as in old api. They only usage for it is updating task->maj_flt/min_flt.
May be just remove arg and always account major/minor faults into current task - currently counters are plain unsigned long, so remote access could corrupt them.
Quoted 296 lines
We also introduce a new gup flag:
FOLL_REMOTEwhich can be used for the "__" gup variants to get this new behavior.The uprobes
is_trap_at_addr()location holdsmmap_semand callsget_user_pages(current->mm)on an instruction address. This makes it a pretty unique gup caller. Being an instruction access and also really originating from the kernel (vs. the app), I opted to consider this a 'remote' access where protection keys will not be enforced.Without protection keys, this patch should not change any behavior.
Signed-off-by Dave Hansen <[email protected]>Reviewed-by Thomas Gleixner <[email protected]>Cc Andrea Arcangeli <[email protected]>Cc Andrew Morton <[email protected]>Cc Andy Lutomirski <[email protected]>Cc Borislav Petkov <[email protected]>Cc Brian Gerst <[email protected]>Cc Dave Hansen <[email protected]>Cc Denys Vlasenko <[email protected]>Cc H. Peter Anvin <[email protected]>Cc Kirill A. Shutemov <[email protected]>Cc Linus Torvalds <[email protected]>Cc Naoya Horiguchi <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Rik van Riel <[email protected]>Cc Srikar Dronamraju <[email protected]>Cc Vlastimil Babka <[email protected]>Signed-off-by Ingo Molnar <[email protected]>--- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 6 +++--- drivers/gpu/drm/i915/i915_gem_userptr.c | 10 +++++----- drivers/infiniband/core/umem_odp.c | 8 ++++---- fs/exec.c | 8 ++++++-- include/linux/mm.h | 5 +++++ kernel/events/uprobes.c | 10 ++++++++-- mm/gup.c | 27 ++++++++++++++++++++++----- mm/memory.c | 2 +- mm/process_vm_access.c | 11 ++++++++--- security/tomoyo/domain.c | 9 ++++++++- virt/kvm/async_pf.c | 8 +++++++- 11 files changed, 77 insertions(+), 27 deletions(-)drivers/gpu/drm/etnaviv/etnaviv_gem.c +3
-3@@ -753,9 +753,9 @@ static struct page **etnaviv_gem_userptr_do_get_pages(down_read (&mm->mmap_sem);while (pinned < npages) { - ret =get_user_pages (task, mm, ptr, npages - pinned, - !etnaviv_obj->userptr.ro,0 , - pvec + pinned,NULL ); + ret =get_user_pages_remote (task, mm, ptr, npages - pinned, + !etnaviv_obj->userptr.ro,0 , + pvec + pinned,NULL );if (ret <0 )break ;drivers/gpu/drm/i915/i915_gem_userptr.c +5
-5@@ -584,11 +584,11 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)down_read (&mm->mmap_sem);while (pinned < npages) { - ret =get_user_pages (work->task, mm, - obj->userptr.ptr + pinned *PAGE_SIZE , - npages - pinned, - !obj->userptr.read_only,0 , - pvec + pinned,NULL ); + ret =get_user_pages_remote (work->task, mm, + obj->userptr.ptr + pinned *PAGE_SIZE , + npages - pinned, + !obj->userptr.read_only,0 , + pvec + pinned,NULL );if (ret <0 )break ;drivers/infiniband/core/umem_odp.c +4
-4@@ -572,10 +572,10 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,* complex (and doesn't gain us much performance in most use * cases). */ - npages =get_user_pages (owning_process, owning_mm, user_virt, - gup_num_pages, - access_mask &ODP_WRITE_ALLOWED_BIT ,0 , - local_page_list,NULL ); + npages =get_user_pages_remote (owning_process, owning_mm, + user_virt, gup_num_pages, + access_mask &ODP_WRITE_ALLOWED_BIT , +0 , local_page_list,NULL );up_read (&owning_mm->mmap_sem);if (npages <0 )fs/exec.c +6
-2@@ -198,8 +198,12 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, return NULL; }#endif - ret =get_user_pages (current, bprm->mm, pos, -1 , write,1 , &page,NULL ); +/* +* We are doing an exec(). 'current' is the process +* doing the exec and bprm->mm is the new process's mm. +*/ + ret =get_user_pages_remote (current, bprm->mm, pos,1 , write, +1 , &page,NULL );if (ret <=0 )return NULL ;include/linux/mm.h +5
-0@@ -1225,6 +1225,10 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, unsigned int foll_flags, struct page **pages, struct vm_area_struct **vmas, int *nonblocking); +long get_user_pages_remote (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages, +struct vm_area_struct **vmas); long get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, int write, int force, struct page **pages,@@ -2170,6 +2174,7 @@ static inline struct page *follow_page(struct vm_area_struct *vma,#define FOLL_MIGRATION 0x400/* wait for page to replace migration entry */ #define FOLL_TRIED 0x800/* a retry, previous pass started an IO */ #define FOLL_MLOCK 0x1000/* lock present pages */ +#define FOLL_REMOTE 0x2000/* we are working on non-current tsk/mm */ typedef int (*pte_fn_t )(pte_t *pte,pgtable_t token,unsigned long addr,void *data);kernel/events/uprobes.c +8
-2@@ -299,7 +299,7 @@ int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, retry:/* Read the page with vaddr into memory */ - ret =get_user_pages (NULL , mm, vaddr,1 ,0 ,1 , &old_page, &vma); + ret =get_user_pages_remote (NULL , mm, vaddr,1 ,0 ,1 , &old_page, &vma);if (ret <=0 )return ret;@@ -1700,7 +1700,13 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)if (likely (result ==0 )) goto out; - result =get_user_pages (NULL , mm, vaddr,1 ,0 ,1 , &page,NULL ); +/* +* The NULL 'tsk' here ensures that any faults that occur here +* will not be accounted to the task. 'mm' *is* current->mm, +* but we treat this as a 'remote' access since it is +* essentially a kernel access to the memory. +*/ + result =get_user_pages_remote (NULL , mm, vaddr,1 ,0 ,1 , &page,NULL );if (result <0 )return result;mm/gup.c +22
-5@@ -870,7 +870,7 @@ long get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,EXPORT_SYMBOL (get_user_pages_unlocked);/* -* get_user_pages() - pin user pages in memory +* get_user_pages_remote() - pin user pages in memory * @tsk: the task_struct to use for page fault accounting, or * NULL if faults are not to be recorded. * @mm: mm_struct of target mm @@ -924,12 +924,29 @@ EXPORT_SYMBOL(get_user_pages_unlocked);* should use get_user_pages because it cannot pass * FAULT_FLAG_ALLOW_RETRY to handle_mm_fault. */ -long get_user_pages (struct task_struct *tsk,struct mm_struct *mm, -unsigned long start,unsigned long nr_pages,int write, -int force,struct page **pages,struct vm_area_struct **vmas) +long get_user_pages_remote (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages, +struct vm_area_struct **vmas) {return __get_user_pages_locked (tsk, mm, start, nr_pages, write, force, - pages, vmas,NULL , false,FOLL_TOUCH ); + pages, vmas,NULL , false, +FOLL_TOUCH |FOLL_REMOTE ); +} +EXPORT_SYMBOL (get_user_pages_remote); + +/* +* This is the same as get_user_pages_remote() for the time +* being. +*/ +long get_user_pages (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages, +struct vm_area_struct **vmas) +{ +return __get_user_pages_locked (tsk, mm, start, nr_pages, + write, force, pages, vmas,NULL , false, +FOLL_TOUCH ); }EXPORT_SYMBOL (get_user_pages);mm/memory.c +1
-1@@ -3685,7 +3685,7 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,void *maddr;struct page *page =NULL ; - ret =get_user_pages (tsk, mm, addr,1 , + ret =get_user_pages_remote (tsk, mm, addr,1 , write,1 , &page, &vma);if (ret <=0 ) {#ifndef CONFIG_HAVE_IOREMAP_PROT mm/process_vm_access.c +8
-3@@ -98,9 +98,14 @@ static int process_vm_rw_single_vec(unsigned long addr,int pages =min (nr_pages, max_pages_per_loop);size_t bytes; -/* Get the pages we're interested in */ - pages =get_user_pages_unlocked (task, mm, pa, pages, - vm_write,0 , process_pages); +/* +* Get the pages we're interested in. We must +* add FOLL_REMOTE because task/mm might not +* current/current->mm +*/ + pages =__get_user_pages_unlocked (task, mm, pa, pages, + vm_write,0 , process_pages, +FOLL_REMOTE );if (pages <=0 )return -EFAULT ;security/tomoyo/domain.c +8
-1@@ -874,7 +874,14 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos, }/* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */ #ifdef CONFIG_MMU -if (get_user_pages (current, bprm->mm, pos,1 ,0 ,1 , &page,NULL ) <=0 ) +/* +* This is called at execve() time in order to dig around +* in the argv/environment of the new proceess +* (represented by bprm). 'current' is the process doing +* the execve(). +*/ +if (get_user_pages_remote (current, bprm->mm, pos,1 , +0 ,1 , &page,NULL ) <=0 )return false;#else page = bprm->page[pos /PAGE_SIZE ];virt/kvm/async_pf.c +7
-1@@ -79,7 +79,13 @@ static void async_pf_execute(struct work_struct *work)might_sleep (); -get_user_pages_unlocked (NULL , mm, addr,1 ,1 ,0 ,NULL ); +/* +* This work is run asynchromously to the task which owns +* mm and might be done in another context, so we must +* use FOLL_REMOTE. +*/ +__get_user_pages_unlocked (NULL , mm, addr,1 ,1 ,0 ,NULL ,FOLL_REMOTE ); +kvm_async_page_present_sync (vcpu, apf);spin_lock (&vcpu->async_pf.lock);
PATCH 2/33 mm: overload get_user_pages() functions
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
The concept here was a suggestion from Ingo. The implementation horrors are all mine.
This allows get_user_pages(), get_user_pages_unlocked(), and get_user_pages_locked() to be called with or without the leading tsk/mm arguments. We will give a compile-time warning about the old style being __deprecated and we will also WARN_ON() if the non-remote version is used for a remote-style access.
Doing this, folks will get nice warnings and will not break the build. This should be nice for -next and will hopefully let developers fix up their own code instead of maintainers needing to do it at merge time.
The way we do this is hideous. It uses the __VA_ARGS__ macro functionality to call different functions based on the number of arguments passed to the macro.
There's an additional hack to ensure that our EXPORT_SYMBOL() of the deprecated symbols doesn't trigger a warning.
We should be able to remove this mess as soon as -rc1 hits in the release after this is merged.
---
b/include/linux/mm.h | 74 ++++++++++++++++++++++++++++++++++++++++++++------- b/mm/gup.c | 62 +++++++++++++++++++++++++++++++++--------- b/mm/nommu.c | 64 +++++++++++++++++++++++++++++++------------- b/mm/util.c | 4 -- 4 files changed, 158 insertions(+), 46 deletions(-)
include/linux/mm.h renamed from include/linux/mm.h~gup-arg-helpers +64 -10
@@ -1229,24 +1229,78 @@ long get_user_pages_remote(struct task_s unsigned long start, unsigned long nr_pages, int write, int force, struct page **pages, struct vm_area_struct **vmas); -long get_user_pages (struct task_struct *tsk,struct mm_struct *mm, -unsigned long start,unsigned long nr_pages, -int write,int force,struct page **pages, -struct vm_area_struct **vmas); -long get_user_pages_locked (struct task_struct *tsk,struct mm_struct *mm, -unsigned long start,unsigned long nr_pages, -int write,int force,struct page **pages, -int *locked); +long get_user_pages6 (unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages, +struct vm_area_struct **vmas); +long get_user_pages_locked6 (unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages,int *locked);long __get_user_pages_unlocked (struct task_struct *tsk,struct mm_struct *mm,unsigned long start,unsigned long nr_pages,int write,int force,struct page **pages,unsigned int gup_flags); -long get_user_pages_unlocked (struct task_struct *tsk,struct mm_struct *mm, -unsigned long start,unsigned long nr_pages, +long get_user_pages_unlocked5 (unsigned long start,unsigned long nr_pages,int write,int force,struct page **pages);int get_user_pages_fast (unsigned long start,int nr_pages,int write,struct page **pages); +/* suppress warnings from use in EXPORT_SYMBOL() */ +#ifndef __DISABLE_GUP_DEPRECATED +#define __gup_deprecated __deprecated +#else +#define __gup_deprecated +#endif +/* +* These macros provide backward-compatibility with the old +* get_user_pages() variants which took tsk/mm. These +* functions/macros provide both compile-time __deprecated so we +* can catch old-style use and not break the build. The actual +* functions also have WARN_ON()s to let us know at runtime if +* the get_user_pages() should have been the "remote" variant. +* +* These are hideous, but temporary. +* +* If you run into one of these __deprecated warnings, look +* at how you are calling get_user_pages(). If you are calling +* it with current/current->mm as the first two arguments, +* simply remove those arguments. The behavior will be the same +* as it is now. If you are calling it on another task, use +* get_user_pages_remote() instead. +* +* Any questions? Ask Dave Hansen <[email protected]> +*/ +long +__gup_deprecated +get_user_pages8 (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages, +struct vm_area_struct **vmas); +#define GUP_MACRO (_1, _2, _3, _4, _5, _6, _7, _8, get_user_pages, ...) \ + get_user_pages +#define get_user_pages (...) GUP_MACRO(__VA_ARGS__, \ + get_user_pages8, x, \ + get_user_pages6, x, x, x, x, x)(__VA_ARGS__) + +__gup_deprecated +long get_user_pages_locked8 (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages, +int *locked); +#define GUPL_MACRO (_1, _2, _3, _4, _5, _6, _7, _8, get_user_pages_locked, ...) \ + get_user_pages_locked +#define get_user_pages_locked (...) GUPL_MACRO(__VA_ARGS__, \ + get_user_pages_locked8, x, \ + get_user_pages_locked6, x, x, x, x)(__VA_ARGS__) + +__gup_deprecated +long get_user_pages_unlocked7 (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages); +#define GUPU_MACRO (_1, _2, _3, _4, _5, _6, _7, get_user_pages_unlocked, ...) \ + get_user_pages_unlocked +#define get_user_pages_unlocked (...) GUPU_MACRO(__VA_ARGS__, \ + get_user_pages_unlocked7, x, \ + get_user_pages_unlocked5, x, x, x, x)(__VA_ARGS__) +/* Container for pinned pfns / pages */ struct frame_vector {unsigned int nr_allocated;/* Number of frames we have space for */
mm/gup.c renamed from mm/gup.c~gup-arg-helpers +48 -14
99 lines not on this page · raw message
mm/nommu.c renamed from mm/nommu.c~gup-arg-helpers +45 -19
103 lines not on this page · raw message
mm/util.c renamed from mm/util.c~gup-arg-helpers +1 -3
@@ -283,9 +283,7 @@ EXPORT_SYMBOL_GPL(__get_user_pages_fast)int __weak get_user_pages_fast (unsigned long start,int nr_pages,int write,struct page **pages) { -struct mm_struct *mm = current->mm; -return get_user_pages_unlocked (current, mm, start, nr_pages, - write,0 , pages); +return get_user_pages_unlocked (start, nr_pages, write,0 , pages); }EXPORT_SYMBOL_GPL (get_user_pages_fast);
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 02/33] mm: overload get_user_pages() functions
Quoted 6 lines · Dave Hansen
From: Dave Hansen <[email protected]>
The concept here was a suggestion from Ingo. The implementation horrors are all mine.
Quoted 6 lines
This allows
get_user_pages(),get_user_pages_unlocked(), andget_user_pages_locked()to be called with or without the leading tsk/mm arguments. We will give a compile-time warning about the old style being__deprecatedand we will alsoWARN_ON()if the non-remote version is used for a remote-style access.
So at minimum this should be WARN_ON_ONCE(), to make it easier to recover some meaningful kernel log from such incidents.
But:
Quoted 9 lines
Doing this, folks will get nice warnings and will not break the build. This should be nice for -next and will hopefully let developers fix up their own code instead of maintainers needing to do it at merge time.
The way we do this is hideous. It uses the
__VA_ARGS__macro functionality to call different functions based on the number of arguments passed to the macro.
Quoted 5 lines
There's an additional hack to ensure that our
EXPORT_SYMBOL()of the deprecated symbols doesn't trigger a warning.We should be able to remove this mess as soon as -rc1 hits in the release after this is merged.
So when I suggested this then it looked a _lot_ cleanear to me, in my head!
OTOH this, if factored out a bit perhaps, could be the basis for a useful technical model to do 'phased in, -next invariant' prototype migrations in the future, especially when it involves lots of subsystems.
Strictly only in cases where -rc1 will truly get rid of the __VA_ARGS__ hackery - which we'd do in this case.
Nevertheless I'd love to have a high level buy-in from either Linus or Andrew that we can do it this way, as the hackery looks very hideous...
The alternative would be to allow the -next churn and to allow the occasional (fairly trivial but tester-disruptive) build breakage.
Thanks,
Ingo
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 02/33] mm: overload get_user_pages() functions
Quoted 5 lines · Ingo Molnar
Quoted 5 lines
Quoted 5 lines
From: Dave Hansen <[email protected]>
The concept here was a suggestion from Ingo. The implementation horrors are all mine.
Quoted 8 lines
Quoted 6 lines
Quoted 6 lines
This allows
get_user_pages(),get_user_pages_unlocked(), andget_user_pages_locked()to be called with or without the leading tsk/mm arguments. We will give a compile-time warning about the old style being__deprecatedand we will alsoWARN_ON()if the non-remote version is used for a remote-style access.So at minimum this should be
WARN_ON_ONCE(), to make it easier to recover some meaningful kernel log from such incidents.
I went to go fix this in the code but realized that I coded it up as WARN_ONCE(). The description was just imprecise. So I won't be sending a code fix for this.
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] mm/gup: Overload get_user_pages() functions
In reply to Dave Hansenmm/gup: Overload get_user_pages() functions
Commit-ID: cde70140fed8429acf7a14e2e2cbd3e329036653 Gitweb: http://git.kernel.org/tip/cde70140fed8429acf7a14e2e2cbd3e329036653 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:01:55 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 16 Feb 2016 10:11:12 +0100
mm/gup: Overload get_user_pages() functions
The concept here was a suggestion from Ingo. The implementation horrors are all mine.
This allows get_user_pages(), get_user_pages_unlocked(), and get_user_pages_locked() to be called with or without the leading tsk/mm arguments. We will give a compile-time warning about the old style being __deprecated and we will also WARN_ON() if the non-remote version is used for a remote-style access.
Doing this, folks will get nice warnings and will not break the build. This should be nice for -next and will hopefully let developers fix up their own code instead of maintainers needing to do it at merge time.
The way we do this is hideous. It uses the __VA_ARGS__ macro functionality to call different functions based on the number of arguments passed to the macro.
There's an additional hack to ensure that our EXPORT_SYMBOL() of the deprecated symbols doesn't trigger a warning.
We should be able to remove this mess as soon as -rc1 hits in the release after this is merged.
--- include/linux/mm.h | 74 ++++++++++++++++++++++++++++++++++++++++++++++-------- mm/gup.c | 62 ++++++++++++++++++++++++++++++++++----------- mm/nommu.c | 64 ++++++++++++++++++++++++++++++++-------------- mm/util.c | 4 +-- 4 files changed, 158 insertions(+), 46 deletions(-)
include/linux/mm.h +64 -10
@@ -1229,24 +1229,78 @@ long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, int write, int force, struct page **pages, struct vm_area_struct **vmas); -long get_user_pages (struct task_struct *tsk,struct mm_struct *mm, -unsigned long start,unsigned long nr_pages, -int write,int force,struct page **pages, -struct vm_area_struct **vmas); -long get_user_pages_locked (struct task_struct *tsk,struct mm_struct *mm, -unsigned long start,unsigned long nr_pages, -int write,int force,struct page **pages, -int *locked); +long get_user_pages6 (unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages, +struct vm_area_struct **vmas); +long get_user_pages_locked6 (unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages,int *locked);long __get_user_pages_unlocked (struct task_struct *tsk,struct mm_struct *mm,unsigned long start,unsigned long nr_pages,int write,int force,struct page **pages,unsigned int gup_flags); -long get_user_pages_unlocked (struct task_struct *tsk,struct mm_struct *mm, -unsigned long start,unsigned long nr_pages, +long get_user_pages_unlocked5 (unsigned long start,unsigned long nr_pages,int write,int force,struct page **pages);int get_user_pages_fast (unsigned long start,int nr_pages,int write,struct page **pages); +/* suppress warnings from use in EXPORT_SYMBOL() */ +#ifndef __DISABLE_GUP_DEPRECATED +#define __gup_deprecated __deprecated +#else +#define __gup_deprecated +#endif +/* +* These macros provide backward-compatibility with the old +* get_user_pages() variants which took tsk/mm. These +* functions/macros provide both compile-time __deprecated so we +* can catch old-style use and not break the build. The actual +* functions also have WARN_ON()s to let us know at runtime if +* the get_user_pages() should have been the "remote" variant. +* +* These are hideous, but temporary. +* +* If you run into one of these __deprecated warnings, look +* at how you are calling get_user_pages(). If you are calling +* it with current/current->mm as the first two arguments, +* simply remove those arguments. The behavior will be the same +* as it is now. If you are calling it on another task, use +* get_user_pages_remote() instead. +* +* Any questions? Ask Dave Hansen <[email protected]> +*/ +long +__gup_deprecated +get_user_pages8 (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages, +struct vm_area_struct **vmas); +#define GUP_MACRO (_1, _2, _3, _4, _5, _6, _7, _8, get_user_pages, ...) \ + get_user_pages +#define get_user_pages (...) GUP_MACRO(__VA_ARGS__, \ + get_user_pages8, x, \ + get_user_pages6, x, x, x, x, x)(__VA_ARGS__) + +__gup_deprecated +long get_user_pages_locked8 (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages, +int *locked); +#define GUPL_MACRO (_1, _2, _3, _4, _5, _6, _7, _8, get_user_pages_locked, ...) \ + get_user_pages_locked +#define get_user_pages_locked (...) GUPL_MACRO(__VA_ARGS__, \ + get_user_pages_locked8, x, \ + get_user_pages_locked6, x, x, x, x)(__VA_ARGS__) + +__gup_deprecated +long get_user_pages_unlocked7 (struct task_struct *tsk,struct mm_struct *mm, +unsigned long start,unsigned long nr_pages, +int write,int force,struct page **pages); +#define GUPU_MACRO (_1, _2, _3, _4, _5, _6, _7, get_user_pages_unlocked, ...) \ + get_user_pages_unlocked +#define get_user_pages_unlocked (...) GUPU_MACRO(__VA_ARGS__, \ + get_user_pages_unlocked7, x, \ + get_user_pages_unlocked5, x, x, x, x)(__VA_ARGS__) +/* Container for pinned pfns / pages */ struct frame_vector {unsigned int nr_allocated;/* Number of frames we have space for */
mm/gup.c +48 -14
99 lines not on this page · raw message
mm/nommu.c +45 -19
103 lines not on this page · raw message
mm/util.c +1 -3
@@ -283,9 +283,7 @@ EXPORT_SYMBOL_GPL(__get_user_pages_fast);int __weak get_user_pages_fast (unsigned long start,int nr_pages,int write,struct page **pages) { -struct mm_struct *mm = current->mm; -return get_user_pages_unlocked (current, mm, start, nr_pages, - write,0 , pages); +return get_user_pages_unlocked (start, nr_pages, write,0 , pages); }EXPORT_SYMBOL_GPL (get_user_pages_fast);
PATCH 3/33 mm, gup: switch callers of get_user_pages() to not pass tsk/mm
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
We will soon modify the vanilla get_user_pages() so it can no longer be used on mm/tasks other than 'current/current->mm', which is by far the most common way it is called. For now, we allow the old-style calls, but warn when they are used. (implemented in previous patch)
This patch switches all callers of:
get_user_pages()
get_user_pages_unlocked()
get_user_pages_locked()
to stop passing tsk/mm so they will no longer see the warnings.
---
b/arch/cris/arch-v32/drivers/cryptocop.c | 8 ++------ b/arch/ia64/kernel/err_inject.c | 3 +-- b/arch/mips/mm/gup.c | 3 +-- b/arch/s390/mm/gup.c | 4 +--- b/arch/sh/mm/gup.c | 2 +- b/arch/sparc/mm/gup.c | 2 +- b/arch/x86/mm/gup.c | 2 +- b/arch/x86/mm/mpx.c | 4 ++-- b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 3 +-- b/drivers/gpu/drm/radeon/radeon_ttm.c | 3 +-- b/drivers/gpu/drm/via/via_dmablit.c | 3 +-- b/drivers/infiniband/core/umem.c | 2 +- b/drivers/infiniband/hw/mthca/mthca_memfree.c | 3 +-- b/drivers/infiniband/hw/qib/qib_user_pages.c | 3 +-- b/drivers/infiniband/hw/usnic/usnic_uiom.c | 2 +- b/drivers/media/pci/ivtv/ivtv-udma.c | 4 ++-- b/drivers/media/pci/ivtv/ivtv-yuv.c | 10 ++++------ b/drivers/media/v4l2-core/videobuf-dma-sg.c | 3 +-- b/drivers/misc/mic/scif/scif_rma.c | 2 -- b/drivers/misc/sgi-gru/grufault.c | 3 +-- b/drivers/scsi/st.c | 2 -- b/drivers/video/fbdev/pvr2fb.c | 4 ++-- b/drivers/virt/fsl_hypervisor.c | 5 ++--- b/mm/frame_vector.c | 2 +- b/mm/gup.c | 6 ++++-- b/mm/ksm.c | 2 +- b/mm/mempolicy.c | 6 +++--- b/net/ceph/pagevec.c | 2 +- b/virt/kvm/kvm_main.c | 10 +++++----- 29 files changed, 44 insertions(+), 64 deletions(-)
arch/cris/arch-v32/drivers/cryptocop.c renamed from arch/cris/arch-v32/drivers/cryptocop.c~get_current_user_pages +2 -6
@@ -2719,9 +2719,7 @@ static int cryptocop_ioctl_process(struc/* Acquire the mm page semaphore. */ down_read (¤t->mm->mmap_sem); - err = get_user_pages(current, - current->mm, - (unsigned long int)(oper.indata + prev_ix), + err = get_user_pages((unsigned long int)(oper.indata + prev_ix), noinpages, 0, /* read access only for in data */ 0, /* no force */
@@ -2736,9 +2734,7 @@ static int cryptocop_ioctl_process(struc } noinpages = err;if (oper.do_cipher){ - err = get_user_pages(current, - current->mm, - (unsigned long int)oper.cipher_outdata, + err = get_user_pages((unsigned long int)oper.cipher_outdata, nooutpages, 1, /* write access for out data */ 0, /* no force */
arch/ia64/kernel/err_inject.c renamed from arch/ia64/kernel/err_inject.c~get_current_user_pages +1 -2
@@ -142,8 +142,7 @@ store_virtual_to_phys(struct device *devu64 virt_addr=simple_strtoull (buf,NULL ,16 );int ret; - ret =get_user_pages (current, current->mm, virt_addr, -1 ,VM_READ ,0 ,NULL ,NULL ); + ret =get_user_pages (virt_addr,1 ,VM_READ ,0 ,NULL ,NULL );if (ret<=0 ) {#ifdef ERR_INJ_DEBUG printk ("Virtual address %lx is not existing.\n" ,virt_addr);
arch/mips/mm/gup.c renamed from arch/mips/mm/gup.c~get_current_user_pages +1 -2
@@ -286,8 +286,7 @@ slow_irqon: start += nr <<PAGE_SHIFT ; pages += nr; - ret =get_user_pages_unlocked (current, mm, start, - (end - start) >>PAGE_SHIFT , + ret =get_user_pages_unlocked (start, (end - start) >>PAGE_SHIFT , write,0 , pages);/* Have to be a bit careful with return values */
arch/s390/mm/gup.c renamed from arch/s390/mm/gup.c~get_current_user_pages +1 -3
@@ -210,7 +210,6 @@ int __get_user_pages_fast(unsigned longint get_user_pages_fast (unsigned long start,int nr_pages,int write,struct page **pages) { -struct mm_struct *mm = current->mm;int nr, ret;might_sleep ();
@@ -222,8 +221,7 @@ int get_user_pages_fast(unsigned long st/* Try to get the remaining pages with get_user_pages */ start += nr <<PAGE_SHIFT ; pages += nr; - ret =get_user_pages_unlocked (current, mm, start, - nr_pages - nr, write,0 , pages); + ret =get_user_pages_unlocked (start, nr_pages - nr, write,0 , pages);/* Have to be a bit careful with return values */ if (nr >0 ) ret = (ret <0 ) ? nr : ret + nr;
arch/sh/mm/gup.c renamed from arch/sh/mm/gup.c~get_current_user_pages +1 -1
@@ -257,7 +257,7 @@ slow_irqon: start += nr <<PAGE_SHIFT ; pages += nr; - ret =get_user_pages_unlocked (current, mm, start, + ret =get_user_pages_unlocked (start, (end - start) >>PAGE_SHIFT , write,0 , pages);/* Have to be a bit careful with return values */
arch/sparc/mm/gup.c renamed from arch/sparc/mm/gup.c~get_current_user_pages +1 -1
@@ -237,7 +237,7 @@ slow: start += nr <<PAGE_SHIFT ; pages += nr; - ret =get_user_pages_unlocked (current, mm, start, + ret =get_user_pages_unlocked (start, (end - start) >>PAGE_SHIFT , write,0 , pages);/* Have to be a bit careful with return values */
arch/x86/mm/gup.c renamed from arch/x86/mm/gup.c~get_current_user_pages +1 -1
@@ -422,7 +422,7 @@ slow_irqon: start += nr <<PAGE_SHIFT ; pages += nr; - ret =get_user_pages_unlocked (current, mm, start, + ret =get_user_pages_unlocked (start, (end - start) >>PAGE_SHIFT , write,0 , pages);
arch/x86/mm/mpx.c renamed from arch/x86/mm/mpx.c~get_current_user_pages +2 -2
@@ -546,8 +546,8 @@ static int mpx_resolve_fault(long __userint nr_pages =1 ;int force =0 ; - gup_ret =get_user_pages (current, current->mm, (unsigned long )addr, - nr_pages, write, force,NULL ,NULL ); + gup_ret =get_user_pages ((unsigned long )addr, nr_pages, write, + force,NULL ,NULL );/* * get_user_pages() returns number of pages gotten. * 0 means we failed to fault in and get anything,
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c renamed from drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c~get_current_user_pages +1 -2
@@ -518,8 +518,7 @@ static int amdgpu_ttm_tt_pin_userptr(struint64_t userptr = gtt->userptr + pinned *PAGE_SIZE ;struct page **pages = ttm->pages + pinned; - r =get_user_pages (current, current->mm, userptr, num_pages, - write,0 , pages,NULL ); + r =get_user_pages (userptr, num_pages, write,0 , pages,NULL );if (r <0 ) goto release_pages;
drivers/gpu/drm/radeon/radeon_ttm.c renamed from drivers/gpu/drm/radeon/radeon_ttm.c~get_current_user_pages +1 -2
@@ -554,8 +554,7 @@ static int radeon_ttm_tt_pin_userptr(struint64_t userptr = gtt->userptr + pinned *PAGE_SIZE ;struct page **pages = ttm->pages + pinned; - r =get_user_pages (current, current->mm, userptr, num_pages, - write,0 , pages,NULL ); + r =get_user_pages (userptr, num_pages, write,0 , pages,NULL );if (r <0 ) goto release_pages;
drivers/gpu/drm/via/via_dmablit.c renamed from drivers/gpu/drm/via/via_dmablit.c~get_current_user_pages +1 -2
@@ -239,8 +239,7 @@ via_lock_all_dma_pages(drm_via_sg_info_tif (NULL == vsg->pages)return -ENOMEM ;down_read (¤t->mm->mmap_sem); - ret =get_user_pages (current, current->mm, - (unsigned long )xfer->mem_addr, + ret =get_user_pages ((unsigned long )xfer->mem_addr, vsg->num_pages, (vsg->direction ==DMA_FROM_DEVICE ),0 , vsg->pages,NULL );
drivers/infiniband/core/umem.c renamed from drivers/infiniband/core/umem.c~get_current_user_pages +1 -1
@@ -188,7 +188,7 @@ struct ib_umem *ib_umem_get(struct ib_uc sg_list_start = umem->sg_head.sgl;while (npages) { - ret =get_user_pages (current, current->mm, cur_base, + ret =get_user_pages (cur_base, min_t(unsigned long, npages,PAGE_SIZE /sizeof (struct page *)),1 , !umem->writable, page_list, vma_list);
drivers/infiniband/hw/mthca/mthca_memfree.c renamed from drivers/infiniband/hw/mthca/mthca_memfree.c~get_current_user_pages +1 -2
@@ -472,8 +472,7 @@ int mthca_map_user_db(struct mthca_dev * goto out; } - ret =get_user_pages (current, current->mm, uaddr &PAGE_MASK ,1 ,1 ,0 , - pages,NULL ); + ret =get_user_pages (uaddr &PAGE_MASK ,1 ,1 ,0 , pages,NULL );if (ret <0 ) goto out;
drivers/infiniband/hw/qib/qib_user_pages.c renamed from drivers/infiniband/hw/qib/qib_user_pages.c~get_current_user_pages +1 -2
@@ -66,8 +66,7 @@ static int __qib_get_user_pages(unsigned }for (got =0 ; got < num_pages; got += ret) { - ret =get_user_pages (current, current->mm, - start_page + got *PAGE_SIZE , + ret =get_user_pages (start_page + got *PAGE_SIZE , num_pages - got,1 ,1 , p + got,NULL );if (ret <0 )
drivers/infiniband/hw/usnic/usnic_uiom.c renamed from drivers/infiniband/hw/usnic/usnic_uiom.c~get_current_user_pages +1 -1
@@ -144,7 +144,7 @@ static int usnic_uiom_get_pages(unsigned ret =0 ;while (npages) { - ret =get_user_pages (current, current->mm, cur_base, + ret =get_user_pages (cur_base, min_t(unsigned long, npages,PAGE_SIZE /sizeof (struct page *)),1 , !writable, page_list,NULL );
drivers/media/pci/ivtv/ivtv-udma.c renamed from drivers/media/pci/ivtv/ivtv-udma.c~get_current_user_pages +2 -2
@@ -124,8 +124,8 @@ int ivtv_udma_setup(struct ivtv *itv, un }/* Get user pages for DMA Xfer */ - err =get_user_pages_unlocked (current, current->mm, - user_dma.uaddr, user_dma.page_count,0 ,1 , dma->map); + err =get_user_pages_unlocked (user_dma.uaddr, user_dma.page_count,0 , +1 , dma->map);if (user_dma.page_count != err) { IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
drivers/media/pci/ivtv/ivtv-yuv.c renamed from drivers/media/pci/ivtv/ivtv-yuv.c~get_current_user_pages +4 -6
@@ -75,14 +75,12 @@ static int ivtv_yuv_prep_user_dma(structivtv_udma_get_page_info (&uv_dma, (unsigned long )args->uv_source,360 * uv_decode_height);/* Get user pages for DMA Xfer */ - y_pages =get_user_pages_unlocked (current, current->mm, - y_dma.uaddr, y_dma.page_count,0 ,1 , - &dma->map[0 ]); + y_pages =get_user_pages_unlocked (y_dma.uaddr, + y_dma.page_count,0 ,1 , &dma->map[0 ]); uv_pages =0 ;/* silence gcc. value is set and consumed only if: */ if (y_pages == y_dma.page_count) { - uv_pages =get_user_pages_unlocked (current, current->mm, - uv_dma.uaddr, uv_dma.page_count,0 ,1 , - &dma->map[y_pages]); + uv_pages =get_user_pages_unlocked (uv_dma.uaddr, + uv_dma.page_count,0 ,1 , &dma->map[y_pages]); }if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) {
drivers/media/v4l2-core/videobuf-dma-sg.c renamed from drivers/media/v4l2-core/videobuf-dma-sg.c~get_current_user_pages +1 -2
@@ -181,8 +181,7 @@ static int videobuf_dma_init_user_lockeddprintk (1 ,"init user [0x%lx+0x%lx => %d pages]\n" , data, size, dma->nr_pages); - err =get_user_pages (current, current->mm, - data &PAGE_MASK , dma->nr_pages, + err =get_user_pages (data &PAGE_MASK , dma->nr_pages, rw ==READ ,1 ,/* force */ dma->pages,NULL );
drivers/misc/mic/scif/scif_rma.c renamed from drivers/misc/mic/scif/scif_rma.c~get_current_user_pages +0 -2
@@ -1394,8 +1394,6 @@ retry: } pinned_pages->nr_pages = get_user_pages( - current, - mm, (u64)addr, nr_pages, !!(prot & SCIF_PROT_WRITE),
drivers/misc/sgi-gru/grufault.c renamed from drivers/misc/sgi-gru/grufault.c~get_current_user_pages +1 -2
@@ -198,8 +198,7 @@ static int non_atomic_pte_lookup(struct#else *pageshift =PAGE_SHIFT ;#endif -if (get_user_pages - (current, current->mm, vaddr,1 , write,0 , &page,NULL ) <=0 ) +if (get_user_pages (vaddr,1 , write,0 , &page,NULL ) <=0 )return -EFAULT ; *paddr =page_to_phys (page);put_page (page);
drivers/scsi/st.c renamed from drivers/scsi/st.c~get_current_user_pages +0 -2
@@ -4817,8 +4817,6 @@ static int sgl_map_user_pages(struct st_/* Try to fault in all of the necessary pages */ /* rw==READ means read from drive, write into memory area */ res = get_user_pages_unlocked( - current, - current->mm, uaddr, nr_pages, rw == READ,
drivers/video/fbdev/pvr2fb.c renamed from drivers/video/fbdev/pvr2fb.c~get_current_user_pages +2 -2
@@ -686,8 +686,8 @@ static ssize_t pvr2fb_write(struct fb_inif (!pages)return -ENOMEM ; - ret =get_user_pages_unlocked (current, current->mm, (unsigned long )buf, - nr_pages,WRITE ,0 , pages); + ret =get_user_pages_unlocked ((unsigned long )buf, nr_pages,WRITE , +0 , pages);if (ret < nr_pages) { nr_pages = ret;
drivers/virt/fsl_hypervisor.c renamed from drivers/virt/fsl_hypervisor.c~get_current_user_pages +2 -3
@@ -244,9 +244,8 @@ static long ioctl_memcpy(struct fsl_hv_i/* Get the physical addresses of the source buffer */ down_read (¤t->mm->mmap_sem); - num_pinned =get_user_pages (current, current->mm, - param.local_vaddr - lb_offset, num_pages, - (param.source ==-1 ) ?READ :WRITE , + num_pinned =get_user_pages (param.local_vaddr - lb_offset, + num_pages, (param.source ==-1 ) ?READ :WRITE ,0 , pages,NULL );up_read (¤t->mm->mmap_sem);
mm/frame_vector.c renamed from mm/frame_vector.c~get_current_user_pages +1 -1
@@ -58,7 +58,7 @@ int get_vaddr_frames(unsigned long startif (!(vma->vm_flags & (VM_IO |VM_PFNMAP ))) { vec->got_ref = true; vec->is_pfns = false; - ret =get_user_pages_locked (current, mm, start, nr_frames, + ret =get_user_pages_locked (start, nr_frames, write, force, (struct page **)(vec->ptrs), &locked); goto out; }
mm/gup.c renamed from mm/gup.c~get_current_user_pages +4 -2
@@ -936,8 +936,10 @@ long get_user_pages_remote(struct task_sEXPORT_SYMBOL (get_user_pages_remote);/* -* This is the same as get_user_pages_remote() for the time -* being. +* This is the same as get_user_pages_remote(), just with a +* less-flexible calling convention where we assume that the task +* and mm being operated on are the current task's. We also +* obviously don't pass FOLL_REMOTE in here. */ long get_user_pages6(unsigned long start, unsigned long nr_pages, int write, int force, struct page **pages,
mm/ksm.c renamed from mm/ksm.c~get_current_user_pages +1 -1
@@ -352,7 +352,7 @@ static inline bool ksm_test_exit(struct/* * We use break_ksm to break COW on a ksm page: it's a stripped down * -* if (get_user_pages(current, mm, addr, 1, 1, 1, &page, NULL) == 1) +* if (get_user_pages(addr, 1, 1, 1, &page, NULL) == 1) * put_page(page); * * but taking great care only to touch a ksm page, in a VM_MERGEABLE vma,
mm/mempolicy.c renamed from mm/mempolicy.c~get_current_user_pages +3 -3
@@ -844,12 +844,12 @@ static void get_policy_nodemask(struct m } } -static int lookup_node (struct mm_struct *mm,unsigned long addr) +static int lookup_node (unsigned long addr) {struct page *p;int err; - err =get_user_pages (current, mm, addr &PAGE_MASK ,1 ,0 ,0 , &p,NULL ); + err =get_user_pages (addr &PAGE_MASK ,1 ,0 ,0 , &p,NULL );if (err >=0 ) { err =page_to_nid (p);put_page (p);
@@ -904,7 +904,7 @@ static long do_get_mempolicy(int *policyif (flags &MPOL_F_NODE ) {if (flags &MPOL_F_ADDR ) { - err =lookup_node (mm, addr); + err =lookup_node (addr);if (err <0 ) goto out; *policy = err;
net/ceph/pagevec.c renamed from net/ceph/pagevec.c~get_current_user_pages +1 -1
@@ -24,7 +24,7 @@ struct page **ceph_get_direct_page_vectoreturn ERR_PTR (-ENOMEM );while (got < num_pages) { - rc =get_user_pages_unlocked (current, current->mm, + rc =get_user_pages_unlocked ( (unsigned long )data + ((unsigned long )got *PAGE_SIZE ), num_pages - got, write_page,0 , pages + got);if (rc <0 )
virt/kvm/kvm_main.c renamed from virt/kvm/kvm_main.c~get_current_user_pages +5 -5
@@ -1264,15 +1264,16 @@ unsigned long kvm_vcpu_gfn_to_hva_prot(sreturn gfn_to_hva_memslot_prot (slot, gfn, writable); } -static int get_user_page_nowait (struct task_struct *tsk,struct mm_struct *mm, -unsigned long start,int write,struct page **page) +static int get_user_page_nowait (unsigned long start,int write, +struct page **page) {int flags =FOLL_TOUCH |FOLL_NOWAIT |FOLL_HWPOISON |FOLL_GET ;if (write) flags |=FOLL_WRITE ; -return __get_user_pages (tsk, mm, start,1 , flags, page,NULL ,NULL ); +return __get_user_pages (current, current->mm, start,1 , flags, page, +NULL ,NULL ); }static inline int check_user_page_hwpoison (unsigned long addr)
@@ -1334,8 +1335,7 @@ static int hva_to_pfn_slow(unsigned longif (async) {down_read (¤t->mm->mmap_sem); - npages =get_user_page_nowait (current, current->mm, - addr, write_fault, page); + npages =get_user_page_nowait (addr, write_fault, page);up_read (¤t->mm->mmap_sem); }else npages = __get_user_pages_unlocked(current, current->mm, addr, 1,
_
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] mm/gup: Switch all callers of get_user_pages() to not pass tsk/mm
mm/gup: Switch all callers of get_user_pages() to not pass tsk/mm
Commit-ID: d4edcf0d56958db0aca0196314ca38a5e730ea92 Gitweb: http://git.kernel.org/tip/d4edcf0d56958db0aca0196314ca38a5e730ea92 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:01:56 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 16 Feb 2016 10:11:12 +0100
mm/gup: Switch all callers of get_user_pages() to not pass tsk/mm
We will soon modify the vanilla get_user_pages() so it can no longer be used on mm/tasks other than 'current/current->mm', which is by far the most common way it is called. For now, we allow the old-style calls, but warn when they are used. (implemented in previous patch)
This patch switches all callers of:
get_user_pages()
get_user_pages_unlocked()
get_user_pages_locked()
to stop passing tsk/mm so they will no longer see the warnings.
--- arch/cris/arch-v32/drivers/cryptocop.c | 8 ++------ arch/ia64/kernel/err_inject.c | 3 +-- arch/mips/mm/gup.c | 3 +-- arch/s390/mm/gup.c | 4 +--- arch/sh/mm/gup.c | 2 +- arch/sparc/mm/gup.c | 2 +- arch/x86/mm/gup.c | 2 +- arch/x86/mm/mpx.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 3 +-- drivers/gpu/drm/radeon/radeon_ttm.c | 3 +-- drivers/gpu/drm/via/via_dmablit.c | 3 +-- drivers/infiniband/core/umem.c | 2 +- drivers/infiniband/hw/mthca/mthca_memfree.c | 3 +-- drivers/infiniband/hw/qib/qib_user_pages.c | 3 +-- drivers/infiniband/hw/usnic/usnic_uiom.c | 2 +- drivers/media/pci/ivtv/ivtv-udma.c | 4 ++-- drivers/media/pci/ivtv/ivtv-yuv.c | 10 ++++------ drivers/media/v4l2-core/videobuf-dma-sg.c | 3 +-- drivers/misc/mic/scif/scif_rma.c | 2 -- drivers/misc/sgi-gru/grufault.c | 3 +-- drivers/scsi/st.c | 2 -- drivers/video/fbdev/pvr2fb.c | 4 ++-- drivers/virt/fsl_hypervisor.c | 5 ++--- mm/frame_vector.c | 2 +- mm/gup.c | 6 ++++-- mm/ksm.c | 2 +- mm/mempolicy.c | 6 +++--- net/ceph/pagevec.c | 2 +- virt/kvm/kvm_main.c | 10 +++++----- 29 files changed, 44 insertions(+), 64 deletions(-)
arch/cris/arch-v32/drivers/cryptocop.c +2 -6
@@ -2719,9 +2719,7 @@ static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsig/* Acquire the mm page semaphore. */ down_read (¤t->mm->mmap_sem); - err = get_user_pages(current, - current->mm, - (unsigned long int)(oper.indata + prev_ix), + err = get_user_pages((unsigned long int)(oper.indata + prev_ix), noinpages, 0, /* read access only for in data */ 0, /* no force */
@@ -2736,9 +2734,7 @@ static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsig } noinpages = err;if (oper.do_cipher){ - err = get_user_pages(current, - current->mm, - (unsigned long int)oper.cipher_outdata, + err = get_user_pages((unsigned long int)oper.cipher_outdata, nooutpages, 1, /* write access for out data */ 0, /* no force */
arch/ia64/kernel/err_inject.c +1 -2
@@ -142,8 +142,7 @@ store_virtual_to_phys(struct device *dev, struct device_attribute *attr,u64 virt_addr=simple_strtoull (buf,NULL ,16 );int ret; - ret =get_user_pages (current, current->mm, virt_addr, -1 ,VM_READ ,0 ,NULL ,NULL ); + ret =get_user_pages (virt_addr,1 ,VM_READ ,0 ,NULL ,NULL );if (ret<=0 ) {#ifdef ERR_INJ_DEBUG printk ("Virtual address %lx is not existing.\n" ,virt_addr);
arch/mips/mm/gup.c +1 -2
@@ -286,8 +286,7 @@ slow_irqon: start += nr <<PAGE_SHIFT ; pages += nr; - ret =get_user_pages_unlocked (current, mm, start, - (end - start) >>PAGE_SHIFT , + ret =get_user_pages_unlocked (start, (end - start) >>PAGE_SHIFT , write,0 , pages);/* Have to be a bit careful with return values */
arch/s390/mm/gup.c +1 -3
@@ -210,7 +210,6 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,int get_user_pages_fast (unsigned long start,int nr_pages,int write,struct page **pages) { -struct mm_struct *mm = current->mm;int nr, ret;might_sleep ();
@@ -222,8 +221,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,/* Try to get the remaining pages with get_user_pages */ start += nr <<PAGE_SHIFT ; pages += nr; - ret =get_user_pages_unlocked (current, mm, start, - nr_pages - nr, write,0 , pages); + ret =get_user_pages_unlocked (start, nr_pages - nr, write,0 , pages);/* Have to be a bit careful with return values */ if (nr >0 ) ret = (ret <0 ) ? nr : ret + nr;
arch/sh/mm/gup.c +1 -1
@@ -257,7 +257,7 @@ slow_irqon: start += nr <<PAGE_SHIFT ; pages += nr; - ret =get_user_pages_unlocked (current, mm, start, + ret =get_user_pages_unlocked (start, (end - start) >>PAGE_SHIFT , write,0 , pages);/* Have to be a bit careful with return values */
arch/sparc/mm/gup.c +1 -1
@@ -237,7 +237,7 @@ slow: start += nr <<PAGE_SHIFT ; pages += nr; - ret =get_user_pages_unlocked (current, mm, start, + ret =get_user_pages_unlocked (start, (end - start) >>PAGE_SHIFT , write,0 , pages);/* Have to be a bit careful with return values */
arch/x86/mm/gup.c +1 -1
@@ -422,7 +422,7 @@ slow_irqon: start += nr <<PAGE_SHIFT ; pages += nr; - ret =get_user_pages_unlocked (current, mm, start, + ret =get_user_pages_unlocked (start, (end - start) >>PAGE_SHIFT , write,0 , pages);
arch/x86/mm/mpx.c +2 -2
@@ -546,8 +546,8 @@ static int mpx_resolve_fault(long __user *addr, int write)int nr_pages =1 ;int force =0 ; - gup_ret =get_user_pages (current, current->mm, (unsigned long )addr, - nr_pages, write, force,NULL ,NULL ); + gup_ret =get_user_pages ((unsigned long )addr, nr_pages, write, + force,NULL ,NULL );/* * get_user_pages() returns number of pages gotten. * 0 means we failed to fault in and get anything,
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +1 -2
@@ -518,8 +518,7 @@ static int amdgpu_ttm_tt_pin_userptr(struct ttm_tt *ttm)uint64_t userptr = gtt->userptr + pinned *PAGE_SIZE ;struct page **pages = ttm->pages + pinned; - r =get_user_pages (current, current->mm, userptr, num_pages, - write,0 , pages,NULL ); + r =get_user_pages (userptr, num_pages, write,0 , pages,NULL );if (r <0 ) goto release_pages;
drivers/gpu/drm/radeon/radeon_ttm.c +1 -2
@@ -554,8 +554,7 @@ static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm)uint64_t userptr = gtt->userptr + pinned *PAGE_SIZE ;struct page **pages = ttm->pages + pinned; - r =get_user_pages (current, current->mm, userptr, num_pages, - write,0 , pages,NULL ); + r =get_user_pages (userptr, num_pages, write,0 , pages,NULL );if (r <0 ) goto release_pages;
drivers/gpu/drm/via/via_dmablit.c +1 -2
@@ -239,8 +239,7 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)if (NULL == vsg->pages)return -ENOMEM ;down_read (¤t->mm->mmap_sem); - ret =get_user_pages (current, current->mm, - (unsigned long )xfer->mem_addr, + ret =get_user_pages ((unsigned long )xfer->mem_addr, vsg->num_pages, (vsg->direction ==DMA_FROM_DEVICE ),0 , vsg->pages,NULL );
drivers/infiniband/core/umem.c +1 -1
@@ -188,7 +188,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, sg_list_start = umem->sg_head.sgl;while (npages) { - ret =get_user_pages (current, current->mm, cur_base, + ret =get_user_pages (cur_base, min_t(unsigned long, npages,PAGE_SIZE /sizeof (struct page *)),1 , !umem->writable, page_list, vma_list);
drivers/infiniband/hw/mthca/mthca_memfree.c +1 -2
@@ -472,8 +472,7 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar, goto out; } - ret =get_user_pages (current, current->mm, uaddr &PAGE_MASK ,1 ,1 ,0 , - pages,NULL ); + ret =get_user_pages (uaddr &PAGE_MASK ,1 ,1 ,0 , pages,NULL );if (ret <0 ) goto out;
drivers/infiniband/hw/qib/qib_user_pages.c +1 -2
@@ -66,8 +66,7 @@ static int __qib_get_user_pages(unsigned long start_page, size_t num_pages, }for (got =0 ; got < num_pages; got += ret) { - ret =get_user_pages (current, current->mm, - start_page + got *PAGE_SIZE , + ret =get_user_pages (start_page + got *PAGE_SIZE , num_pages - got,1 ,1 , p + got,NULL );if (ret <0 )
drivers/infiniband/hw/usnic/usnic_uiom.c +1 -1
@@ -144,7 +144,7 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable, ret =0 ;while (npages) { - ret =get_user_pages (current, current->mm, cur_base, + ret =get_user_pages (cur_base, min_t(unsigned long, npages,PAGE_SIZE /sizeof (struct page *)),1 , !writable, page_list,NULL );
drivers/media/pci/ivtv/ivtv-udma.c +2 -2
@@ -124,8 +124,8 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, }/* Get user pages for DMA Xfer */ - err =get_user_pages_unlocked (current, current->mm, - user_dma.uaddr, user_dma.page_count,0 ,1 , dma->map); + err =get_user_pages_unlocked (user_dma.uaddr, user_dma.page_count,0 , +1 , dma->map);if (user_dma.page_count != err) { IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
drivers/media/pci/ivtv/ivtv-yuv.c +4 -6
@@ -75,14 +75,12 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,ivtv_udma_get_page_info (&uv_dma, (unsigned long )args->uv_source,360 * uv_decode_height);/* Get user pages for DMA Xfer */ - y_pages =get_user_pages_unlocked (current, current->mm, - y_dma.uaddr, y_dma.page_count,0 ,1 , - &dma->map[0 ]); + y_pages =get_user_pages_unlocked (y_dma.uaddr, + y_dma.page_count,0 ,1 , &dma->map[0 ]); uv_pages =0 ;/* silence gcc. value is set and consumed only if: */ if (y_pages == y_dma.page_count) { - uv_pages =get_user_pages_unlocked (current, current->mm, - uv_dma.uaddr, uv_dma.page_count,0 ,1 , - &dma->map[y_pages]); + uv_pages =get_user_pages_unlocked (uv_dma.uaddr, + uv_dma.page_count,0 ,1 , &dma->map[y_pages]); }if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) {
drivers/media/v4l2-core/videobuf-dma-sg.c +1 -2
@@ -181,8 +181,7 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,dprintk (1 ,"init user [0x%lx+0x%lx => %d pages]\n" , data, size, dma->nr_pages); - err =get_user_pages (current, current->mm, - data &PAGE_MASK , dma->nr_pages, + err =get_user_pages (data &PAGE_MASK , dma->nr_pages, rw ==READ ,1 ,/* force */ dma->pages,NULL );
drivers/misc/mic/scif/scif_rma.c +0 -2
@@ -1394,8 +1394,6 @@ retry: } pinned_pages->nr_pages = get_user_pages( - current, - mm, (u64)addr, nr_pages, !!(prot & SCIF_PROT_WRITE),
drivers/misc/sgi-gru/grufault.c +1 -2
@@ -198,8 +198,7 @@ static int non_atomic_pte_lookup(struct vm_area_struct *vma,#else *pageshift =PAGE_SHIFT ;#endif -if (get_user_pages - (current, current->mm, vaddr,1 , write,0 , &page,NULL ) <=0 ) +if (get_user_pages (vaddr,1 , write,0 , &page,NULL ) <=0 )return -EFAULT ; *paddr =page_to_phys (page);put_page (page);
drivers/scsi/st.c +0 -2
@@ -4817,8 +4817,6 @@ static int sgl_map_user_pages(struct st_buffer *STbp,/* Try to fault in all of the necessary pages */ /* rw==READ means read from drive, write into memory area */ res = get_user_pages_unlocked( - current, - current->mm, uaddr, nr_pages, rw == READ,
drivers/video/fbdev/pvr2fb.c +2 -2
@@ -686,8 +686,8 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf,if (!pages)return -ENOMEM ; - ret =get_user_pages_unlocked (current, current->mm, (unsigned long )buf, - nr_pages,WRITE ,0 , pages); + ret =get_user_pages_unlocked ((unsigned long )buf, nr_pages,WRITE , +0 , pages);if (ret < nr_pages) { nr_pages = ret;
drivers/virt/fsl_hypervisor.c +2 -3
@@ -244,9 +244,8 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p)/* Get the physical addresses of the source buffer */ down_read (¤t->mm->mmap_sem); - num_pinned =get_user_pages (current, current->mm, - param.local_vaddr - lb_offset, num_pages, - (param.source ==-1 ) ?READ :WRITE , + num_pinned =get_user_pages (param.local_vaddr - lb_offset, + num_pages, (param.source ==-1 ) ?READ :WRITE ,0 , pages,NULL );up_read (¤t->mm->mmap_sem);
mm/frame_vector.c +1 -1
@@ -58,7 +58,7 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames,if (!(vma->vm_flags & (VM_IO |VM_PFNMAP ))) { vec->got_ref = true; vec->is_pfns = false; - ret =get_user_pages_locked (current, mm, start, nr_frames, + ret =get_user_pages_locked (start, nr_frames, write, force, (struct page **)(vec->ptrs), &locked); goto out; }
mm/gup.c +4 -2
@@ -936,8 +936,10 @@ long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,EXPORT_SYMBOL (get_user_pages_remote);/* -* This is the same as get_user_pages_remote() for the time -* being. +* This is the same as get_user_pages_remote(), just with a +* less-flexible calling convention where we assume that the task +* and mm being operated on are the current task's. We also +* obviously don't pass FOLL_REMOTE in here. */ long get_user_pages6(unsigned long start, unsigned long nr_pages, int write, int force, struct page **pages,
mm/ksm.c +1 -1
@@ -352,7 +352,7 @@ static inline bool ksm_test_exit(struct mm_struct *mm)/* * We use break_ksm to break COW on a ksm page: it's a stripped down * -* if (get_user_pages(current, mm, addr, 1, 1, 1, &page, NULL) == 1) +* if (get_user_pages(addr, 1, 1, 1, &page, NULL) == 1) * put_page(page); * * but taking great care only to touch a ksm page, in a VM_MERGEABLE vma,
mm/mempolicy.c +3 -3
@@ -844,12 +844,12 @@ static void get_policy_nodemask(struct mempolicy *p, nodemask_t *nodes) } } -static int lookup_node (struct mm_struct *mm,unsigned long addr) +static int lookup_node (unsigned long addr) {struct page *p;int err; - err =get_user_pages (current, mm, addr &PAGE_MASK ,1 ,0 ,0 , &p,NULL ); + err =get_user_pages (addr &PAGE_MASK ,1 ,0 ,0 , &p,NULL );if (err >=0 ) { err =page_to_nid (p);put_page (p);
@@ -904,7 +904,7 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask,if (flags &MPOL_F_NODE ) {if (flags &MPOL_F_ADDR ) { - err =lookup_node (mm, addr); + err =lookup_node (addr);if (err <0 ) goto out; *policy = err;
net/ceph/pagevec.c +1 -1
@@ -24,7 +24,7 @@ struct page **ceph_get_direct_page_vector(const void __user *data,return ERR_PTR (-ENOMEM );while (got < num_pages) { - rc =get_user_pages_unlocked (current, current->mm, + rc =get_user_pages_unlocked ( (unsigned long )data + ((unsigned long )got *PAGE_SIZE ), num_pages - got, write_page,0 , pages + got);if (rc <0 )
virt/kvm/kvm_main.c +5 -5
@@ -1264,15 +1264,16 @@ unsigned long kvm_vcpu_gfn_to_hva_prot(struct kvm_vcpu *vcpu, gfn_t gfn, bool *wreturn gfn_to_hva_memslot_prot (slot, gfn, writable); } -static int get_user_page_nowait (struct task_struct *tsk,struct mm_struct *mm, -unsigned long start,int write,struct page **page) +static int get_user_page_nowait (unsigned long start,int write, +struct page **page) {int flags =FOLL_TOUCH |FOLL_NOWAIT |FOLL_HWPOISON |FOLL_GET ;if (write) flags |=FOLL_WRITE ; -return __get_user_pages (tsk, mm, start,1 , flags, page,NULL ,NULL ); +return __get_user_pages (current, current->mm, start,1 , flags, page, +NULL ,NULL ); }static inline int check_user_page_hwpoison (unsigned long addr)
@@ -1334,8 +1335,7 @@ static int hva_to_pfn_slow(unsigned long addr, bool *async, bool write_fault,if (async) {down_read (¤t->mm->mmap_sem); - npages =get_user_page_nowait (current, current->mm, - addr, write_fault, page); + npages =get_user_page_nowait (addr, write_fault, page);up_read (¤t->mm->mmap_sem); }else npages = __get_user_pages_unlocked(current, current->mm, addr, 1,
PATCH 4/33 x86, fpu: add placeholder for Processor Trace XSAVE state
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
There is an XSAVE state component for Intel Processor Trace (PT). But, we do not currently use it.
We add a placeholder in the code for it so it is not a mystery and also so we do not need an explicit enum initialization for Protection Keys in a moment.
Why don't we use it?
We might end up using this at _some_ point in the future. But, this is a "system" state which requires using the currently unsupported XSAVES feature. Unlike all the other XSAVE states, PT state is also not directly tied to a thread. You might context-switch between threads, but not want to change any of the PT state. Or, you might switch between threads, and *do* want to change PT state, all depending on what is being traced.
We currently just manually set some MSRs to do this PT context switching, and it is unclear whether replacing our direct MSR use with XSAVE will be a net win or loss, both in code complexity and performance.
---
b/arch/x86/include/asm/fpu/types.h | 1 + b/arch/x86/kernel/fpu/xstate.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-)
arch/x86/include/asm/fpu/types.h renamed from arch/x86/include/asm/fpu/types.h~pt-xstate-bit +1 -0
@@ -108,6 +108,7 @@ enum xfeature {XFEATURE_OPMASK , XFEATURE_ZMM_Hi256, XFEATURE_Hi16_ZMM, +XFEATURE_PT_UNIMPLEMENTED_SO_FAR , XFEATURE_MAX, };
arch/x86/kernel/fpu/xstate.c renamed from arch/x86/kernel/fpu/xstate.c~pt-xstate-bit +8 -2
@@ -13,6 +13,11 @@#include <asm/tlbflush.h> +/* +* Although we spell it out in here, the Processor Trace +* xfeature is completely unused. We use other mechanisms +* to save/restore PT state in Linux. +*/ static const char *xfeature_names[] = {"x87 floating point registers" ,
@@ -23,7 +28,7 @@ static const char *xfeature_names[] ="AVX-512 opmask" ,"AVX-512 Hi256" ,"AVX-512 ZMM_Hi256" , - "unknown xstate feature" , + "Processor Trace (unused)" , };/*
@@ -470,7 +475,8 @@ static void check_xstate_against_struct(* numbers. */ if ((nr <XFEATURE_YMM ) || - (nr >=XFEATURE_MAX )) { + (nr >=XFEATURE_MAX ) || + (nr ==XFEATURE_PT_UNIMPLEMENTED_SO_FAR )) {WARN_ONCE (1 ,"no structure for xstate: %d\n" , nr);XSTATE_WARN_ON (1 ); }
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/fpu: Add placeholder for 'Processor Trace' XSAVE state
x86/fpu: Add placeholder for 'Processor Trace' XSAVE state
Commit-ID: 1f96b1efbad4bb753e7fd265753f6cac1cdc5648 Gitweb: http://git.kernel.org/tip/1f96b1efbad4bb753e7fd265753f6cac1cdc5648 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:01:58 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 16 Feb 2016 10:11:13 +0100
x86/fpu: Add placeholder for 'Processor Trace' XSAVE state
There is an XSAVE state component for Intel Processor Trace (PT). But, we do not currently use it.
We add a placeholder in the code for it so it is not a mystery and also so we do not need an explicit enum initialization for Protection Keys in a moment.
Why don't we use it?
We might end up using this at _some_ point in the future. But, this is a "system" state which requires using the currently unsupported XSAVES feature. Unlike all the other XSAVE states, PT state is also not directly tied to a thread. You might context-switch between threads, but not want to change any of the PT state. Or, you might switch between threads, and *do* want to change PT state, all depending on what is being traced.
We currently just manually set some MSRs to do this PT context switching, and it is unclear whether replacing our direct MSR use with XSAVE will be a net win or loss, both in code complexity and performance.
--- arch/x86/include/asm/fpu/types.h | 1 + arch/x86/kernel/fpu/xstate.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-)
arch/x86/include/asm/fpu/types.h +1 -0
@@ -108,6 +108,7 @@ enum xfeature {XFEATURE_OPMASK , XFEATURE_ZMM_Hi256, XFEATURE_Hi16_ZMM, +XFEATURE_PT_UNIMPLEMENTED_SO_FAR , XFEATURE_MAX, };
arch/x86/kernel/fpu/xstate.c +8 -2
@@ -13,6 +13,11 @@#include <asm/tlbflush.h> +/* +* Although we spell it out in here, the Processor Trace +* xfeature is completely unused. We use other mechanisms +* to save/restore PT state in Linux. +*/ static const char *xfeature_names[] = {"x87 floating point registers" ,
@@ -23,7 +28,7 @@ static const char *xfeature_names[] ="AVX-512 opmask" ,"AVX-512 Hi256" ,"AVX-512 ZMM_Hi256" , - "unknown xstate feature" , + "Processor Trace (unused)" , };/*
@@ -470,7 +475,8 @@ static void check_xstate_against_struct(int nr)* numbers. */ if ((nr <XFEATURE_YMM ) || - (nr >=XFEATURE_MAX )) { + (nr >=XFEATURE_MAX ) || + (nr ==XFEATURE_PT_UNIMPLEMENTED_SO_FAR )) {WARN_ONCE (1 ,"no structure for xstate: %d\n" , nr);XSTATE_WARN_ON (1 ); }
PATCH 5/33 x86, pkeys: Add Kconfig option
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
I don't have a strong opinion on whether we need a Kconfig prompt or not. Protection Keys has relatively little code associated with it, and it is not a heavyweight feature to keep enabled. However, I can imagine that folks would still appreciate being able to disable it.
Note that, with disabled-features.h, the checks in the code for protection keys are always the same:
cpu_has(c, X86_FEATURE_PKU)
With the config option disabled, this essentially turns into an #ifdef.
We will hide the prompt for now.
---
b/arch/x86/Kconfig | 4 ++++ 1 file changed, 4 insertions(+)
arch/x86/Kconfig renamed from arch/x86/Kconfig~pkeys-01-kconfig +4 -0
@@ -1713,6 +1713,10 @@ config X86_INTEL_MPX If unsure, say N. +config X86_INTEL_MEMORY_PROTECTION_KEYS + def_bool y + depends on CPU_SUP_INTEL && X86_64 + config EFI bool "EFI runtime service support" depends on ACPI
_
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/mm/pkeys: Add Kconfig option
x86/mm/pkeys: Add Kconfig option
Commit-ID: 35e97790f5f1e5cf2b5522c55e3e31d5c81bd226 Gitweb: http://git.kernel.org/tip/35e97790f5f1e5cf2b5522c55e3e31d5c81bd226 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:00 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 16 Feb 2016 10:11:13 +0100
x86/mm/pkeys: Add Kconfig option
I don't have a strong opinion on whether we need a Kconfig prompt or not. Protection Keys has relatively little code associated with it, and it is not a heavyweight feature to keep enabled. However, I can imagine that folks would still appreciate being able to disable it.
Note that, with disabled-features.h, the checks in the code for protection keys are always the same:
cpu_has(c, X86_FEATURE_PKU)
With the config option disabled, this essentially turns into an
We will hide the prompt for now.
--- arch/x86/Kconfig | 4 ++++ 1 file changed, 4 insertions(+)
arch/x86/Kconfig +4 -0
@@ -1714,6 +1714,10 @@ config X86_INTEL_MPX If unsure, say N. +config X86_INTEL_MEMORY_PROTECTION_KEYS + def_bool y + depends on CPU_SUP_INTEL && X86_64 + config EFI bool "EFI runtime service support" depends on ACPI
Borislav Petkov
maintainerPATCH 1/1 x86/mm/pkeys: Do not enable them by default
Quoted 15 lines · tip-bot for Dave Hansen
Commit-ID: 35e97790f5f1e5cf2b5522c55e3e31d5c81bd226 Gitweb: http://git.kernel.org/tip/35e97790f5f1e5cf2b5522c55e3e31d5c81bd226 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:00 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 16 Feb 2016 10:11:13 +0100x86/mm/pkeys: Add
KconfigoptionI don't have a strong opinion on whether we need a
Kconfigprompt or not. Protection Keys has relatively little code associated with it, and it is not a heavyweight feature to keep enabled. However, I can imagine that folks would still appreciate being able to disable it.
Quoted 6 lines
Note that, with
disabled-features.h, the checks in the code for protection keys are always the same:cpu_has(c, X86_FEATURE_PKU)With the config option disabled, this essentially turns into an
whoops, something is missing here. An "#ifdef."
...
arch/x86/Kconfig config X86_INTEL_MPX · line 1718
Quoted 13 lines
arch/x86/Kconfig | 4 ++++ 1 file changed, 4 insertions(+)arch/x86/Kconfig +2
-0@@ -1714,6 +1714,10 @@ config X86_INTEL_MPX If unsure, say N. +config X86_INTEL_MEMORY_PROTECTION_KEYS + def_bool y
This is not necessary.
---
From: Borislav Petkov <[email protected]>
Date: Fri, 19 Feb 2016 12:19:50 +0100
Subject: [PATCH] x86/mm/pkeys: Do not enable them by default
No need to default to y.
--- arch/x86/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
arch/x86/Kconfig +1 -2
@@ -1719,8 +1719,7 @@ config X86_INTEL_MPX If unsure, say N. config X86_INTEL_MEMORY_PROTECTION_KEYS - prompt "Intel Memory Protection Keys" - def_bool y + bool "Intel Memory Protection Keys" # Note: only available in 64-bit mode depends on CPU_SUP_INTEL && X86_64 ---help---
Signature · 7 lines
2.3.5
--
Regards/Gruss,
Boris.
ECO tip #101: Trim your mails when you reply.Re: [PATCH] x86/mm/pkeys: Do not enable them by default
arch/x86/Kconfig config X86_INTEL_MPX · line 1725
Quoted 7 lines · Borislav Petkov
config
X86_INTEL_MEMORY_PROTECTION_KEYSarch/x86/Kconfig +1
-2- prompt "Intel Memory Protection Keys" - def_bool y + bool "Intel Memory Protection Keys" # Note: only available in 64-bit mode depends on CPU_SUP_INTEL && X86_64 ---help---
Hi Borislav,
I'd really prefer this be left on by default. This is a feature that I expect to be widely enabled in distribution kernels.
Borislav Petkov
maintainerRe: [PATCH] x86/mm/pkeys: Do not enable them by default
Quoted 2 lines · Dave Hansen
I'd really prefer this be left on by default. This is a feature that I expect to be widely enabled in distribution kernels.
Distribution kernels can enable it without defaulting to y here. Also, this code doesn't need to be built on the majority of x86 boxes out there because they don't have the hw support.
Signature · 4 lines
Regards/Gruss,
Boris.
ECO tip #101: Trim your mails when you reply.Re: [PATCH] x86/mm/pkeys: Do not enable them by default
Borislav, we're talking about 1566 bytes of text here:
Quoted 3 lines
text data bss dec hex filename
13874312 2633704 3014656 19522672 129e470 64bit-pkey/vmlinux
13872746 2633648 3014656 19521050 129de1a 64bit-nopkey/vmlinux
For gains that small, we should barely even allow this thing to be configurable, much less default it to off.
Quoted 5 lines · Borislav Petkov
Quoted 2 lines · Dave Hansen
I'd really prefer this be left on by default. This is a feature that I expect to be widely enabled in distribution kernels.
Distribution kernels can enable it without defaulting to y here.
Yes, agreed. Distros _can_ override things. But, In general, *especially* with user-visible effects, I'd really like defconfig (or other build defaults) to be reasonably close to what distributions do.
Quoted 2 lines
Also, this code doesn't need to be built on the majority of x86 boxes out there because they don't have the hw support.
My view has always been that the folks that really care about binary size are the ones that will be the ones digging through their .configs turning things off.
BTW, what percentage of x86 boxes must have a feature before we can enable it by default?
Borislav Petkov
maintainerRe: [PATCH] x86/mm/pkeys: Do not enable them by default
Quoted 2 lines · Dave Hansen
For gains that small, we should barely even allow this thing to be configurable, much less default it to off.
Well, it's not about size gains only - it is also about adding code to the kernel which is never going to be executed and also building it each time on !pkey machines.
Quoted 3 lines
Yes, agreed. Distros _can_ override things. But, In general, *especially* with user-visible effects, I'd really like defconfig (or other build defaults) to be reasonably close to what distributions do.
You can always add it to arch/x86/configs/x86_64_defconfig.
Quoted 3 lines
My view has always been that the folks that really care about binary size are the ones that will be the ones digging through their .configs turning things off.
Except when automating "make oldconfig" and then wondering why all of a sudden new features are enabled.
In my experience, it has always been the case that new features are default off. What you want to achieve can easily be done without the "def_bool y" thing.
Signature · 4 lines
Regards/Gruss,
Boris.
ECO tip #101: Trim your mails when you reply.PATCH 6/33 x86, pkeys: cpuid bit definition
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
There are two CPUID bits for protection keys. One is for whether the CPU contains the feature, and the other will appear set once the OS enables protection keys. Specifically:
Bit 04: OSPKE. If 1, OS has set CR4.PKE to enable Protection keys (and the RDPKRU/WRPKRU instructions)
This is because userspace can not see CR4 contents, but it can see CPUID contents.
X86_FEATURE_PKU is referred to as "PKU" in the hardware documentation:
CPUID.(EAX=07H,ECX=0H):ECX.PKU [bit 3]
X86_FEATURE_OSPKE is "OSPKU":
CPUID.(EAX=07H,ECX=0H):ECX.OSPKE [bit 4]
These are the first CPU features which need to look at the ECX word in CPUID leaf 0x7, so this patch also includes fetching that word in to the cpuinfo->x86_capability[] array.
Add it to the disabled-features mask when its config option is off. Even though we are not using it here, we also extend the REQUIRED_MASK_BIT_SET() macro to keep it mirroring the DISABLED_MASK_BIT_SET() version.
This means that in almost all code, you should use:
cpu_has(c, X86_FEATURE_PKU)
and *not* the CONFIG option.
---
b/arch/x86/include/asm/cpufeature.h | 61 +++++++++++++++++++---------- b/arch/x86/include/asm/disabled-features.h | 15 +++++++ b/arch/x86/include/asm/required-features.h | 7 +++ b/arch/x86/kernel/cpu/common.c | 1 4 files changed, 63 insertions(+), 21 deletions(-)
arch/x86/include/asm/cpufeature.h renamed from arch/x86/include/asm/cpufeature.h~pkeys-01-cpuid +40 -21
@@ -12,7 +12,7 @@#include <asm/disabled-features.h> #endif -#define NCAPINTS 16/* N 32-bit words worth of info */ +#define NCAPINTS 17/* N 32-bit words worth of info */ #define NBUGINTS 1/* N 32-bit bug flags */ /*
@@ -269,6 +269,10 @@#define X86_FEATURE_PAUSEFILTER (15*32+10)/* filtered pause intercept */ #define X86_FEATURE_PFTHRESHOLD (15*32+12)/* pause filter threshold */ +/* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx), word 16 */ +#define X86_FEATURE_PKU (16*32+ 3)/* Protection Keys for Userspace */ +#define X86_FEATURE_OSPKE (16*32+ 4)/* OS Protection Keys Enable */ +/* * BUG word(s) */
@@ -307,6 +311,7 @@ enum cpuid_leafsCPUID_8000_0008_EBX ,CPUID_6_EAX ,CPUID_8000_000A_EDX , + CPUID_7_ECX, };#ifdef CONFIG_X86_FEATURE_NAMES
@@ -329,28 +334,42 @@ extern const char * const x86_bug_flags[ test_bit(bit, (unsigned long *)((c)->x86_capability))#define REQUIRED_MASK_BIT_SET (bit) \ - ( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0)) || \ - (((bit)>>5)==1 && (1UL<<((bit)&31) & REQUIRED_MASK1)) || \ - (((bit)>>5)==2 && (1UL<<((bit)&31) & REQUIRED_MASK2)) || \ - (((bit)>>5)==3 && (1UL<<((bit)&31) & REQUIRED_MASK3)) || \ - (((bit)>>5)==4 && (1UL<<((bit)&31) & REQUIRED_MASK4)) || \ - (((bit)>>5)==5 && (1UL<<((bit)&31) & REQUIRED_MASK5)) || \ - (((bit)>>5)==6 && (1UL<<((bit)&31) & REQUIRED_MASK6)) || \ - (((bit)>>5)==7 && (1UL<<((bit)&31) & REQUIRED_MASK7)) || \ - (((bit)>>5)==8 && (1UL<<((bit)&31) & REQUIRED_MASK8)) || \ - (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9)) ) + ( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0 )) || \ + (((bit)>>5)==1 && (1UL<<((bit)&31) & REQUIRED_MASK1 )) || \ + (((bit)>>5)==2 && (1UL<<((bit)&31) & REQUIRED_MASK2 )) || \ + (((bit)>>5)==3 && (1UL<<((bit)&31) & REQUIRED_MASK3 )) || \ + (((bit)>>5)==4 && (1UL<<((bit)&31) & REQUIRED_MASK4 )) || \ + (((bit)>>5)==5 && (1UL<<((bit)&31) & REQUIRED_MASK5 )) || \ + (((bit)>>5)==6 && (1UL<<((bit)&31) & REQUIRED_MASK6 )) || \ + (((bit)>>5)==7 && (1UL<<((bit)&31) & REQUIRED_MASK7 )) || \ + (((bit)>>5)==8 && (1UL<<((bit)&31) & REQUIRED_MASK8 )) || \ + (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9 )) || \ + (((bit)>>5)==10 && (1UL<<((bit)&31) & REQUIRED_MASK10)) || \ + (((bit)>>5)==11 && (1UL<<((bit)&31) & REQUIRED_MASK11)) || \ + (((bit)>>5)==12 && (1UL<<((bit)&31) & REQUIRED_MASK12)) || \ + (((bit)>>5)==13 && (1UL<<((bit)&31) & REQUIRED_MASK13)) || \ + (((bit)>>5)==13 && (1UL<<((bit)&31) & REQUIRED_MASK14)) || \ + (((bit)>>5)==13 && (1UL<<((bit)&31) & REQUIRED_MASK15)) || \ + (((bit)>>5)==14 && (1UL<<((bit)&31) & REQUIRED_MASK16)) )#define DISABLED_MASK_BIT_SET (bit) \ - ( (((bit)>>5)==0 && (1UL<<((bit)&31) & DISABLED_MASK0)) || \ - (((bit)>>5)==1 && (1UL<<((bit)&31) & DISABLED_MASK1)) || \ - (((bit)>>5)==2 && (1UL<<((bit)&31) & DISABLED_MASK2)) || \ - (((bit)>>5)==3 && (1UL<<((bit)&31) & DISABLED_MASK3)) || \ - (((bit)>>5)==4 && (1UL<<((bit)&31) & DISABLED_MASK4)) || \ - (((bit)>>5)==5 && (1UL<<((bit)&31) & DISABLED_MASK5)) || \ - (((bit)>>5)==6 && (1UL<<((bit)&31) & DISABLED_MASK6)) || \ - (((bit)>>5)==7 && (1UL<<((bit)&31) & DISABLED_MASK7)) || \ - (((bit)>>5)==8 && (1UL<<((bit)&31) & DISABLED_MASK8)) || \ - (((bit)>>5)==9 && (1UL<<((bit)&31) & DISABLED_MASK9)) ) + ( (((bit)>>5)==0 && (1UL<<((bit)&31) & DISABLED_MASK0 )) || \ + (((bit)>>5)==1 && (1UL<<((bit)&31) & DISABLED_MASK1 )) || \ + (((bit)>>5)==2 && (1UL<<((bit)&31) & DISABLED_MASK2 )) || \ + (((bit)>>5)==3 && (1UL<<((bit)&31) & DISABLED_MASK3 )) || \ + (((bit)>>5)==4 && (1UL<<((bit)&31) & DISABLED_MASK4 )) || \ + (((bit)>>5)==5 && (1UL<<((bit)&31) & DISABLED_MASK5 )) || \ + (((bit)>>5)==6 && (1UL<<((bit)&31) & DISABLED_MASK6 )) || \ + (((bit)>>5)==7 && (1UL<<((bit)&31) & DISABLED_MASK7 )) || \ + (((bit)>>5)==8 && (1UL<<((bit)&31) & DISABLED_MASK8 )) || \ + (((bit)>>5)==9 && (1UL<<((bit)&31) & DISABLED_MASK9 )) || \ + (((bit)>>5)==10 && (1UL<<((bit)&31) & DISABLED_MASK10)) || \ + (((bit)>>5)==11 && (1UL<<((bit)&31) & DISABLED_MASK11)) || \ + (((bit)>>5)==12 && (1UL<<((bit)&31) & DISABLED_MASK12)) || \ + (((bit)>>5)==13 && (1UL<<((bit)&31) & DISABLED_MASK13)) || \ + (((bit)>>5)==13 && (1UL<<((bit)&31) & DISABLED_MASK14)) || \ + (((bit)>>5)==13 && (1UL<<((bit)&31) & DISABLED_MASK15)) || \ + (((bit)>>5)==14 && (1UL<<((bit)&31) & DISABLED_MASK16)) )#define cpu_has (c, bit) \ (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \
arch/x86/include/asm/disabled-features.h renamed from arch/x86/include/asm/disabled-features.h~pkeys-01-cpuid +15 -0
@@ -28,6 +28,14 @@# define DISABLE_CENTAUR_MCR 0#endif /* CONFIG_X86_64 */ +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +# define DISABLE_PKU (1<<(X86_FEATURE_PKU)) +# define DISABLE_OSPKE (1<<(X86_FEATURE_OSPKE)) +#else +# define DISABLE_PKU 0 +# define DISABLE_OSPKE 0 +#endif /* CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS */ +/* * Make sure to add features to the correct mask */
@@ -41,5 +49,12 @@#define DISABLED_MASK7 0#define DISABLED_MASK8 0#define DISABLED_MASK9 (DISABLE_MPX) +#define DISABLED_MASK10 0 +#define DISABLED_MASK11 0 +#define DISABLED_MASK12 0 +#define DISABLED_MASK13 0 +#define DISABLED_MASK14 0 +#define DISABLED_MASK15 0 +#define DISABLED_MASK16 (DISABLE_PKU|DISABLE_OSPKE)#endif /* _ASM_X86_DISABLED_FEATURES_H */
arch/x86/include/asm/required-features.h renamed from arch/x86/include/asm/required-features.h~pkeys-01-cpuid +7 -0
@@ -92,5 +92,12 @@#define REQUIRED_MASK7 0#define REQUIRED_MASK8 0#define REQUIRED_MASK9 0 +#define REQUIRED_MASK10 0 +#define REQUIRED_MASK11 0 +#define REQUIRED_MASK12 0 +#define REQUIRED_MASK13 0 +#define REQUIRED_MASK14 0 +#define REQUIRED_MASK15 0 +#define REQUIRED_MASK16 0#endif /* _ASM_X86_REQUIRED_FEATURES_H */
arch/x86/kernel/cpu/common.c renamed from arch/x86/kernel/cpu/common.c~pkeys-01-cpuid +1 -0
@@ -611,6 +611,7 @@ void get_cpu_cap(struct cpuinfo_x86 *c) c->x86_capability[CPUID_7_0_EBX ] = ebx; c->x86_capability[CPUID_6_EAX ] =cpuid_eax (0x00000006 ); + c->x86_capability[CPUID_7_ECX ] = ecx; }/* Extended state features: level 0x0000000d */
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/cpufeature, x86/mm/pkeys: Add protection keys related CPUID definitions
x86/cpufeature, x86/mm/pkeys: Add protection keys related CPUID definitions
Commit-ID: dfb4a70f20c5b3880da56ee4c9484bdb4e8f1e65 Gitweb: http://git.kernel.org/tip/dfb4a70f20c5b3880da56ee4c9484bdb4e8f1e65 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:01 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 16 Feb 2016 10:11:13 +0100
x86/cpufeature, x86/mm/pkeys: Add protection keys related CPUID definitions
There are two CPUID bits for protection keys. One is for whether the CPU contains the feature, and the other will appear set once the OS enables protection keys. Specifically:
Bit 04: OSPKE. If 1, OS has set CR4.PKE to enable Protection keys (and the RDPKRU/WRPKRU instructions)
This is because userspace can not see CR4 contents, but it can see CPUID contents.
X86_FEATURE_PKU is referred to as "PKU" in the hardware documentation:
CPUID.(EAX=07H,ECX=0H):ECX.PKU [bit 3]
X86_FEATURE_OSPKE is "OSPKU":
CPUID.(EAX=07H,ECX=0H):ECX.OSPKE [bit 4]
These are the first CPU features which need to look at the ECX word in CPUID leaf 0x7, so this patch also includes fetching that word in to the cpuinfo->x86_capability[] array.
Add it to the disabled-features mask when its config option is off. Even though we are not using it here, we also extend the REQUIRED_MASK_BIT_SET() macro to keep it mirroring the DISABLED_MASK_BIT_SET() version.
This means that in almost all code, you should use:
cpu_has(c, X86_FEATURE_PKU)
and *not* the CONFIG option.
--- arch/x86/include/asm/cpufeature.h | 59 +++++++++++++++++++++----------- arch/x86/include/asm/cpufeatures.h | 2 +- arch/x86/include/asm/disabled-features.h | 15 ++++++++ arch/x86/include/asm/required-features.h | 7 ++++ arch/x86/kernel/cpu/common.c | 1 + 5 files changed, 63 insertions(+), 21 deletions(-)
arch/x86/include/asm/cpufeature.h +39 -20
@@ -26,6 +26,7 @@ enum cpuid_leafsCPUID_8000_0008_EBX ,CPUID_6_EAX ,CPUID_8000_000A_EDX , + CPUID_7_ECX, };#ifdef CONFIG_X86_FEATURE_NAMES
@@ -48,28 +49,42 @@ extern const char * const x86_bug_flags[NBUGINTS*32]; test_bit(bit, (unsigned long *)((c)->x86_capability))#define REQUIRED_MASK_BIT_SET (bit) \ - ( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0)) || \ - (((bit)>>5)==1 && (1UL<<((bit)&31) & REQUIRED_MASK1)) || \ - (((bit)>>5)==2 && (1UL<<((bit)&31) & REQUIRED_MASK2)) || \ - (((bit)>>5)==3 && (1UL<<((bit)&31) & REQUIRED_MASK3)) || \ - (((bit)>>5)==4 && (1UL<<((bit)&31) & REQUIRED_MASK4)) || \ - (((bit)>>5)==5 && (1UL<<((bit)&31) & REQUIRED_MASK5)) || \ - (((bit)>>5)==6 && (1UL<<((bit)&31) & REQUIRED_MASK6)) || \ - (((bit)>>5)==7 && (1UL<<((bit)&31) & REQUIRED_MASK7)) || \ - (((bit)>>5)==8 && (1UL<<((bit)&31) & REQUIRED_MASK8)) || \ - (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9)) ) + ( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0 )) || \ + (((bit)>>5)==1 && (1UL<<((bit)&31) & REQUIRED_MASK1 )) || \ + (((bit)>>5)==2 && (1UL<<((bit)&31) & REQUIRED_MASK2 )) || \ + (((bit)>>5)==3 && (1UL<<((bit)&31) & REQUIRED_MASK3 )) || \ + (((bit)>>5)==4 && (1UL<<((bit)&31) & REQUIRED_MASK4 )) || \ + (((bit)>>5)==5 && (1UL<<((bit)&31) & REQUIRED_MASK5 )) || \ + (((bit)>>5)==6 && (1UL<<((bit)&31) & REQUIRED_MASK6 )) || \ + (((bit)>>5)==7 && (1UL<<((bit)&31) & REQUIRED_MASK7 )) || \ + (((bit)>>5)==8 && (1UL<<((bit)&31) & REQUIRED_MASK8 )) || \ + (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9 )) || \ + (((bit)>>5)==10 && (1UL<<((bit)&31) & REQUIRED_MASK10)) || \ + (((bit)>>5)==11 && (1UL<<((bit)&31) & REQUIRED_MASK11)) || \ + (((bit)>>5)==12 && (1UL<<((bit)&31) & REQUIRED_MASK12)) || \ + (((bit)>>5)==13 && (1UL<<((bit)&31) & REQUIRED_MASK13)) || \ + (((bit)>>5)==13 && (1UL<<((bit)&31) & REQUIRED_MASK14)) || \ + (((bit)>>5)==13 && (1UL<<((bit)&31) & REQUIRED_MASK15)) || \ + (((bit)>>5)==14 && (1UL<<((bit)&31) & REQUIRED_MASK16)) )#define DISABLED_MASK_BIT_SET (bit) \ - ( (((bit)>>5)==0 && (1UL<<((bit)&31) & DISABLED_MASK0)) || \ - (((bit)>>5)==1 && (1UL<<((bit)&31) & DISABLED_MASK1)) || \ - (((bit)>>5)==2 && (1UL<<((bit)&31) & DISABLED_MASK2)) || \ - (((bit)>>5)==3 && (1UL<<((bit)&31) & DISABLED_MASK3)) || \ - (((bit)>>5)==4 && (1UL<<((bit)&31) & DISABLED_MASK4)) || \ - (((bit)>>5)==5 && (1UL<<((bit)&31) & DISABLED_MASK5)) || \ - (((bit)>>5)==6 && (1UL<<((bit)&31) & DISABLED_MASK6)) || \ - (((bit)>>5)==7 && (1UL<<((bit)&31) & DISABLED_MASK7)) || \ - (((bit)>>5)==8 && (1UL<<((bit)&31) & DISABLED_MASK8)) || \ - (((bit)>>5)==9 && (1UL<<((bit)&31) & DISABLED_MASK9)) ) + ( (((bit)>>5)==0 && (1UL<<((bit)&31) & DISABLED_MASK0 )) || \ + (((bit)>>5)==1 && (1UL<<((bit)&31) & DISABLED_MASK1 )) || \ + (((bit)>>5)==2 && (1UL<<((bit)&31) & DISABLED_MASK2 )) || \ + (((bit)>>5)==3 && (1UL<<((bit)&31) & DISABLED_MASK3 )) || \ + (((bit)>>5)==4 && (1UL<<((bit)&31) & DISABLED_MASK4 )) || \ + (((bit)>>5)==5 && (1UL<<((bit)&31) & DISABLED_MASK5 )) || \ + (((bit)>>5)==6 && (1UL<<((bit)&31) & DISABLED_MASK6 )) || \ + (((bit)>>5)==7 && (1UL<<((bit)&31) & DISABLED_MASK7 )) || \ + (((bit)>>5)==8 && (1UL<<((bit)&31) & DISABLED_MASK8 )) || \ + (((bit)>>5)==9 && (1UL<<((bit)&31) & DISABLED_MASK9 )) || \ + (((bit)>>5)==10 && (1UL<<((bit)&31) & DISABLED_MASK10)) || \ + (((bit)>>5)==11 && (1UL<<((bit)&31) & DISABLED_MASK11)) || \ + (((bit)>>5)==12 && (1UL<<((bit)&31) & DISABLED_MASK12)) || \ + (((bit)>>5)==13 && (1UL<<((bit)&31) & DISABLED_MASK13)) || \ + (((bit)>>5)==13 && (1UL<<((bit)&31) & DISABLED_MASK14)) || \ + (((bit)>>5)==13 && (1UL<<((bit)&31) & DISABLED_MASK15)) || \ + (((bit)>>5)==14 && (1UL<<((bit)&31) & DISABLED_MASK16)) )#define cpu_has (c, bit) \ (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \
@@ -79,6 +94,10 @@ extern const char * const x86_bug_flags[NBUGINTS*32]; (__builtin_constant_p (bit) &&REQUIRED_MASK_BIT_SET (bit) ?1 : \x86_this_cpu_test_bit (bit, (unsigned long *)&cpu_info.x86_capability)) +/* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx), word 16 */ +#define X86_FEATURE_PKU (16*32+ 3)/* Protection Keys for Userspace */ +#define X86_FEATURE_OSPKE (16*32+ 4)/* OS Protection Keys Enable */ +/* * This macro is for detection of features which need kernel * infrastructure to be used. It may *not* directly test the CPU
arch/x86/include/asm/cpufeatures.h +1 -1
@@ -12,7 +12,7 @@/* * Defines x86 CPU feature bits */ -#define NCAPINTS 16/* N 32-bit words worth of info */ +#define NCAPINTS 17/* N 32-bit words worth of info */ #define NBUGINTS 1/* N 32-bit bug flags */ /*
arch/x86/include/asm/disabled-features.h +15 -0
@@ -28,6 +28,14 @@# define DISABLE_CENTAUR_MCR 0#endif /* CONFIG_X86_64 */ +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +# define DISABLE_PKU (1<<(X86_FEATURE_PKU)) +# define DISABLE_OSPKE (1<<(X86_FEATURE_OSPKE)) +#else +# define DISABLE_PKU 0 +# define DISABLE_OSPKE 0 +#endif /* CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS */ +/* * Make sure to add features to the correct mask */
@@ -41,5 +49,12 @@#define DISABLED_MASK7 0#define DISABLED_MASK8 0#define DISABLED_MASK9 (DISABLE_MPX) +#define DISABLED_MASK10 0 +#define DISABLED_MASK11 0 +#define DISABLED_MASK12 0 +#define DISABLED_MASK13 0 +#define DISABLED_MASK14 0 +#define DISABLED_MASK15 0 +#define DISABLED_MASK16 (DISABLE_PKU|DISABLE_OSPKE)#endif /* _ASM_X86_DISABLED_FEATURES_H */
arch/x86/include/asm/required-features.h +7 -0
@@ -92,5 +92,12 @@#define REQUIRED_MASK7 0#define REQUIRED_MASK8 0#define REQUIRED_MASK9 0 +#define REQUIRED_MASK10 0 +#define REQUIRED_MASK11 0 +#define REQUIRED_MASK12 0 +#define REQUIRED_MASK13 0 +#define REQUIRED_MASK14 0 +#define REQUIRED_MASK15 0 +#define REQUIRED_MASK16 0#endif /* _ASM_X86_REQUIRED_FEATURES_H */
arch/x86/kernel/cpu/common.c +1 -0
@@ -627,6 +627,7 @@ void get_cpu_cap(struct cpuinfo_x86 *c) c->x86_capability[CPUID_7_0_EBX ] = ebx; c->x86_capability[CPUID_6_EAX ] =cpuid_eax (0x00000006 ); + c->x86_capability[CPUID_7_ECX ] = ecx; }/* Extended state features: level 0x0000000d */
PATCH 7/33 x86, pkeys: define new CR4 bit
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
There is a new bit in CR4 for enabling protection keys. We will actually enable it later in the series.
---
b/arch/x86/include/uapi/asm/processor-flags.h | 2 ++ 1 file changed, 2 insertions(+)
arch/x86/include/uapi/asm/processor-flags.h renamed from arch/x86/include/uapi/asm/processor-flags.h~pkeys-02-cr4 +2 -0
@@ -118,6 +118,8 @@#define X86_CR4_SMEP _BITUL(X86_CR4_SMEP_BIT)#define X86_CR4_SMAP_BIT 21/* enable SMAP support */ #define X86_CR4_SMAP _BITUL(X86_CR4_SMAP_BIT) +#define X86_CR4_PKE_BIT 22/* enable Protection Keys support */ +#define X86_CR4_PKE _BITUL(X86_CR4_PKE_BIT)/* * x86-64 Task Priority Register, CR8
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/cpu, x86/mm/pkeys: Define new CR4 bit
x86/cpu, x86/mm/pkeys: Define new CR4 bit
Commit-ID: f28b49d2bcdb9ef9e771b3d6750f40be9d453316 Gitweb: http://git.kernel.org/tip/f28b49d2bcdb9ef9e771b3d6750f40be9d453316 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:02 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 16 Feb 2016 10:11:14 +0100
x86/cpu, x86/mm/pkeys: Define new CR4 bit
There is a new bit in CR4 for enabling protection keys. We will actually enable it later in the series.
--- arch/x86/include/uapi/asm/processor-flags.h | 2 ++ 1 file changed, 2 insertions(+)
arch/x86/include/uapi/asm/processor-flags.h +2 -0
@@ -118,6 +118,8 @@#define X86_CR4_SMEP _BITUL(X86_CR4_SMEP_BIT)#define X86_CR4_SMAP_BIT 21/* enable SMAP support */ #define X86_CR4_SMAP _BITUL(X86_CR4_SMAP_BIT) +#define X86_CR4_PKE_BIT 22/* enable Protection Keys support */ +#define X86_CR4_PKE _BITUL(X86_CR4_PKE_BIT)/* * x86-64 Task Priority Register, CR8
PATCH 8/33 x86, pkeys: add PKRU xsave fields and data structure(s)
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
The protection keys register (PKRU) is saved and restored using xsave. Define the data structure that we will use to access it inside the xsave buffer.
Note that we also have to widen the printk of the xsave feature masks since this is feature 0x200 and we only did two characters before.
---
b/arch/x86/include/asm/fpu/types.h | 11 +++++++++++ b/arch/x86/include/asm/fpu/xstate.h | 3 ++- b/arch/x86/kernel/fpu/xstate.c | 7 ++++++- 3 files changed, 19 insertions(+), 2 deletions(-)
arch/x86/include/asm/fpu/types.h renamed from arch/x86/include/asm/fpu/types.h~pkeys-03-xsave +11 -0
@@ -109,6 +109,7 @@ enum xfeature { XFEATURE_ZMM_Hi256, XFEATURE_Hi16_ZMM,XFEATURE_PT_UNIMPLEMENTED_SO_FAR , +XFEATURE_PKRU , XFEATURE_MAX, };
@@ -121,6 +122,7 @@ enum xfeature {#define XFEATURE_MASK_OPMASK (1 << XFEATURE_OPMASK)#define XFEATURE_MASK_ZMM_Hi256 (1 << XFEATURE_ZMM_Hi256)#define XFEATURE_MASK_Hi16_ZMM (1 << XFEATURE_Hi16_ZMM) +#define XFEATURE_MASK_PKRU (1 << XFEATURE_PKRU)#define XFEATURE_MASK_FPSSE (XFEATURE_MASK_FP | XFEATURE_MASK_SSE)#define XFEATURE_MASK_AVX512 (XFEATURE_MASK_OPMASK \
@@ -213,6 +215,15 @@ struct avx_512_hi16_state {struct reg_512_bit hi16_zmm[16 ]; } __packed; +/* +* State component 9: 32-bit PKRU register. The state is +* 8 bytes long but only 4 bytes is used currently. +*/ +struct pkru_state { +u32 pkru; +u32 pad; +} __packed; +struct xstate_header {u64 xfeatures;u64 xcomp_bv;
arch/x86/include/asm/fpu/xstate.h renamed from arch/x86/include/asm/fpu/xstate.h~pkeys-03-xsave +2 -1
@@ -28,7 +28,8 @@XFEATURE_MASK_YMM | \XFEATURE_MASK_OPMASK | \ XFEATURE_MASK_ZMM_Hi256 | \ - XFEATURE_MASK_Hi16_ZMM) + XFEATURE_MASK_Hi16_ZMM | \ + XFEATURE_MASK_PKRU) /* All currently supported features */ #define XCNTXT_MASK (XFEATURE_MASK_LAZY | XFEATURE_MASK_EAGER)
arch/x86/kernel/fpu/xstate.c renamed from arch/x86/kernel/fpu/xstate.c~pkeys-03-xsave +6 -1
@@ -29,6 +29,8 @@ static const char *xfeature_names[] ="AVX-512 Hi256" ,"AVX-512 ZMM_Hi256" ,"Processor Trace (unused)" , +"Protection Keys User registers" , + "unknown xstate feature" , };/*
@@ -58,6 +60,7 @@ void fpu__xstate_clear_all_cpu_caps(voidsetup_clear_cpu_cap (X86_FEATURE_AVX512CD );setup_clear_cpu_cap (X86_FEATURE_MPX );setup_clear_cpu_cap (X86_FEATURE_XGETBV1 ); +setup_clear_cpu_cap (X86_FEATURE_PKU ); }/*
@@ -236,7 +239,7 @@ static void __init print_xstate_feature(const char *feature_name;if (cpu_has_xfeatures (xstate_mask, &feature_name)) -pr_info ("x86/fpu: Supporting XSAVE feature 0x%02Lx: '%s'\n" , xstate_mask, feature_name); +pr_info ("x86/fpu: Supporting XSAVE feature 0x%03Lx: '%s'\n" , xstate_mask, feature_name); }/*
@@ -252,6 +255,7 @@ static void __init print_xstate_featuresprint_xstate_feature (XFEATURE_MASK_OPMASK );print_xstate_feature (XFEATURE_MASK_ZMM_Hi256);print_xstate_feature (XFEATURE_MASK_Hi16_ZMM); +print_xstate_feature (XFEATURE_MASK_PKRU ); }/*
@@ -468,6 +472,7 @@ static void check_xstate_against_struct( XCHECK_SZ(sz, nr, XFEATURE_OPMASK, struct avx_512_opmask_state); XCHECK_SZ(sz, nr, XFEATURE_ZMM_Hi256, struct avx_512_zmm_uppers_state); XCHECK_SZ(sz, nr, XFEATURE_Hi16_ZMM, struct avx_512_hi16_state); + XCHECK_SZ(sz, nr, XFEATURE_PKRU, struct pkru_state);/* * Make *SURE* to add any feature numbers in below if
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/fpu, x86/mm/pkeys: Add PKRU xsave fields and data structures
x86/fpu, x86/mm/pkeys: Add PKRU xsave fields and data structures
Commit-ID: c8df40098451ba18a43f22b563c9129182353158 Gitweb: http://git.kernel.org/tip/c8df40098451ba18a43f22b563c9129182353158 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:04 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 16 Feb 2016 10:11:14 +0100
x86/fpu, x86/mm/pkeys: Add PKRU xsave fields and data structures
The protection keys register (PKRU) is saved and restored using xsave. Define the data structure that we will use to access it inside the xsave buffer.
Note that we also have to widen the printk of the xsave feature masks since this is feature 0x200 and we only did two characters before.
--- arch/x86/include/asm/fpu/types.h | 11 +++++++++++ arch/x86/include/asm/fpu/xstate.h | 3 ++- arch/x86/kernel/fpu/xstate.c | 7 ++++++- 3 files changed, 19 insertions(+), 2 deletions(-)
arch/x86/include/asm/fpu/types.h +11 -0
@@ -109,6 +109,7 @@ enum xfeature { XFEATURE_ZMM_Hi256, XFEATURE_Hi16_ZMM,XFEATURE_PT_UNIMPLEMENTED_SO_FAR , +XFEATURE_PKRU , XFEATURE_MAX, };
@@ -121,6 +122,7 @@ enum xfeature {#define XFEATURE_MASK_OPMASK (1 << XFEATURE_OPMASK)#define XFEATURE_MASK_ZMM_Hi256 (1 << XFEATURE_ZMM_Hi256)#define XFEATURE_MASK_Hi16_ZMM (1 << XFEATURE_Hi16_ZMM) +#define XFEATURE_MASK_PKRU (1 << XFEATURE_PKRU)#define XFEATURE_MASK_FPSSE (XFEATURE_MASK_FP | XFEATURE_MASK_SSE)#define XFEATURE_MASK_AVX512 (XFEATURE_MASK_OPMASK \
@@ -213,6 +215,15 @@ struct avx_512_hi16_state {struct reg_512_bit hi16_zmm[16 ]; } __packed; +/* +* State component 9: 32-bit PKRU register. The state is +* 8 bytes long but only 4 bytes is used currently. +*/ +struct pkru_state { +u32 pkru; +u32 pad; +} __packed; +struct xstate_header {u64 xfeatures;u64 xcomp_bv;
arch/x86/include/asm/fpu/xstate.h +2 -1
@@ -28,7 +28,8 @@XFEATURE_MASK_YMM | \XFEATURE_MASK_OPMASK | \ XFEATURE_MASK_ZMM_Hi256 | \ - XFEATURE_MASK_Hi16_ZMM) + XFEATURE_MASK_Hi16_ZMM | \ + XFEATURE_MASK_PKRU) /* All currently supported features */ #define XCNTXT_MASK (XFEATURE_MASK_LAZY | XFEATURE_MASK_EAGER)
arch/x86/kernel/fpu/xstate.c +6 -1
@@ -29,6 +29,8 @@ static const char *xfeature_names[] ="AVX-512 Hi256" ,"AVX-512 ZMM_Hi256" ,"Processor Trace (unused)" , +"Protection Keys User registers" , + "unknown xstate feature" , };/*
@@ -58,6 +60,7 @@ void fpu__xstate_clear_all_cpu_caps(void)setup_clear_cpu_cap (X86_FEATURE_AVX512CD );setup_clear_cpu_cap (X86_FEATURE_MPX );setup_clear_cpu_cap (X86_FEATURE_XGETBV1 ); +setup_clear_cpu_cap (X86_FEATURE_PKU ); }/*
@@ -236,7 +239,7 @@ static void __init print_xstate_feature(u64 xstate_mask)const char *feature_name;if (cpu_has_xfeatures (xstate_mask, &feature_name)) -pr_info ("x86/fpu: Supporting XSAVE feature 0x%02Lx: '%s'\n" , xstate_mask, feature_name); +pr_info ("x86/fpu: Supporting XSAVE feature 0x%03Lx: '%s'\n" , xstate_mask, feature_name); }/*
@@ -252,6 +255,7 @@ static void __init print_xstate_features(void)print_xstate_feature (XFEATURE_MASK_OPMASK );print_xstate_feature (XFEATURE_MASK_ZMM_Hi256);print_xstate_feature (XFEATURE_MASK_Hi16_ZMM); +print_xstate_feature (XFEATURE_MASK_PKRU ); }/*
@@ -468,6 +472,7 @@ static void check_xstate_against_struct(int nr) XCHECK_SZ(sz, nr, XFEATURE_OPMASK, struct avx_512_opmask_state); XCHECK_SZ(sz, nr, XFEATURE_ZMM_Hi256, struct avx_512_zmm_uppers_state); XCHECK_SZ(sz, nr, XFEATURE_Hi16_ZMM, struct avx_512_hi16_state); + XCHECK_SZ(sz, nr, XFEATURE_PKRU, struct pkru_state);/* * Make *SURE* to add any feature numbers in below if
PATCH 9/33 x86, pkeys: PTE bits for storing protection key
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
Previous documentation has referred to these 4 bits as "ignored". That means that software could have made use of them. But, as far as I know, the kernel never used them.
They are still ignored when protection keys is not enabled, so they could theoretically still get used for software purposes.
We also implement "empty" versions so that code that references to them can be optimized away by the compiler when the config option is not enabled.
---
b/arch/x86/include/asm/pgtable_types.h | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-)
arch/x86/include/asm/pgtable_types.h renamed from arch/x86/include/asm/pgtable_types.h~pkeys-04-ptebits +19 -3
@@ -20,13 +20,18 @@#define _PAGE_BIT_SOFTW2 10/* " */ #define _PAGE_BIT_SOFTW3 11/* " */ #define _PAGE_BIT_PAT_LARGE 12/* On 2MB or 1GB pages */ +#define _PAGE_BIT_SOFTW4 58/* available for programmer */ +#define _PAGE_BIT_PKEY_BIT0 59/* Protection Keys, bit 1/4 */ +#define _PAGE_BIT_PKEY_BIT1 60/* Protection Keys, bit 2/4 */ +#define _PAGE_BIT_PKEY_BIT2 61/* Protection Keys, bit 3/4 */ +#define _PAGE_BIT_PKEY_BIT3 62/* Protection Keys, bit 4/4 */ +#define _PAGE_BIT_NX 63/* No execute: only valid after cpuid check */ +#define _PAGE_BIT_SPECIAL _PAGE_BIT_SOFTW1#define _PAGE_BIT_CPA_TEST _PAGE_BIT_SOFTW1#define _PAGE_BIT_HIDDEN _PAGE_BIT_SOFTW3/* hidden by kmemcheck */ #define _PAGE_BIT_SOFT_DIRTY _PAGE_BIT_SOFTW3/* software dirty tracking */ -#define _PAGE_BIT_SOFTW4 58/* available for programmer */ -#define _PAGE_BIT_DEVMAP _PAGE_BIT_SOFTW4 -#define _PAGE_BIT_NX 63/* No execute: only valid after cpuid check */ +#define _PAGE_BIT_DEVMAP _PAGE_BIT_SOFTW4/* If _PAGE_BIT_PRESENT is clear, we use these: */ /* - if the user mapped it with PROT_NONE; pte_present gives true */
@@ -47,6 +52,17 @@#define _PAGE_PAT_LARGE (_AT(pteval_t, 1) << _PAGE_BIT_PAT_LARGE)#define _PAGE_SPECIAL (_AT(pteval_t, 1) << _PAGE_BIT_SPECIAL)#define _PAGE_CPA_TEST (_AT(pteval_t, 1) << _PAGE_BIT_CPA_TEST) +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +#define _PAGE_PKEY_BIT0 (_AT(pteval_t, 1) << _PAGE_BIT_PKEY_BIT0) +#define _PAGE_PKEY_BIT1 (_AT(pteval_t, 1) << _PAGE_BIT_PKEY_BIT1) +#define _PAGE_PKEY_BIT2 (_AT(pteval_t, 1) << _PAGE_BIT_PKEY_BIT2) +#define _PAGE_PKEY_BIT3 (_AT(pteval_t, 1) << _PAGE_BIT_PKEY_BIT3) +#else +#define _PAGE_PKEY_BIT0 (_AT(pteval_t, 0)) +#define _PAGE_PKEY_BIT1 (_AT(pteval_t, 0)) +#define _PAGE_PKEY_BIT2 (_AT(pteval_t, 0)) +#define _PAGE_PKEY_BIT3 (_AT(pteval_t, 0)) +#endif #define __HAVE_ARCH_PTE_SPECIAL#ifdef CONFIG_KMEMCHECK
_
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/mm/pkeys: Add PTE bits for storing protection key
x86/mm/pkeys: Add PTE bits for storing protection key
Commit-ID: 5c1d90f51027e197e1299ab1235a2fed78910905 Gitweb: http://git.kernel.org/tip/5c1d90f51027e197e1299ab1235a2fed78910905 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:05 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 09:31:44 +0100
x86/mm/pkeys: Add PTE bits for storing protection key
Previous documentation has referred to these 4 bits as "ignored". That means that software could have made use of them. But, as far as I know, the kernel never used them.
They are still ignored when protection keys is not enabled, so they could theoretically still get used for software purposes.
We also implement "empty" versions so that code that references to them can be optimized away by the compiler when the config option is not enabled.
--- arch/x86/include/asm/pgtable_types.h | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-)
arch/x86/include/asm/pgtable_types.h +19 -3
@@ -20,13 +20,18 @@#define _PAGE_BIT_SOFTW2 10/* " */ #define _PAGE_BIT_SOFTW3 11/* " */ #define _PAGE_BIT_PAT_LARGE 12/* On 2MB or 1GB pages */ +#define _PAGE_BIT_SOFTW4 58/* available for programmer */ +#define _PAGE_BIT_PKEY_BIT0 59/* Protection Keys, bit 1/4 */ +#define _PAGE_BIT_PKEY_BIT1 60/* Protection Keys, bit 2/4 */ +#define _PAGE_BIT_PKEY_BIT2 61/* Protection Keys, bit 3/4 */ +#define _PAGE_BIT_PKEY_BIT3 62/* Protection Keys, bit 4/4 */ +#define _PAGE_BIT_NX 63/* No execute: only valid after cpuid check */ +#define _PAGE_BIT_SPECIAL _PAGE_BIT_SOFTW1#define _PAGE_BIT_CPA_TEST _PAGE_BIT_SOFTW1#define _PAGE_BIT_HIDDEN _PAGE_BIT_SOFTW3/* hidden by kmemcheck */ #define _PAGE_BIT_SOFT_DIRTY _PAGE_BIT_SOFTW3/* software dirty tracking */ -#define _PAGE_BIT_SOFTW4 58/* available for programmer */ -#define _PAGE_BIT_DEVMAP _PAGE_BIT_SOFTW4 -#define _PAGE_BIT_NX 63/* No execute: only valid after cpuid check */ +#define _PAGE_BIT_DEVMAP _PAGE_BIT_SOFTW4/* If _PAGE_BIT_PRESENT is clear, we use these: */ /* - if the user mapped it with PROT_NONE; pte_present gives true */
@@ -47,6 +52,17 @@#define _PAGE_PAT_LARGE (_AT(pteval_t, 1) << _PAGE_BIT_PAT_LARGE)#define _PAGE_SPECIAL (_AT(pteval_t, 1) << _PAGE_BIT_SPECIAL)#define _PAGE_CPA_TEST (_AT(pteval_t, 1) << _PAGE_BIT_CPA_TEST) +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +#define _PAGE_PKEY_BIT0 (_AT(pteval_t, 1) << _PAGE_BIT_PKEY_BIT0) +#define _PAGE_PKEY_BIT1 (_AT(pteval_t, 1) << _PAGE_BIT_PKEY_BIT1) +#define _PAGE_PKEY_BIT2 (_AT(pteval_t, 1) << _PAGE_BIT_PKEY_BIT2) +#define _PAGE_PKEY_BIT3 (_AT(pteval_t, 1) << _PAGE_BIT_PKEY_BIT3) +#else +#define _PAGE_PKEY_BIT0 (_AT(pteval_t, 0)) +#define _PAGE_PKEY_BIT1 (_AT(pteval_t, 0)) +#define _PAGE_PKEY_BIT2 (_AT(pteval_t, 0)) +#define _PAGE_PKEY_BIT3 (_AT(pteval_t, 0)) +#endif #define __HAVE_ARCH_PTE_SPECIAL#ifdef CONFIG_KMEMCHECK
PATCH 10/33 x86, pkeys: new page fault error code bit: PF_PK
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
Note: "PK" is how the Intel SDM refers to this bit, so we also use that nomenclature.
This only defines the bit, it does not plumb it anywhere to be handled.
---
b/arch/x86/mm/fault.c | 8 ++++++++ 1 file changed, 8 insertions(+)
arch/x86/mm/fault.c renamed from arch/x86/mm/fault.c~pkeys-05-pfec +8 -0
@@ -33,6 +33,7 @@* bit 2 == 0: kernel-mode access 1: user-mode access * bit 3 == 1: use of reserved bit detected * bit 4 == 1: fault was an instruction fetch +* bit 5 == 1: protection keys block access */ enum x86_pf_error_code {
@@ -41,6 +42,7 @@ enum x86_pf_error_code {PF_USER =1 <<2 ,PF_RSVD =1 <<3 ,PF_INSTR =1 <<4 , + PF_PK = 1 << 5, };/*
@@ -916,6 +918,12 @@ static int spurious_fault_check(unsignedif ((error_code &PF_INSTR ) && !pte_exec (*pte))return 0 ; +/* +* Note: We do not do lazy flushing on protection key +* changes, so no spurious fault will ever set PF_PK. +*/ +if ((error_code &PF_PK )) +return 1 ;return 1 ; }
_
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/mm/pkeys: Add new 'PF_PK' page fault error code bit
x86/mm/pkeys: Add new 'PF_PK' page fault error code bit
Commit-ID: b3ecd51559ae7a8f40b10443773b9cd0e6a50f5e Gitweb: http://git.kernel.org/tip/b3ecd51559ae7a8f40b10443773b9cd0e6a50f5e Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:07 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 09:31:50 +0100
x86/mm/pkeys: Add new 'PF_PK' page fault error code bit
Note: "PK" is how the Intel SDM refers to this bit, so we also use that nomenclature.
This only defines the bit, it does not plumb it anywhere to be handled.
--- arch/x86/mm/fault.c | 8 ++++++++ 1 file changed, 8 insertions(+)
arch/x86/mm/fault.c +8 -0
@@ -33,6 +33,7 @@* bit 2 == 0: kernel-mode access 1: user-mode access * bit 3 == 1: use of reserved bit detected * bit 4 == 1: fault was an instruction fetch +* bit 5 == 1: protection keys block access */ enum x86_pf_error_code {
@@ -41,6 +42,7 @@ enum x86_pf_error_code {PF_USER =1 <<2 ,PF_RSVD =1 <<3 ,PF_INSTR =1 <<4 , + PF_PK = 1 << 5, };/*
@@ -916,6 +918,12 @@ static int spurious_fault_check(unsigned long error_code, pte_t *pte)if ((error_code &PF_INSTR ) && !pte_exec (*pte))return 0 ; +/* +* Note: We do not do lazy flushing on protection key +* changes, so no spurious fault will ever set PF_PK. +*/ +if ((error_code &PF_PK )) +return 1 ;return 1 ; }
PATCH 11/33 x86, pkeys: store protection in high VMA flags
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
vma->vm_flags is an 'unsigned long', so has space for 32 flags on 32-bit architectures. The high 32 bits are unused on 64-bit platforms. We've steered away from using the unused high VMA bits for things because we would have difficulty supporting it on 32-bit.
Protection Keys are not available in 32-bit mode, so there is no concern about supporting this feature in 32-bit mode or on 32-bit CPUs.
This patch carves out 4 bits from the high half of vma->vm_flags and allows architectures to set config option to make them available.
Sparse complains about these constants unless we explicitly call them "UL".
---
b/arch/x86/Kconfig | 1 + b/include/linux/mm.h | 11 +++++++++++ b/mm/Kconfig | 3 +++ 3 files changed, 15 insertions(+)
arch/x86/Kconfig renamed from arch/x86/Kconfig~pkeys-06-eat-high-vma-flags +1 -0
@@ -155,6 +155,7 @@ config X86 select VIRT_TO_BUS select X86_DEV_DMA_OPS if X86_64 select X86_FEATURE_NAMES if PROC_FS + select ARCH_USES_HIGH_VMA_FLAGS if X86_INTEL_MEMORY_PROTECTION_KEYS config INSTRUCTION_DECODER def_bool y
include/linux/mm.h renamed from include/linux/mm.h~pkeys-06-eat-high-vma-flags +11 -0
@@ -170,6 +170,17 @@ extern unsigned int kobjsize(const void#define VM_NOHUGEPAGE 0x40000000/* MADV_NOHUGEPAGE marked this vma */ #define VM_MERGEABLE 0x80000000/* KSM may merge identical pages */ +#ifdef CONFIG_ARCH_USES_HIGH_VMA_FLAGS +#define VM_HIGH_ARCH_BIT_0 32/* bit only usable on 64-bit architectures */ +#define VM_HIGH_ARCH_BIT_1 33/* bit only usable on 64-bit architectures */ +#define VM_HIGH_ARCH_BIT_2 34/* bit only usable on 64-bit architectures */ +#define VM_HIGH_ARCH_BIT_3 35/* bit only usable on 64-bit architectures */ +#define VM_HIGH_ARCH_0 BIT(VM_HIGH_ARCH_BIT_0) +#define VM_HIGH_ARCH_1 BIT(VM_HIGH_ARCH_BIT_1) +#define VM_HIGH_ARCH_2 BIT(VM_HIGH_ARCH_BIT_2) +#define VM_HIGH_ARCH_3 BIT(VM_HIGH_ARCH_BIT_3) +#endif /* CONFIG_ARCH_USES_HIGH_VMA_FLAGS */ +#if defined(CONFIG_X86 )# define VM_PAT VM_ARCH_1/* PAT reserves whole VMA at once (x86) */ #elif defined(CONFIG_PPC )
mm/Kconfig renamed from mm/Kconfig~pkeys-06-eat-high-vma-flags +3 -0
@@ -669,3 +669,6 @@ config ZONE_DEVICE config FRAME_VECTOR bool + +config ARCH_USES_HIGH_VMA_FLAGS + bool
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] mm/core, x86/mm/pkeys: Store protection bits in high VMA flags
mm/core, x86/mm/pkeys: Store protection bits in high VMA flags
Commit-ID: 63c17fb8e5a46a16e10e82005748837fd11a2024 Gitweb: http://git.kernel.org/tip/63c17fb8e5a46a16e10e82005748837fd11a2024 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:08 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 09:31:50 +0100
mm/core, x86/mm/pkeys: Store protection bits in high VMA flags
vma->vm_flags is an 'unsigned long', so has space for 32 flags on 32-bit architectures. The high 32 bits are unused on 64-bit platforms. We've steered away from using the unused high VMA bits for things because we would have difficulty supporting it on 32-bit.
Protection Keys are not available in 32-bit mode, so there is no concern about supporting this feature in 32-bit mode or on 32-bit CPUs.
This patch carves out 4 bits from the high half of vma->vm_flags and allows architectures to set config option to make them available.
Sparse complains about these constants unless we explicitly call them "UL".
--- arch/x86/Kconfig | 1 + include/linux/mm.h | 11 +++++++++++ mm/Kconfig | 3 +++ 3 files changed, 15 insertions(+)
arch/x86/Kconfig +1 -0
@@ -155,6 +155,7 @@ config X86 select VIRT_TO_BUS select X86_DEV_DMA_OPS if X86_64 select X86_FEATURE_NAMES if PROC_FS + select ARCH_USES_HIGH_VMA_FLAGS if X86_INTEL_MEMORY_PROTECTION_KEYS config INSTRUCTION_DECODER def_bool y
include/linux/mm.h +11 -0
@@ -170,6 +170,17 @@ extern unsigned int kobjsize(const void *objp);#define VM_NOHUGEPAGE 0x40000000/* MADV_NOHUGEPAGE marked this vma */ #define VM_MERGEABLE 0x80000000/* KSM may merge identical pages */ +#ifdef CONFIG_ARCH_USES_HIGH_VMA_FLAGS +#define VM_HIGH_ARCH_BIT_0 32/* bit only usable on 64-bit architectures */ +#define VM_HIGH_ARCH_BIT_1 33/* bit only usable on 64-bit architectures */ +#define VM_HIGH_ARCH_BIT_2 34/* bit only usable on 64-bit architectures */ +#define VM_HIGH_ARCH_BIT_3 35/* bit only usable on 64-bit architectures */ +#define VM_HIGH_ARCH_0 BIT(VM_HIGH_ARCH_BIT_0) +#define VM_HIGH_ARCH_1 BIT(VM_HIGH_ARCH_BIT_1) +#define VM_HIGH_ARCH_2 BIT(VM_HIGH_ARCH_BIT_2) +#define VM_HIGH_ARCH_3 BIT(VM_HIGH_ARCH_BIT_3) +#endif /* CONFIG_ARCH_USES_HIGH_VMA_FLAGS */ +#if defined(CONFIG_X86 )# define VM_PAT VM_ARCH_1/* PAT reserves whole VMA at once (x86) */ #elif defined(CONFIG_PPC )
mm/Kconfig +3 -0
@@ -669,3 +669,6 @@ config ZONE_DEVICE config FRAME_VECTOR bool + +config ARCH_USES_HIGH_VMA_FLAGS + bool
PATCH 12/33 x86, pkeys: arch-specific protection bits
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
Lots of things seem to do:
vma->vm_page_prot = vm_get_page_prot(flags);
and the ptes get created right from things we pull out of ->vm_page_prot. So it is very convenient if we can store the protection key in flags and vm_page_prot, just like the existing permission bits (_PAGE_RW/PRESENT). It greatly reduces the amount of plumbing and arch-specific hacking we have to do in generic code.
This also takes the new PROT_PKEY{0,1,2,3} flags and turns *those* in to VM_ flags for vma->vm_flags.
The protection key values are stored in 4 places:
1. "prot" argument to system calls
2. vma->vm_flags, filled from the mmap "prot"
3. vma->vm_page prot, filled from vma->vm_flags
4. the PTE itself.
The pseudocode for these for steps are as follows:
mmap(PROT_PKEY*) vma->vm_flags = ... | arch_calc_vm_prot_bits(mmap_prot); vma->vm_page_prot = ... | arch_vm_get_page_prot(vma->vm_flags); pte = pfn | vma->vm_page_prot
Note that this provides a new definitions for x86:
arch_vm_get_page_prot()
---
b/arch/x86/include/asm/mmu_context.h | 11 +++++++++++ b/arch/x86/include/asm/pgtable_types.h | 12 ++++++++++-- b/arch/x86/include/uapi/asm/mman.h | 16 ++++++++++++++++ b/include/linux/mm.h | 7 +++++++ 4 files changed, 44 insertions(+), 2 deletions(-)
arch/x86/include/asm/mmu_context.h renamed from arch/x86/include/asm/mmu_context.h~pkeys-07-store-pkey-in-vma +11 -0
@@ -275,4 +275,15 @@ static inline void arch_unmap(struct mm_ mpx_notify_unmap(mm, vma, start, end); } +static inline int vma_pkey (struct vm_area_struct *vma) +{ +u16 pkey =0 ; +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +unsigned long vma_pkey_mask =VM_PKEY_BIT0 |VM_PKEY_BIT1 | +VM_PKEY_BIT2 |VM_PKEY_BIT3 ; + pkey = (vma->vm_flags & vma_pkey_mask) >>VM_PKEY_SHIFT ; +#endif +return pkey; +} +#endif /* _ASM_X86_MMU_CONTEXT_H */
arch/x86/include/asm/pgtable_types.h renamed from arch/x86/include/asm/pgtable_types.h~pkeys-07-store-pkey-in-vma +10 -2
@@ -115,7 +115,12 @@#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | \ _PAGE_DIRTY) -/* Set of bits not changed in pte_modify */ +/* +* Set of bits not changed in pte_modify. The pte's +* protection key is treated like _PAGE_RW, for +* instance, and is *not* included in this mask since +* pte_modify() does modify it. +*/ #define _PAGE_CHG_MASK (PTE_PFN_MASK | _PAGE_PCD | _PAGE_PWT | \ _PAGE_SPECIAL | _PAGE_ACCESSED | _PAGE_DIRTY | \ _PAGE_SOFT_DIRTY)
@@ -231,7 +236,10 @@ enum page_cache_mode {/* Extracts the PFN from a (pte|pmd|pud|pgd)val_t of a 4KB page */ #define PTE_PFN_MASK ((pteval_t)PHYSICAL_PAGE_MASK) -/* Extracts the flags from a (pte|pmd|pud|pgd)val_t of a 4KB page */ +/* +* Extracts the flags from a (pte|pmd|pud|pgd)val_t +* This includes the protection key value. +*/ #define PTE_FLAGS_MASK (~PTE_PFN_MASK)typedef struct pgprot {pgprotval_t pgprot; }pgprot_t ;
arch/x86/include/uapi/asm/mman.h renamed from arch/x86/include/uapi/asm/mman.h~pkeys-07-store-pkey-in-vma +16 -0
@@ -6,6 +6,22 @@#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT) +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +/* +* Take the 4 protection key bits out of the vma->vm_flags +* value and turn them in to the bits that we can put in +* to a pte. +* +* Only override these if Protection Keys are available +* (which is only on 64-bit). +*/ +#define arch_vm_get_page_prot (vm_flags) __pgprot( \ + ((vm_flags) & VM_PKEY_BIT0 ? _PAGE_PKEY_BIT0 : 0) | \ + ((vm_flags) & VM_PKEY_BIT1 ? _PAGE_PKEY_BIT1 : 0) | \ + ((vm_flags) & VM_PKEY_BIT2 ? _PAGE_PKEY_BIT2 : 0) | \ + ((vm_flags) & VM_PKEY_BIT3 ? _PAGE_PKEY_BIT3 : 0)) +#endif +#include <asm-generic/mman.h> #endif /* _ASM_X86_MMAN_H */
include/linux/mm.h renamed from include/linux/mm.h~pkeys-07-store-pkey-in-vma +7 -0
@@ -183,6 +183,13 @@ extern unsigned int kobjsize(const void#if defined(CONFIG_X86 )# define VM_PAT VM_ARCH_1/* PAT reserves whole VMA at once (x86) */ +#if defined (CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS ) +# define VM_PKEY_SHIFT VM_HIGH_ARCH_BIT_0 +# define VM_PKEY_BIT0 VM_HIGH_ARCH_0/* A protection key is a 4-bit value */ +# define VM_PKEY_BIT1 VM_HIGH_ARCH_1 +# define VM_PKEY_BIT2 VM_HIGH_ARCH_2 +# define VM_PKEY_BIT3 VM_HIGH_ARCH_3 +#endif #elif defined(CONFIG_PPC )# define VM_SAO VM_ARCH_1/* Strong Access Ordering (powerpc) */ #elif defined(CONFIG_PARISC )
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/mm/pkeys: Add arch-specific VMA protection bits
x86/mm/pkeys: Add arch-specific VMA protection bits
Commit-ID: 8f62c883222c9e3c06d60b5e55e307a3d1f18257 Gitweb: http://git.kernel.org/tip/8f62c883222c9e3c06d60b5e55e307a3d1f18257 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:10 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 09:31:51 +0100
x86/mm/pkeys: Add arch-specific VMA protection bits
Lots of things seem to do:
vma->vm_page_prot = vm_get_page_prot(flags);
and the ptes get created right from things we pull out of ->vm_page_prot. So it is very convenient if we can store the protection key in flags and vm_page_prot, just like the existing permission bits (_PAGE_RW/PRESENT). It greatly reduces the amount of plumbing and arch-specific hacking we have to do in generic code.
This also takes the new PROT_PKEY{0,1,2,3} flags and turns *those* in to VM_ flags for vma->vm_flags.
The protection key values are stored in 4 places:
1. "prot" argument to system calls
2. vma->vm_flags, filled from the mmap "prot"
3. vma->vm_page prot, filled from vma->vm_flags
4. the PTE itself.
The pseudocode for these for steps are as follows:
mmap(PROT_PKEY*) vma->vm_flags = ... | arch_calc_vm_prot_bits(mmap_prot); vma->vm_page_prot = ... | arch_vm_get_page_prot(vma->vm_flags); pte = pfn | vma->vm_page_prot
Note that this provides a new definitions for x86:
arch_vm_get_page_prot()
--- arch/x86/include/asm/mmu_context.h | 11 +++++++++++ arch/x86/include/asm/pgtable_types.h | 12 ++++++++++-- arch/x86/include/uapi/asm/mman.h | 16 ++++++++++++++++ include/linux/mm.h | 7 +++++++ 4 files changed, 44 insertions(+), 2 deletions(-)
arch/x86/include/asm/mmu_context.h +11 -0
@@ -275,4 +275,15 @@ static inline void arch_unmap(struct mm_struct *mm, struct vm_area_struct *vma, mpx_notify_unmap(mm, vma, start, end); } +static inline int vma_pkey (struct vm_area_struct *vma) +{ +u16 pkey =0 ; +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +unsigned long vma_pkey_mask =VM_PKEY_BIT0 |VM_PKEY_BIT1 | +VM_PKEY_BIT2 |VM_PKEY_BIT3 ; + pkey = (vma->vm_flags & vma_pkey_mask) >>VM_PKEY_SHIFT ; +#endif +return pkey; +} +#endif /* _ASM_X86_MMU_CONTEXT_H */
arch/x86/include/asm/pgtable_types.h +10 -2
@@ -115,7 +115,12 @@#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | \ _PAGE_DIRTY) -/* Set of bits not changed in pte_modify */ +/* +* Set of bits not changed in pte_modify. The pte's +* protection key is treated like _PAGE_RW, for +* instance, and is *not* included in this mask since +* pte_modify() does modify it. +*/ #define _PAGE_CHG_MASK (PTE_PFN_MASK | _PAGE_PCD | _PAGE_PWT | \ _PAGE_SPECIAL | _PAGE_ACCESSED | _PAGE_DIRTY | \ _PAGE_SOFT_DIRTY)
@@ -231,7 +236,10 @@ enum page_cache_mode {/* Extracts the PFN from a (pte|pmd|pud|pgd)val_t of a 4KB page */ #define PTE_PFN_MASK ((pteval_t)PHYSICAL_PAGE_MASK) -/* Extracts the flags from a (pte|pmd|pud|pgd)val_t of a 4KB page */ +/* +* Extracts the flags from a (pte|pmd|pud|pgd)val_t +* This includes the protection key value. +*/ #define PTE_FLAGS_MASK (~PTE_PFN_MASK)typedef struct pgprot {pgprotval_t pgprot; }pgprot_t ;
arch/x86/include/uapi/asm/mman.h +16 -0
@@ -6,6 +6,22 @@#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT) +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +/* +* Take the 4 protection key bits out of the vma->vm_flags +* value and turn them in to the bits that we can put in +* to a pte. +* +* Only override these if Protection Keys are available +* (which is only on 64-bit). +*/ +#define arch_vm_get_page_prot (vm_flags) __pgprot( \ + ((vm_flags) & VM_PKEY_BIT0 ? _PAGE_PKEY_BIT0 : 0) | \ + ((vm_flags) & VM_PKEY_BIT1 ? _PAGE_PKEY_BIT1 : 0) | \ + ((vm_flags) & VM_PKEY_BIT2 ? _PAGE_PKEY_BIT2 : 0) | \ + ((vm_flags) & VM_PKEY_BIT3 ? _PAGE_PKEY_BIT3 : 0)) +#endif +#include <asm-generic/mman.h> #endif /* _ASM_X86_MMAN_H */
include/linux/mm.h +7 -0
@@ -183,6 +183,13 @@ extern unsigned int kobjsize(const void *objp);#if defined(CONFIG_X86 )# define VM_PAT VM_ARCH_1/* PAT reserves whole VMA at once (x86) */ +#if defined (CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS ) +# define VM_PKEY_SHIFT VM_HIGH_ARCH_BIT_0 +# define VM_PKEY_BIT0 VM_HIGH_ARCH_0/* A protection key is a 4-bit value */ +# define VM_PKEY_BIT1 VM_HIGH_ARCH_1 +# define VM_PKEY_BIT2 VM_HIGH_ARCH_2 +# define VM_PKEY_BIT3 VM_HIGH_ARCH_3 +#endif #elif defined(CONFIG_PPC )# define VM_SAO VM_ARCH_1/* Strong Access Ordering (powerpc) */ #elif defined(CONFIG_PARISC )
PATCH 13/33 x86, pkeys: pass VMA down in to fault signal generation code
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
During a page fault, we look up the VMA to ensure that the fault is in a region with a valid mapping. But, in the top-level page fault code we don't need the VMA for much else. Once we have decided that an access is bad, we are going to send a signal no matter what and do not need the VMA any more. So we do not pass it down in to the signal generation code.
But, for protection keys, we need the VMA. It tells us *which* protection key we violated if we get a PF_PK. So, we need to pass the VMA down and fill in siginfo->si_pkey.
---
b/arch/x86/mm/fault.c | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-)
arch/x86/mm/fault.c renamed from arch/x86/mm/fault.c~pkeys-08-pass-down-vma +28 -22
@@ -171,7 +171,8 @@ is_prefetch(struct pt_regs *regs, unsignstatic void force_sig_info_fault (int si_signo,int si_code,unsigned long address, -struct task_struct *tsk,int fault) +struct task_struct *tsk,struct vm_area_struct *vma, +int fault) {unsigned lsb =0 ;siginfo_t info;
@@ -656,6 +657,8 @@ no_context(struct pt_regs *regs, unsignestruct task_struct *tsk = current;unsigned long flags;int sig; +/* No context means no VMA to pass down */ +struct vm_area_struct *vma =NULL ;/* Are we prepared to handle this kernel fault? */ if (fixup_exception (regs)) {
@@ -679,7 +682,8 @@ no_context(struct pt_regs *regs, unsigne tsk->thread.cr2 = address;/* XXX: hwpoison faults will set the wrong code. */ -force_sig_info_fault (signal, si_code, address, tsk,0 ); +force_sig_info_fault (signal, si_code, address, + tsk, vma,0 ); }/*
@@ -756,7 +760,8 @@ show_signal_msg(struct pt_regs *regs, unstatic void __bad_area_nosemaphore (struct pt_regs *regs,unsigned long error_code, -unsigned long address,int si_code) +unsigned long address,struct vm_area_struct *vma, +int si_code) {struct task_struct *tsk = current;
@@ -799,7 +804,7 @@ __bad_area_nosemaphore(struct pt_regs *r tsk->thread.error_code = error_code; tsk->thread.trap_nr =X86_TRAP_PF ; -force_sig_info_fault (SIGSEGV , si_code, address, tsk,0 ); +force_sig_info_fault (SIGSEGV , si_code, address, tsk, vma,0 );return ; }
@@ -812,14 +817,14 @@ __bad_area_nosemaphore(struct pt_regs *r static noinline voidbad_area_nosemaphore (struct pt_regs *regs,unsigned long error_code, -unsigned long address) +unsigned long address,struct vm_area_struct *vma) { -__bad_area_nosemaphore (regs, error_code, address,SEGV_MAPERR ); +__bad_area_nosemaphore (regs, error_code, address, vma,SEGV_MAPERR ); }static void __bad_area (struct pt_regs *regs,unsigned long error_code, -unsigned long address,int si_code) +unsigned long address,struct vm_area_struct *vma,int si_code) {struct mm_struct *mm = current->mm;
@@ -829,25 +834,25 @@ __bad_area(struct pt_regs *regs, unsigne*/ up_read (&mm->mmap_sem); -__bad_area_nosemaphore (regs, error_code, address, si_code); +__bad_area_nosemaphore (regs, error_code, address, vma, si_code); } static noinline voidbad_area (struct pt_regs *regs,unsigned long error_code,unsigned long address) { -__bad_area (regs, error_code, address,SEGV_MAPERR ); +__bad_area (regs, error_code, address,NULL ,SEGV_MAPERR ); } static noinline voidbad_area_access_error (struct pt_regs *regs,unsigned long error_code, -unsigned long address) +unsigned long address,struct vm_area_struct *vma) { -__bad_area (regs, error_code, address,SEGV_ACCERR ); +__bad_area (regs, error_code, address, vma,SEGV_ACCERR ); }static void do_sigbus (struct pt_regs *regs,unsigned long error_code,unsigned long address, -unsigned int fault) +struct vm_area_struct *vma,unsigned int fault) {struct task_struct *tsk = current;int code =BUS_ADRERR ;
@@ -874,12 +879,13 @@ do_sigbus(struct pt_regs *regs, unsigned code =BUS_MCEERR_AR ; }#endif -force_sig_info_fault (SIGBUS , code, address, tsk, fault); +force_sig_info_fault (SIGBUS , code, address, tsk, vma, fault); } static noinline voidmm_fault_error (struct pt_regs *regs,unsigned long error_code, -unsigned long address,unsigned int fault) +unsigned long address,struct vm_area_struct *vma, +unsigned int fault) {if (fatal_signal_pending (current) && !(error_code &PF_USER )) {no_context (regs, error_code, address,0 ,0 );
@@ -903,9 +909,9 @@ mm_fault_error(struct pt_regs *regs, uns }else {if (fault & (VM_FAULT_SIGBUS |VM_FAULT_HWPOISON |VM_FAULT_HWPOISON_LARGE )) -do_sigbus (regs, error_code, address, fault); +do_sigbus (regs, error_code, address, vma, fault);else if (fault &VM_FAULT_SIGSEGV ) -bad_area_nosemaphore (regs, error_code, address); +bad_area_nosemaphore (regs, error_code, address, vma);else BUG (); }
@@ -1119,7 +1125,7 @@ __do_page_fault(struct pt_regs *regs, un* Don't take the mm semaphore here. If we fixup a prefetch * fault we could otherwise deadlock: */ -bad_area_nosemaphore (regs, error_code, address); +bad_area_nosemaphore (regs, error_code, address,NULL );return ; }
@@ -1132,7 +1138,7 @@ __do_page_fault(struct pt_regs *regs, unpgtable_bad (regs, error_code, address);if (unlikely (smap_violation (error_code, regs))) { -bad_area_nosemaphore (regs, error_code, address); +bad_area_nosemaphore (regs, error_code, address,NULL );return ; }
@@ -1141,7 +1147,7 @@ __do_page_fault(struct pt_regs *regs, un* in a region with pagefaults disabled then we must not take the fault */ if (unlikely (faulthandler_disabled () || !mm)) { -bad_area_nosemaphore (regs, error_code, address); +bad_area_nosemaphore (regs, error_code, address,NULL );return ; }
@@ -1185,7 +1191,7 @@ __do_page_fault(struct pt_regs *regs, unif (unlikely (!down_read_trylock (&mm->mmap_sem))) {if ((error_code &PF_USER ) ==0 && !search_exception_tables (regs->ip)) { -bad_area_nosemaphore (regs, error_code, address); +bad_area_nosemaphore (regs, error_code, address,NULL );return ; } retry:
@@ -1233,7 +1239,7 @@ retry:*/ good_area:if (unlikely (access_error (error_code, vma))) { -bad_area_access_error (regs, error_code, address); +bad_area_access_error (regs, error_code, address, vma);return ; }
@@ -1271,7 +1277,7 @@ good_area:up_read (&mm->mmap_sem);if (unlikely (fault &VM_FAULT_ERROR )) { -mm_fault_error (regs, error_code, address, fault); +mm_fault_error (regs, error_code, address, vma, fault);return ; }
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/mm/pkeys: Pass VMA down in to fault signal generation code
x86/mm/pkeys: Pass VMA down in to fault signal generation code
Commit-ID: 7b2d0dbac4890c8ca4a8acc57709639fc8b158e9 Gitweb: http://git.kernel.org/tip/7b2d0dbac4890c8ca4a8acc57709639fc8b158e9 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:11 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 09:31:51 +0100
x86/mm/pkeys: Pass VMA down in to fault signal generation code
During a page fault, we look up the VMA to ensure that the fault is in a region with a valid mapping. But, in the top-level page fault code we don't need the VMA for much else. Once we have decided that an access is bad, we are going to send a signal no matter what and do not need the VMA any more. So we do not pass it down in to the signal generation code.
But, for protection keys, we need the VMA. It tells us *which* protection key we violated if we get a PF_PK. So, we need to pass the VMA down and fill in siginfo->si_pkey.
--- arch/x86/mm/fault.c | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-)
arch/x86/mm/fault.c +28 -22
@@ -171,7 +171,8 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr)static void force_sig_info_fault (int si_signo,int si_code,unsigned long address, -struct task_struct *tsk,int fault) +struct task_struct *tsk,struct vm_area_struct *vma, +int fault) {unsigned lsb =0 ;siginfo_t info;
@@ -656,6 +657,8 @@ no_context(struct pt_regs *regs, unsigned long error_code,struct task_struct *tsk = current;unsigned long flags;int sig; +/* No context means no VMA to pass down */ +struct vm_area_struct *vma =NULL ;/* Are we prepared to handle this kernel fault? */ if (fixup_exception (regs)) {
@@ -679,7 +682,8 @@ no_context(struct pt_regs *regs, unsigned long error_code, tsk->thread.cr2 = address;/* XXX: hwpoison faults will set the wrong code. */ -force_sig_info_fault (signal, si_code, address, tsk,0 ); +force_sig_info_fault (signal, si_code, address, + tsk, vma,0 ); }/*
@@ -756,7 +760,8 @@ show_signal_msg(struct pt_regs *regs, unsigned long error_code,static void __bad_area_nosemaphore (struct pt_regs *regs,unsigned long error_code, -unsigned long address,int si_code) +unsigned long address,struct vm_area_struct *vma, +int si_code) {struct task_struct *tsk = current;
@@ -799,7 +804,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, tsk->thread.error_code = error_code; tsk->thread.trap_nr =X86_TRAP_PF ; -force_sig_info_fault (SIGSEGV , si_code, address, tsk,0 ); +force_sig_info_fault (SIGSEGV , si_code, address, tsk, vma,0 );return ; }
@@ -812,14 +817,14 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, static noinline voidbad_area_nosemaphore (struct pt_regs *regs,unsigned long error_code, -unsigned long address) +unsigned long address,struct vm_area_struct *vma) { -__bad_area_nosemaphore (regs, error_code, address,SEGV_MAPERR ); +__bad_area_nosemaphore (regs, error_code, address, vma,SEGV_MAPERR ); }static void __bad_area (struct pt_regs *regs,unsigned long error_code, -unsigned long address,int si_code) +unsigned long address,struct vm_area_struct *vma,int si_code) {struct mm_struct *mm = current->mm;
@@ -829,25 +834,25 @@ __bad_area(struct pt_regs *regs, unsigned long error_code,*/ up_read (&mm->mmap_sem); -__bad_area_nosemaphore (regs, error_code, address, si_code); +__bad_area_nosemaphore (regs, error_code, address, vma, si_code); } static noinline voidbad_area (struct pt_regs *regs,unsigned long error_code,unsigned long address) { -__bad_area (regs, error_code, address,SEGV_MAPERR ); +__bad_area (regs, error_code, address,NULL ,SEGV_MAPERR ); } static noinline voidbad_area_access_error (struct pt_regs *regs,unsigned long error_code, -unsigned long address) +unsigned long address,struct vm_area_struct *vma) { -__bad_area (regs, error_code, address,SEGV_ACCERR ); +__bad_area (regs, error_code, address, vma,SEGV_ACCERR ); }static void do_sigbus (struct pt_regs *regs,unsigned long error_code,unsigned long address, -unsigned int fault) +struct vm_area_struct *vma,unsigned int fault) {struct task_struct *tsk = current;int code =BUS_ADRERR ;
@@ -874,12 +879,13 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, code =BUS_MCEERR_AR ; }#endif -force_sig_info_fault (SIGBUS , code, address, tsk, fault); +force_sig_info_fault (SIGBUS , code, address, tsk, vma, fault); } static noinline voidmm_fault_error (struct pt_regs *regs,unsigned long error_code, -unsigned long address,unsigned int fault) +unsigned long address,struct vm_area_struct *vma, +unsigned int fault) {if (fatal_signal_pending (current) && !(error_code &PF_USER )) {no_context (regs, error_code, address,0 ,0 );
@@ -903,9 +909,9 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code, }else {if (fault & (VM_FAULT_SIGBUS |VM_FAULT_HWPOISON |VM_FAULT_HWPOISON_LARGE )) -do_sigbus (regs, error_code, address, fault); +do_sigbus (regs, error_code, address, vma, fault);else if (fault &VM_FAULT_SIGSEGV ) -bad_area_nosemaphore (regs, error_code, address); +bad_area_nosemaphore (regs, error_code, address, vma);else BUG (); }
@@ -1119,7 +1125,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code,* Don't take the mm semaphore here. If we fixup a prefetch * fault we could otherwise deadlock: */ -bad_area_nosemaphore (regs, error_code, address); +bad_area_nosemaphore (regs, error_code, address,NULL );return ; }
@@ -1132,7 +1138,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code,pgtable_bad (regs, error_code, address);if (unlikely (smap_violation (error_code, regs))) { -bad_area_nosemaphore (regs, error_code, address); +bad_area_nosemaphore (regs, error_code, address,NULL );return ; }
@@ -1141,7 +1147,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code,* in a region with pagefaults disabled then we must not take the fault */ if (unlikely (faulthandler_disabled () || !mm)) { -bad_area_nosemaphore (regs, error_code, address); +bad_area_nosemaphore (regs, error_code, address,NULL );return ; }
@@ -1185,7 +1191,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code,if (unlikely (!down_read_trylock (&mm->mmap_sem))) {if ((error_code &PF_USER ) ==0 && !search_exception_tables (regs->ip)) { -bad_area_nosemaphore (regs, error_code, address); +bad_area_nosemaphore (regs, error_code, address,NULL );return ; } retry:
@@ -1233,7 +1239,7 @@ retry:*/ good_area:if (unlikely (access_error (error_code, vma))) { -bad_area_access_error (regs, error_code, address); +bad_area_access_error (regs, error_code, address, vma);return ; }
@@ -1271,7 +1277,7 @@ good_area:up_read (&mm->mmap_sem);if (unlikely (fault &VM_FAULT_ERROR )) { -mm_fault_error (regs, error_code, address, fault); +mm_fault_error (regs, error_code, address, vma, fault);return ; }
PATCH 14/33 signals, pkeys: notify userspace about protection key faults
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
A protection key fault is very similar to any other access error. There must be a VMA, etc... We even want to take the same action (SIGSEGV) that we do with a normal access fault.
However, we do need to let userspace know that something is different. We do this the same way what we did with SEGV_BNDERR with Memory Protection eXtensions (MPX): define a new SEGV code:SEGV_PKUERR.
We add a siginfo field: si_pkey that reveals to userspace which protection key was set on the PTE that we faulted on. There is no other easy way for userspace to figure this out. They could parse smaps but that would be a bit cruel.
We share space with in siginfo with _addr_bnd. #BR faults from MPX are completely separate from page faults (#PF) that trigger from protection key violations, so we never need both at the same time.
Note that _pkey is a 64-bit value. The current hardware only supports 4-bit protection keys. We do this because there is _plenty_ of space in _sigfault and it is possible that future processors would support more than 4 bits of protection keys.
The x86 code to actually fill in the siginfo is in the next patch.
---
b/include/uapi/asm-generic/siginfo.h | 17 ++++++++++++----- b/kernel/signal.c | 4 ++++ 2 files changed, 16 insertions(+), 5 deletions(-)
include/uapi/asm-generic/siginfo.h renamed from include/uapi/asm-generic/siginfo.h~pkeys-09-siginfo-core +12 -5
@@ -91,10 +91,15 @@ typedef struct siginfo {int _trapno;/* TRAP # which caused the signal */ #endif short _addr_lsb;/* LSB of the reported address */ -struct { -void __user *_lower; -void __user *_upper; - } _addr_bnd; +union { +/* used when si_code=SEGV_BNDERR */ +struct { +void __user *_lower; +void __user *_upper; + } _addr_bnd; +/* used when si_code=SEGV_PKUERR */ +u64 _pkey; + }; } _sigfault;/* SIGPOLL */
@@ -137,6 +142,7 @@ typedef struct siginfo {#define si_addr_lsb _sifields._sigfault._addr_lsb#define si_lower _sifields._sigfault._addr_bnd._lower#define si_upper _sifields._sigfault._addr_bnd._upper +#define si_pkey _sifields._sigfault._pkey#define si_band _sifields._sigpoll._band#define si_fd _sifields._sigpoll._fd#ifdef __ARCH_SIGSYS
@@ -206,7 +212,8 @@ typedef struct siginfo {#define SEGV_MAPERR (__SI_FAULT|1)/* address not mapped to object */ #define SEGV_ACCERR (__SI_FAULT|2)/* invalid permissions for mapped object */ #define SEGV_BNDERR (__SI_FAULT|3)/* failed address bound checks */ -#define NSIGSEGV 3 +#define SEGV_PKUERR (__SI_FAULT|4)/* failed protection key checks */ +#define NSIGSEGV 4/* * SIGBUS si_codes
kernel/signal.c renamed from kernel/signal.c~pkeys-09-siginfo-core +4 -0
@@ -2709,6 +2709,10 @@ int copy_siginfo_to_user(siginfo_t __use err |= __put_user(from->si_upper, &to->si_upper); }#endif +#ifdef SEGV_PKUERR +if (from->si_signo ==SIGSEGV && from->si_code ==SEGV_PKUERR ) + err |=__put_user (from->si_pkey, &to->si_pkey); +#endif break ;case __SI_CHLD: err |=__put_user (from->si_pid, &to->si_pid);
_
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] signals, pkeys: Notify userspace about protection key faults
signals, pkeys: Notify userspace about protection key faults
Commit-ID: cd0ea35ff5511cde299a61c21a95889b4a71464e Gitweb: http://git.kernel.org/tip/cd0ea35ff5511cde299a61c21a95889b4a71464e Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:12 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 09:32:42 +0100
signals, pkeys: Notify userspace about protection key faults
A protection key fault is very similar to any other access error. There must be a VMA, etc... We even want to take the same action (SIGSEGV) that we do with a normal access fault.
However, we do need to let userspace know that something is different. We do this the same way what we did with SEGV_BNDERR with Memory Protection eXtensions (MPX): define a new SEGV code:SEGV_PKUERR.
We add a siginfo field: si_pkey that reveals to userspace which protection key was set on the PTE that we faulted on. There is no other easy way for userspace to figure this out. They could parse smaps but that would be a bit cruel.
We share space with in siginfo with _addr_bnd. #BR faults from MPX are completely separate from page faults (#PF) that trigger from protection key violations, so we never need both at the same time.
Note that _pkey is a 64-bit value. The current hardware only supports 4-bit protection keys. We do this because there is _plenty_ of space in _sigfault and it is possible that future processors would support more than 4 bits of protection keys.
The x86 code to actually fill in the siginfo is in the next patch.
--- include/uapi/asm-generic/siginfo.h | 17 ++++++++++++----- kernel/signal.c | 4 ++++ 2 files changed, 16 insertions(+), 5 deletions(-)
include/uapi/asm-generic/siginfo.h +12 -5
@@ -91,10 +91,15 @@ typedef struct siginfo {int _trapno;/* TRAP # which caused the signal */ #endif short _addr_lsb;/* LSB of the reported address */ -struct { -void __user *_lower; -void __user *_upper; - } _addr_bnd; +union { +/* used when si_code=SEGV_BNDERR */ +struct { +void __user *_lower; +void __user *_upper; + } _addr_bnd; +/* used when si_code=SEGV_PKUERR */ +u64 _pkey; + }; } _sigfault;/* SIGPOLL */
@@ -137,6 +142,7 @@ typedef struct siginfo {#define si_addr_lsb _sifields._sigfault._addr_lsb#define si_lower _sifields._sigfault._addr_bnd._lower#define si_upper _sifields._sigfault._addr_bnd._upper +#define si_pkey _sifields._sigfault._pkey#define si_band _sifields._sigpoll._band#define si_fd _sifields._sigpoll._fd#ifdef __ARCH_SIGSYS
@@ -206,7 +212,8 @@ typedef struct siginfo {#define SEGV_MAPERR (__SI_FAULT|1)/* address not mapped to object */ #define SEGV_ACCERR (__SI_FAULT|2)/* invalid permissions for mapped object */ #define SEGV_BNDERR (__SI_FAULT|3)/* failed address bound checks */ -#define NSIGSEGV 3 +#define SEGV_PKUERR (__SI_FAULT|4)/* failed protection key checks */ +#define NSIGSEGV 4/* * SIGBUS si_codes
kernel/signal.c +4 -0
@@ -2709,6 +2709,10 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from) err |= __put_user(from->si_upper, &to->si_upper); }#endif +#ifdef SEGV_PKUERR +if (from->si_signo ==SIGSEGV && from->si_code ==SEGV_PKUERR ) + err |=__put_user (from->si_pkey, &to->si_pkey); +#endif break ;case __SI_CHLD: err |=__put_user (from->si_pid, &to->si_pid);
PATCH 15/33 x86, pkeys: fill in pkey field in siginfo
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
This fills in the new siginfo field: si_pkey to indicate to userspace which protection key was set on the PTE that we faulted on.
Note though that *ALL* protection key faults have to be generated by a valid, present PTE at some point. But this code does no PTE lookups which seeds odd. The reason is that we take advantage of the way we generate PTEs from VMAs. All PTEs under a VMA share some attributes. For instance, they are _all_ either PROT_READ *OR* PROT_NONE. They also always share a protection key, so we never have to walk the page tables; we just use the VMA.
Note that _pkey is a 64-bit value. The current hardware only supports 4-bit protection keys. We do this because there is _plenty_ of space in _sigfault and it is possible that future processors would support more than 4 bits of protection keys.
---
b/arch/x86/include/asm/pgtable_types.h | 5 ++ b/arch/x86/mm/fault.c | 64 ++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-)
arch/x86/include/asm/pgtable_types.h renamed from arch/x86/include/asm/pgtable_types.h~pkeys-09-siginfo-x86 +5 -0
@@ -65,6 +65,11 @@#endif #define __HAVE_ARCH_PTE_SPECIAL +#define _PAGE_PKEY_MASK (_PAGE_PKEY_BIT0 | \ + _PAGE_PKEY_BIT1 | \ + _PAGE_PKEY_BIT2 | \ + _PAGE_PKEY_BIT3) +#ifdef CONFIG_KMEMCHECK #define _PAGE_HIDDEN (_AT(pteval_t, 1) << _PAGE_BIT_HIDDEN)#else
arch/x86/mm/fault.c renamed from arch/x86/mm/fault.c~pkeys-09-siginfo-x86 +63 -1
94 lines not on this page · raw message
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/mm/pkeys: Fill in pkey field in siginfo
x86/mm/pkeys: Fill in pkey field in siginfo
Commit-ID: 019132ff3daf36c97a4006655dfd00ee42f2b590 Gitweb: http://git.kernel.org/tip/019132ff3daf36c97a4006655dfd00ee42f2b590 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:14 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 09:32:43 +0100
x86/mm/pkeys: Fill in pkey field in siginfo
This fills in the new siginfo field: si_pkey to indicate to userspace which protection key was set on the PTE that we faulted on.
Note though that *ALL* protection key faults have to be generated by a valid, present PTE at some point. But this code does no PTE lookups which seeds odd. The reason is that we take advantage of the way we generate PTEs from VMAs. All PTEs under a VMA share some attributes. For instance, they are _all_ either PROT_READ *OR* PROT_NONE. They also always share a protection key, so we never have to walk the page tables; we just use the VMA.
Note that _pkey is a 64-bit value. The current hardware only supports 4-bit protection keys. We do this because there is _plenty_ of space in _sigfault and it is possible that future processors would support more than 4 bits of protection keys.
--- arch/x86/include/asm/pgtable_types.h | 5 +++ arch/x86/mm/fault.c | 64 +++++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-)
arch/x86/include/asm/pgtable_types.h +5 -0
@@ -65,6 +65,11 @@#endif #define __HAVE_ARCH_PTE_SPECIAL +#define _PAGE_PKEY_MASK (_PAGE_PKEY_BIT0 | \ + _PAGE_PKEY_BIT1 | \ + _PAGE_PKEY_BIT2 | \ + _PAGE_PKEY_BIT3) +#ifdef CONFIG_KMEMCHECK #define _PAGE_HIDDEN (_AT(pteval_t, 1) << _PAGE_BIT_HIDDEN)#else
arch/x86/mm/fault.c +63 -1
94 lines not on this page · raw message
PATCH 16/33 x86, pkeys: add functions to fetch PKRU
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
This adds the raw instruction to access PKRU as well as some accessor functions that correctly handle when the CPU does not support the instruction. We don't use it here, but we will use read_pkru() in the next patch.
---
b/arch/x86/include/asm/pgtable.h | 8 ++++++++ b/arch/x86/include/asm/special_insns.h | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+)
arch/x86/include/asm/pgtable.h renamed from arch/x86/include/asm/pgtable.h~pkeys-10-kernel-pkru-instructions +8 -0
@@ -99,6 +99,14 @@ static inline int pte_dirty(pte_t pte)return pte_flags (pte) & _PAGE_DIRTY; } + +static inline u32 read_pkru (void ) +{ +if (boot_cpu_has (X86_FEATURE_OSPKE )) +return __read_pkru (); +return 0 ; +} +static inline int pte_young (pte_t pte) {return pte_flags (pte) & _PAGE_ACCESSED;
arch/x86/include/asm/special_insns.h renamed from arch/x86/include/asm/special_insns.h~pkeys-10-kernel-pkru-instructions +22 -0
@@ -98,6 +98,28 @@ static inline void native_write_cr8(unsi }#endif +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +static inline u32 __read_pkru (void ) +{ +u32 ecx =0 ; +u32 edx, pkru; + +/* +* "rdpkru" instruction. Places PKRU contents in to EAX, +* clears EDX and requires that ecx=0. +*/ + asmvolatile (".byte 0x0f,0x01,0xee\n\t" + :"=a" (pkru),"=d" (edx) + :"c" (ecx)); +return pkru; +} +#else +static inline u32 __read_pkru (void ) +{ +return 0 ; +} +#endif +static inline void native_wbinvd (void ) { asmvolatile ("wbinvd" : : :"memory" );
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/mm/pkeys: Add functions to fetch PKRU
x86/mm/pkeys: Add functions to fetch PKRU
Commit-ID: a927cb83f3300bcb1ae18672e58029acddd18b33 Gitweb: http://git.kernel.org/tip/a927cb83f3300bcb1ae18672e58029acddd18b33 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:15 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 09:32:43 +0100
x86/mm/pkeys: Add functions to fetch PKRU
This adds the raw instruction to access PKRU as well as some accessor functions that correctly handle when the CPU does not support the instruction. We don't use it here, but we will use read_pkru() in the next patch.
--- arch/x86/include/asm/pgtable.h | 8 ++++++++ arch/x86/include/asm/special_insns.h | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+)
arch/x86/include/asm/pgtable.h +8 -0
@@ -99,6 +99,14 @@ static inline int pte_dirty(pte_t pte)return pte_flags (pte) & _PAGE_DIRTY; } + +static inline u32 read_pkru (void ) +{ +if (boot_cpu_has (X86_FEATURE_OSPKE )) +return __read_pkru (); +return 0 ; +} +static inline int pte_young (pte_t pte) {return pte_flags (pte) & _PAGE_ACCESSED;
arch/x86/include/asm/special_insns.h +22 -0
@@ -98,6 +98,28 @@ static inline void native_write_cr8(unsigned long val) }#endif +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +static inline u32 __read_pkru (void ) +{ +u32 ecx =0 ; +u32 edx, pkru; + +/* +* "rdpkru" instruction. Places PKRU contents in to EAX, +* clears EDX and requires that ecx=0. +*/ + asmvolatile (".byte 0x0f,0x01,0xee\n\t" + :"=a" (pkru),"=d" (edx) + :"c" (ecx)); +return pkru; +} +#else +static inline u32 __read_pkru (void ) +{ +return 0 ; +} +#endif +static inline void native_wbinvd (void ) { asmvolatile ("wbinvd" : : :"memory" );
PATCH 17/33 mm: factor out VMA fault permission checking
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
This code matches a fault condition up with the VMA and ensures that the VMA allows the fault to be handled instead of just erroring out.
We will be extending this in a moment to comprehend protection keys.
---
b/mm/gup.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
mm/gup.c renamed from mm/gup.c~pkeys-10-pte-fault +13 -3
@@ -610,6 +610,18 @@ next_page: }EXPORT_SYMBOL (__get_user_pages); +bool vma_permits_fault (struct vm_area_struct *vma,unsigned int fault_flags) +{ +vm_flags_t vm_flags; + + vm_flags = (fault_flags &FAULT_FLAG_WRITE ) ?VM_WRITE :VM_READ ; + +if (!(vm_flags & vma->vm_flags)) +return false; + +return true; +} +/* * fixup_user_fault() - manually resolve a user page fault * @tsk: the task_struct to use for page fault accounting, or
@@ -645,7 +657,6 @@ int fixup_user_fault(struct task_struct bool *unlocked) {struct vm_area_struct *vma; -vm_flags_t vm_flags;int ret, major =0 ;if (unlocked)
@@ -656,8 +667,7 @@ retry:if (!vma || address < vma->vm_start)return -EFAULT ; - vm_flags = (fault_flags &FAULT_FLAG_WRITE ) ?VM_WRITE :VM_READ ; -if (!(vm_flags & vma->vm_flags)) +if (!vma_permits_fault (vma, fault_flags))return -EFAULT ; ret =handle_mm_fault (mm, vma, address, fault_flags);
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] mm/gup: Factor out VMA fault permission checking
mm/gup: Factor out VMA fault permission checking
Commit-ID: d4925e00d59698a201231cf99dce47d8b922bb34 Gitweb: http://git.kernel.org/tip/d4925e00d59698a201231cf99dce47d8b922bb34 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:16 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 09:32:43 +0100
mm/gup: Factor out VMA fault permission checking
This code matches a fault condition up with the VMA and ensures that the VMA allows the fault to be handled instead of just erroring out.
We will be extending this in a moment to comprehend protection keys.
--- mm/gup.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
mm/gup.c +13 -3
@@ -610,6 +610,18 @@ next_page: }EXPORT_SYMBOL (__get_user_pages); +bool vma_permits_fault (struct vm_area_struct *vma,unsigned int fault_flags) +{ +vm_flags_t vm_flags; + + vm_flags = (fault_flags &FAULT_FLAG_WRITE ) ?VM_WRITE :VM_READ ; + +if (!(vm_flags & vma->vm_flags)) +return false; + +return true; +} +/* * fixup_user_fault() - manually resolve a user page fault * @tsk: the task_struct to use for page fault accounting, or
@@ -645,7 +657,6 @@ int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm, bool *unlocked) {struct vm_area_struct *vma; -vm_flags_t vm_flags;int ret, major =0 ;if (unlocked)
@@ -656,8 +667,7 @@ retry:if (!vma || address < vma->vm_start)return -EFAULT ; - vm_flags = (fault_flags &FAULT_FLAG_WRITE ) ?VM_WRITE :VM_READ ; -if (!(vm_flags & vma->vm_flags)) +if (!vma_permits_fault (vma, fault_flags))return -EFAULT ; ret =handle_mm_fault (mm, vma, address, fault_flags);
PATCH 18/33 x86, mm: simplify get_user_pages() PTE bit handling
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
The current get_user_pages() code is a wee bit more complicated than it needs to be for pte bit checking. Currently, it establishes a mask of required pte _PAGE_* bits and ensures that the pte it goes after has all those bits.
This consolidates the three identical copies of this code.
---
b/arch/x86/mm/gup.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-)
arch/x86/mm/gup.c renamed from arch/x86/mm/gup.c~pkeys-12-gup-swizzle +22 -16
@@ -75,6 +75,24 @@ static void undo_dev_pagemap(int *nr, in }/* +* 'pteval' can come from a pte, pmd or pud. We only check +* _PAGE_PRESENT, _PAGE_USER, and _PAGE_RW in here which are the +* same value on all 3 types. +*/ +static inline int pte_allows_gup (unsigned long pteval,int write) +{ +unsigned long need_pte_bits = _PAGE_PRESENT|_PAGE_USER; + +if (write) + need_pte_bits |= _PAGE_RW; + +if ((pteval & need_pte_bits) != need_pte_bits) +return 0 ; + +return 1 ; +} + +/* * The performance critical leaf functions are made noinline otherwise gcc * inlines everything into a single function which results in too much * register pressure.
@@ -83,14 +101,9 @@ static noinline int gup_pte_range(pmd_t unsigned long end, int write, struct page **pages, int *nr) { struct dev_pagemap *pgmap = NULL; -unsigned long mask;int nr_start = *nr;pte_t *ptep; - mask = _PAGE_PRESENT|_PAGE_USER; -if (write) - mask |= _PAGE_RW; - ptep =pte_offset_map (&pmd, addr); do { pte_t pte = gup_get_pte(ptep);
@@ -110,7 +123,8 @@ static noinline int gup_pte_range(pmd_tpte_unmap (ptep);return 0 ; } - }else if ((pte_flags (pte) & (mask | _PAGE_SPECIAL)) != mask) { + }else if (!pte_allows_gup (pte_val (pte), write) || +pte_special (pte)) {pte_unmap (ptep);return 0 ; }
@@ -164,14 +178,10 @@ static int __gup_device_huge_pmd(pmd_t p static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,unsigned long end,int write,struct page **pages,int *nr) { -unsigned long mask;struct page *head, *page;int refs; - mask = _PAGE_PRESENT|_PAGE_USER; -if (write) - mask |= _PAGE_RW; -if ((pmd_flags (pmd) & mask) != mask) +if (!pte_allows_gup (pmd_val (pmd), write))return 0 ;VM_BUG_ON (!pfn_valid (pmd_pfn (pmd)));
@@ -231,14 +241,10 @@ static int gup_pmd_range(pud_t pud, unsi static noinline int gup_huge_pud(pud_t pud, unsigned long addr,unsigned long end,int write,struct page **pages,int *nr) { -unsigned long mask;struct page *head, *page;int refs; - mask = _PAGE_PRESENT|_PAGE_USER; -if (write) - mask |= _PAGE_RW; -if ((pud_flags (pud) & mask) != mask) +if (!pte_allows_gup (pud_val (pud), write))return 0 ;/* hugepages are never "special" */ VM_BUG_ON (pud_flags (pud) & _PAGE_SPECIAL);
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/mm/gup: Simplify get_user_pages() PTE bit handling
x86/mm/gup: Simplify get_user_pages() PTE bit handling
Commit-ID: 1874f6895c92d991ccf85edcc55a0d9dd552d71c Gitweb: http://git.kernel.org/tip/1874f6895c92d991ccf85edcc55a0d9dd552d71c Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:18 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 09:32:44 +0100
x86/mm/gup: Simplify get_user_pages() PTE bit handling
The current get_user_pages() code is a wee bit more complicated than it needs to be for pte bit checking. Currently, it establishes a mask of required pte _PAGE_* bits and ensures that the pte it goes after has all those bits.
This consolidates the three identical copies of this code.
--- arch/x86/mm/gup.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-)
arch/x86/mm/gup.c +22 -16
@@ -75,6 +75,24 @@ static void undo_dev_pagemap(int *nr, int nr_start, struct page **pages) }/* +* 'pteval' can come from a pte, pmd or pud. We only check +* _PAGE_PRESENT, _PAGE_USER, and _PAGE_RW in here which are the +* same value on all 3 types. +*/ +static inline int pte_allows_gup (unsigned long pteval,int write) +{ +unsigned long need_pte_bits = _PAGE_PRESENT|_PAGE_USER; + +if (write) + need_pte_bits |= _PAGE_RW; + +if ((pteval & need_pte_bits) != need_pte_bits) +return 0 ; + +return 1 ; +} + +/* * The performance critical leaf functions are made noinline otherwise gcc * inlines everything into a single function which results in too much * register pressure.
@@ -83,14 +101,9 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end, int write, struct page **pages, int *nr) { struct dev_pagemap *pgmap = NULL; -unsigned long mask;int nr_start = *nr;pte_t *ptep; - mask = _PAGE_PRESENT|_PAGE_USER; -if (write) - mask |= _PAGE_RW; - ptep =pte_offset_map (&pmd, addr); do { pte_t pte = gup_get_pte(ptep);
@@ -110,7 +123,8 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,pte_unmap (ptep);return 0 ; } - }else if ((pte_flags (pte) & (mask | _PAGE_SPECIAL)) != mask) { + }else if (!pte_allows_gup (pte_val (pte), write) || +pte_special (pte)) {pte_unmap (ptep);return 0 ; }
@@ -164,14 +178,10 @@ static int __gup_device_huge_pmd(pmd_t pmd, unsigned long addr, static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,unsigned long end,int write,struct page **pages,int *nr) { -unsigned long mask;struct page *head, *page;int refs; - mask = _PAGE_PRESENT|_PAGE_USER; -if (write) - mask |= _PAGE_RW; -if ((pmd_flags (pmd) & mask) != mask) +if (!pte_allows_gup (pmd_val (pmd), write))return 0 ;VM_BUG_ON (!pfn_valid (pmd_pfn (pmd)));
@@ -231,14 +241,10 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end, static noinline int gup_huge_pud(pud_t pud, unsigned long addr,unsigned long end,int write,struct page **pages,int *nr) { -unsigned long mask;struct page *head, *page;int refs; - mask = _PAGE_PRESENT|_PAGE_USER; -if (write) - mask |= _PAGE_RW; -if ((pud_flags (pud) & mask) != mask) +if (!pte_allows_gup (pud_val (pud), write))return 0 ;/* hugepages are never "special" */ VM_BUG_ON (pud_flags (pud) & _PAGE_SPECIAL);
PATCH 19/33 x86, pkeys: check VMAs and PTEs for protection keys
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
Today, for normal faults and page table walks, we check the VMA and/or PTE to ensure that it is compatible with the action. For instance, if we get a write fault on a non-writeable VMA, we SIGSEGV.
We try to do the same thing for protection keys. Basically, we try to make sure that if a user does this:
mprotect(ptr, size, PROT_NONE); *ptr = foo;
they see the same effects with protection keys when they do this:
mprotect(ptr, size, PROT_READ|PROT_WRITE); set_pkey(ptr, size, 4); wrpkru(0xffffff3f); // access disable pkey 4 *ptr = foo;
The state to do that checking is in the VMA, but we also sometimes have to do it on the page tables only, like when doing a get_user_pages_fast() where we have no VMA.
We add two functions and expose them to generic code:
arch_pte_access_permitted(pte_flags, write) arch_vma_access_permitted(vma, write)
These are, of course, backed up in x86 arch code with checks against the PTE or VMA's protection key.
But, there are also cases where we do not want to respect protection keys. When we ptrace(), for instance, we do not want to apply the tracer's PKRU permissions to the PTEs from the process being traced.
---
b/arch/powerpc/include/asm/mmu_context.h | 11 ++++++ b/arch/s390/include/asm/mmu_context.h | 11 ++++++ b/arch/unicore32/include/asm/mmu_context.h | 11 ++++++ b/arch/x86/include/asm/mmu_context.h | 49 +++++++++++++++++++++++++++++ b/arch/x86/include/asm/pgtable.h | 29 +++++++++++++++++ b/arch/x86/mm/fault.c | 21 +++++++++++- b/arch/x86/mm/gup.c | 5 ++ b/include/asm-generic/mm_hooks.h | 11 ++++++ b/mm/gup.c | 18 ++++++++-- b/mm/memory.c | 4 ++ 10 files changed, 166 insertions(+), 4 deletions(-)
arch/powerpc/include/asm/mmu_context.h renamed from arch/powerpc/include/asm/mmu_context.h~pkeys-13-pte-fault +11 -0
@@ -148,5 +148,16 @@ static inline void arch_bprm_mm_init(str { } +static inline bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write) +{ +/* by default, allow everything */ +return true; +} + +static inline bool arch_pte_access_permitted (pte_t pte,bool write) +{ +/* by default, allow everything */ +return true; +}#endif /* __KERNEL__ */ #endif /* __ASM_POWERPC_MMU_CONTEXT_H */
arch/s390/include/asm/mmu_context.h renamed from arch/s390/include/asm/mmu_context.h~pkeys-13-pte-fault +11 -0
@@ -130,4 +130,15 @@ static inline void arch_bprm_mm_init(str { } +static inline bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write) +{ +/* by default, allow everything */ +return true; +} + +static inline bool arch_pte_access_permitted (pte_t pte,bool write) +{ +/* by default, allow everything */ +return true; +}#endif /* __S390_MMU_CONTEXT_H */
arch/unicore32/include/asm/mmu_context.h renamed from arch/unicore32/include/asm/mmu_context.h~pkeys-13-pte-fault +11 -0
@@ -97,4 +97,15 @@ static inline void arch_bprm_mm_init(str { } +static inline bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write) +{ +/* by default, allow everything */ +return true; +} + +static inline bool arch_pte_access_permitted (pte_t pte,bool write) +{ +/* by default, allow everything */ +return true; +}#endif
arch/x86/include/asm/mmu_context.h renamed from arch/x86/include/asm/mmu_context.h~pkeys-13-pte-fault +49 -0
53 lines not on this page · raw message
arch/x86/include/asm/pgtable.h renamed from arch/x86/include/asm/pgtable.h~pkeys-13-pte-fault +29 -0
@@ -919,6 +919,35 @@ static inline pte_t pte_swp_clear_soft_d }#endif +#define PKRU_AD_BIT 0x1 +#define PKRU_WD_BIT 0x2 + +static inline bool __pkru_allows_read (u32 pkru,u16 pkey) +{ +int pkru_pkey_bits = pkey *2 ; +return !(pkru & (PKRU_AD_BIT << pkru_pkey_bits)); +} + +static inline bool __pkru_allows_write (u32 pkru,u16 pkey) +{ +int pkru_pkey_bits = pkey *2 ; +/* +* Access-disable disables writes too so we need to check +* both bits here. +*/ +return !(pkru & ((PKRU_AD_BIT |PKRU_WD_BIT ) << pkru_pkey_bits)); +} + +static inline u16 pte_flags_pkey (unsigned long pte_flags) +{ +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +/* ifdef to avoid doing 59-bit shift on 32-bit values */ +return (pte_flags & _PAGE_PKEY_MASK) >> _PAGE_BIT_PKEY_BIT0; +#else +return 0 ; +#endif +} +#include <asm-generic/pgtable.h> #endif /* __ASSEMBLY__ */
arch/x86/mm/fault.c renamed from arch/x86/mm/fault.c~pkeys-13-pte-fault +20 -1
@@ -897,6 +897,16 @@ bad_area(struct pt_regs *regs, unsigned__bad_area (regs, error_code, address,NULL ,SEGV_MAPERR ); } +static inline bool bad_area_access_from_pkeys (unsigned long error_code, +struct vm_area_struct *vma) +{ +if (!boot_cpu_has (X86_FEATURE_OSPKE )) +return false; +if (error_code &PF_PK ) +return true; +return false; +} + static noinline voidbad_area_access_error (struct pt_regs *regs,unsigned long error_code,unsigned long address,struct vm_area_struct *vma)
@@ -906,7 +916,7 @@ bad_area_access_error(struct pt_regs *re* But, doing it this way allows compiler optimizations * if pkeys are compiled out. */ -if (boot_cpu_has (X86_FEATURE_OSPKE ) && (error_code &PF_PK )) +if (bad_area_access_from_pkeys (error_code, vma))__bad_area (regs, error_code, address, vma,SEGV_PKUERR );else __bad_area (regs, error_code, address, vma,SEGV_ACCERR );
@@ -1081,6 +1091,15 @@ int show_unhandled_signals = 1;static inline int access_error (unsigned long error_code,struct vm_area_struct *vma) { +/* +* Access or read was blocked by protection keys. We do +* this check before any others because we do not want +* to, for instance, confuse a protection-key-denied +* write with one for which we should do a COW. +*/ +if (error_code &PF_PK ) +return 1 ; +if (error_code &PF_WRITE ) {/* write, present and write, not present: */ if (unlikely (!(vma->vm_flags &VM_WRITE )))
arch/x86/mm/gup.c renamed from arch/x86/mm/gup.c~pkeys-13-pte-fault +5 -0
@@ -11,6 +11,7 @@#include <linux/swap.h> #include <linux/memremap.h> +#include <asm/mmu_context.h> #include <asm/pgtable.h> static inline pte_t gup_get_pte (pte_t *ptep)
@@ -89,6 +90,10 @@ static inline int pte_allows_gup(unsigneif ((pteval & need_pte_bits) != need_pte_bits)return 0 ; +/* Check memory protection keys permissions. */ +if (!__pkru_allows_pkey (pte_flags_pkey (pteval), write)) +return 0 ; +return 1 ; }
include/asm-generic/mm_hooks.h renamed from include/asm-generic/mm_hooks.h~pkeys-13-pte-fault +11 -0
@@ -26,4 +26,15 @@ static inline void arch_bprm_mm_init(str { } +static inline bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write) +{ +/* by default, allow everything */ +return true; +} + +static inline bool arch_pte_access_permitted (pte_t pte,bool write) +{ +/* by default, allow everything */ +return true; +}#endif /* _ASM_GENERIC_MM_HOOKS_H */
mm/gup.c renamed from mm/gup.c~pkeys-13-pte-fault +15 -3
@@ -15,6 +15,7 @@#include <linux/rwsem.h> #include <linux/hugetlb.h> +#include <asm/mmu_context.h> #include <asm/pgtable.h> #include <asm/tlbflush.h>
@@ -444,6 +445,8 @@ static int check_vma_flags(struct vm_areif (!(vm_flags &VM_MAYREAD ))return -EFAULT ; } +if (!arch_vma_access_permitted (vma, (gup_flags &FOLL_WRITE ))) +return -EFAULT ;return 0 ; }
@@ -612,13 +615,19 @@ EXPORT_SYMBOL(__get_user_pages);bool vma_permits_fault (struct vm_area_struct *vma,unsigned int fault_flags) { -vm_flags_t vm_flags; - - vm_flags = (fault_flags &FAULT_FLAG_WRITE ) ?VM_WRITE :VM_READ ; +bool write = !!(fault_flags &FAULT_FLAG_WRITE ); +vm_flags_t vm_flags = write ?VM_WRITE :VM_READ ;if (!(vm_flags & vma->vm_flags))return false; +/* +* The architecture might have a hardware protection +* mechanism other than read/write that can deny access +*/ +if (!arch_vma_access_permitted (vma, write)) +return false; +return true; }
@@ -1172,6 +1181,9 @@ static int gup_pte_range(pmd_t pmd, unsi pte_protnone(pte) || (write && !pte_write(pte))) goto pte_unmap; +if (!arch_pte_access_permitted (pte, write)) + goto pte_unmap; +VM_BUG_ON (!pfn_valid (pte_pfn (pte))); page =pte_page (pte); head =compound_head (page);
mm/memory.c renamed from mm/memory.c~pkeys-13-pte-fault +4 -0
@@ -65,6 +65,7 @@#include <linux/userfaultfd_k.h> #include <asm/io.h> +#include <asm/mmu_context.h> #include <asm/pgalloc.h> #include <asm/uaccess.h> #include <asm/tlb.h>
@@ -3357,6 +3358,9 @@ static int __handle_mm_fault(struct mm_spmd_t *pmd;pte_t *pte; +if (!arch_vma_access_permitted (vma, flags &FAULT_FLAG_WRITE )) +return VM_FAULT_SIGSEGV ; +if (unlikely (is_vm_hugetlb_page (vma)))return hugetlb_fault (mm, vma, address, flags);
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] mm/gup, x86/mm/pkeys: Check VMAs and PTEs for protection keys
mm/gup, x86/mm/pkeys: Check VMAs and PTEs for protection keys
Commit-ID: 33a709b25a760b91184bb335cf7d7c32b8123013 Gitweb: http://git.kernel.org/tip/33a709b25a760b91184bb335cf7d7c32b8123013 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:19 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 09:32:44 +0100
mm/gup, x86/mm/pkeys: Check VMAs and PTEs for protection keys
Today, for normal faults and page table walks, we check the VMA and/or PTE to ensure that it is compatible with the action. For instance, if we get a write fault on a non-writeable VMA, we SIGSEGV.
We try to do the same thing for protection keys. Basically, we try to make sure that if a user does this:
mprotect(ptr, size, PROT_NONE); *ptr = foo;
they see the same effects with protection keys when they do this:
mprotect(ptr, size, PROT_READ|PROT_WRITE); set_pkey(ptr, size, 4); wrpkru(0xffffff3f); // access disable pkey 4 *ptr = foo;
The state to do that checking is in the VMA, but we also sometimes have to do it on the page tables only, like when doing a get_user_pages_fast() where we have no VMA.
We add two functions and expose them to generic code:
arch_pte_access_permitted(pte_flags, write) arch_vma_access_permitted(vma, write)
These are, of course, backed up in x86 arch code with checks against the PTE or VMA's protection key.
But, there are also cases where we do not want to respect protection keys. When we ptrace(), for instance, we do not want to apply the tracer's PKRU permissions to the PTEs from the process being traced.
--- arch/powerpc/include/asm/mmu_context.h | 11 +++++++ arch/s390/include/asm/mmu_context.h | 11 +++++++ arch/unicore32/include/asm/mmu_context.h | 11 +++++++ arch/x86/include/asm/mmu_context.h | 49 ++++++++++++++++++++++++++++++++ arch/x86/include/asm/pgtable.h | 29 +++++++++++++++++++ arch/x86/mm/fault.c | 21 +++++++++++++- arch/x86/mm/gup.c | 5 ++++ include/asm-generic/mm_hooks.h | 11 +++++++ mm/gup.c | 18 ++++++++++-- mm/memory.c | 4 +++ 10 files changed, 166 insertions(+), 4 deletions(-)
arch/powerpc/include/asm/mmu_context.h +11 -0
@@ -148,5 +148,16 @@ static inline void arch_bprm_mm_init(struct mm_struct *mm, { } +static inline bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write) +{ +/* by default, allow everything */ +return true; +} + +static inline bool arch_pte_access_permitted (pte_t pte,bool write) +{ +/* by default, allow everything */ +return true; +}#endif /* __KERNEL__ */ #endif /* __ASM_POWERPC_MMU_CONTEXT_H */
arch/s390/include/asm/mmu_context.h +11 -0
@@ -130,4 +130,15 @@ static inline void arch_bprm_mm_init(struct mm_struct *mm, { } +static inline bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write) +{ +/* by default, allow everything */ +return true; +} + +static inline bool arch_pte_access_permitted (pte_t pte,bool write) +{ +/* by default, allow everything */ +return true; +}#endif /* __S390_MMU_CONTEXT_H */
arch/unicore32/include/asm/mmu_context.h +11 -0
@@ -97,4 +97,15 @@ static inline void arch_bprm_mm_init(struct mm_struct *mm, { } +static inline bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write) +{ +/* by default, allow everything */ +return true; +} + +static inline bool arch_pte_access_permitted (pte_t pte,bool write) +{ +/* by default, allow everything */ +return true; +}#endif
arch/x86/include/asm/mmu_context.h +49 -0
53 lines not on this page · raw message
arch/x86/include/asm/pgtable.h +29 -0
@@ -919,6 +919,35 @@ static inline pte_t pte_swp_clear_soft_dirty(pte_t pte) }#endif +#define PKRU_AD_BIT 0x1 +#define PKRU_WD_BIT 0x2 + +static inline bool __pkru_allows_read (u32 pkru,u16 pkey) +{ +int pkru_pkey_bits = pkey *2 ; +return !(pkru & (PKRU_AD_BIT << pkru_pkey_bits)); +} + +static inline bool __pkru_allows_write (u32 pkru,u16 pkey) +{ +int pkru_pkey_bits = pkey *2 ; +/* +* Access-disable disables writes too so we need to check +* both bits here. +*/ +return !(pkru & ((PKRU_AD_BIT |PKRU_WD_BIT ) << pkru_pkey_bits)); +} + +static inline u16 pte_flags_pkey (unsigned long pte_flags) +{ +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +/* ifdef to avoid doing 59-bit shift on 32-bit values */ +return (pte_flags & _PAGE_PKEY_MASK) >> _PAGE_BIT_PKEY_BIT0; +#else +return 0 ; +#endif +} +#include <asm-generic/pgtable.h> #endif /* __ASSEMBLY__ */
arch/x86/mm/fault.c +20 -1
@@ -897,6 +897,16 @@ bad_area(struct pt_regs *regs, unsigned long error_code, unsigned long address)__bad_area (regs, error_code, address,NULL ,SEGV_MAPERR ); } +static inline bool bad_area_access_from_pkeys (unsigned long error_code, +struct vm_area_struct *vma) +{ +if (!boot_cpu_has (X86_FEATURE_OSPKE )) +return false; +if (error_code &PF_PK ) +return true; +return false; +} + static noinline voidbad_area_access_error (struct pt_regs *regs,unsigned long error_code,unsigned long address,struct vm_area_struct *vma)
@@ -906,7 +916,7 @@ bad_area_access_error(struct pt_regs *regs, unsigned long error_code,* But, doing it this way allows compiler optimizations * if pkeys are compiled out. */ -if (boot_cpu_has (X86_FEATURE_OSPKE ) && (error_code &PF_PK )) +if (bad_area_access_from_pkeys (error_code, vma))__bad_area (regs, error_code, address, vma,SEGV_PKUERR );else __bad_area (regs, error_code, address, vma,SEGV_ACCERR );
@@ -1081,6 +1091,15 @@ int show_unhandled_signals = 1;static inline int access_error (unsigned long error_code,struct vm_area_struct *vma) { +/* +* Access or read was blocked by protection keys. We do +* this check before any others because we do not want +* to, for instance, confuse a protection-key-denied +* write with one for which we should do a COW. +*/ +if (error_code &PF_PK ) +return 1 ; +if (error_code &PF_WRITE ) {/* write, present and write, not present: */ if (unlikely (!(vma->vm_flags &VM_WRITE )))
arch/x86/mm/gup.c +5 -0
@@ -11,6 +11,7 @@#include <linux/swap.h> #include <linux/memremap.h> +#include <asm/mmu_context.h> #include <asm/pgtable.h> static inline pte_t gup_get_pte (pte_t *ptep)
@@ -89,6 +90,10 @@ static inline int pte_allows_gup(unsigned long pteval, int write)if ((pteval & need_pte_bits) != need_pte_bits)return 0 ; +/* Check memory protection keys permissions. */ +if (!__pkru_allows_pkey (pte_flags_pkey (pteval), write)) +return 0 ; +return 1 ; }
include/asm-generic/mm_hooks.h +11 -0
@@ -26,4 +26,15 @@ static inline void arch_bprm_mm_init(struct mm_struct *mm, { } +static inline bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write) +{ +/* by default, allow everything */ +return true; +} + +static inline bool arch_pte_access_permitted (pte_t pte,bool write) +{ +/* by default, allow everything */ +return true; +}#endif /* _ASM_GENERIC_MM_HOOKS_H */
mm/gup.c +15 -3
@@ -15,6 +15,7 @@#include <linux/rwsem.h> #include <linux/hugetlb.h> +#include <asm/mmu_context.h> #include <asm/pgtable.h> #include <asm/tlbflush.h>
@@ -444,6 +445,8 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags)if (!(vm_flags &VM_MAYREAD ))return -EFAULT ; } +if (!arch_vma_access_permitted (vma, (gup_flags &FOLL_WRITE ))) +return -EFAULT ;return 0 ; }
@@ -612,13 +615,19 @@ EXPORT_SYMBOL(__get_user_pages);bool vma_permits_fault (struct vm_area_struct *vma,unsigned int fault_flags) { -vm_flags_t vm_flags; - - vm_flags = (fault_flags &FAULT_FLAG_WRITE ) ?VM_WRITE :VM_READ ; +bool write = !!(fault_flags &FAULT_FLAG_WRITE ); +vm_flags_t vm_flags = write ?VM_WRITE :VM_READ ;if (!(vm_flags & vma->vm_flags))return false; +/* +* The architecture might have a hardware protection +* mechanism other than read/write that can deny access +*/ +if (!arch_vma_access_permitted (vma, write)) +return false; +return true; }
@@ -1172,6 +1181,9 @@ static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end, pte_protnone(pte) || (write && !pte_write(pte))) goto pte_unmap; +if (!arch_pte_access_permitted (pte, write)) + goto pte_unmap; +VM_BUG_ON (!pfn_valid (pte_pfn (pte))); page =pte_page (pte); head =compound_head (page);
mm/memory.c +4 -0
@@ -65,6 +65,7 @@#include <linux/userfaultfd_k.h> #include <asm/io.h> +#include <asm/mmu_context.h> #include <asm/pgalloc.h> #include <asm/uaccess.h> #include <asm/tlb.h>
@@ -3378,6 +3379,9 @@ static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,pmd_t *pmd;pte_t *pte; +if (!arch_vma_access_permitted (vma, flags &FAULT_FLAG_WRITE )) +return VM_FAULT_SIGSEGV ; +if (unlikely (is_vm_hugetlb_page (vma)))return hugetlb_fault (mm, vma, address, flags);
PATCH 20/33 mm: do not enforce PKEY permissions on "foreign" mm access
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
We try to enforce protection keys in software the same way that we do in hardware. (See long example below).
But, we only want to do this when accessing our *own* process's memory. If GDB set PKRU[6].AD=1 (disable access to PKEY 6), then tried to PTRACE_POKE a target process which just happened to have some mprotect_pkey(pkey=6) memory, we do *not* want to deny the debugger access to that memory. PKRU is fundamentally a thread-local structure and we do not want to enforce it on access to _another_ thread's data.
This gets especially tricky when we have workqueues or other delayed-work mechanisms that might run in a random process's context. We can check that we only enforce pkeys when operating on our *own* mm, but delayed work gets performed when a random user context is active. We might end up with a situation where a delayed-work gup fails when running randomly under its "own" task but succeeds when running under another process. We want to avoid that.
To avoid that, we use the new GUP flag: FOLL_REMOTE and add a fault flag: FAULT_FLAG_REMOTE. They indicate that we are walking an mm which is not guranteed to be the same as current->mm and should not be subject to protection key enforcement.
Thanks to Jerome Glisse for pointing out this scenario.
*** Why do we enforce protection keys in software?? ***
Imagine that we disabled access to the memory pointer to by 'buf'. The, we implemented sys_write() like this:
sys_read(fd, buf, len...)
{
struct page *page = follow_page(buf);
void *buf_mapped = kmap(page);
memcpy(buf_mapped, fd_data, len);
...
}This writes to 'buf' via a *kernel* mapping, without a protection key. While this implementation does the same thing:
sys_read(fd, buf, len...)
{
copy_to_user(buf, fd_data, len);
...
}but would hit a protection key fault because the userspace 'buf' mapping has a protection key set.
To provide consistency, and to make key-protected memory work as much like mprotect()ed memory as possible, we try to enforce the same protections as the hardware would when the *kernel* walks the page tables (and other mm structures).
---
b/arch/powerpc/include/asm/mmu_context.h | 3 ++- b/arch/s390/include/asm/mmu_context.h | 3 ++- b/arch/unicore32/include/asm/mmu_context.h | 3 ++- b/arch/x86/include/asm/mmu_context.h | 5 +++-- b/drivers/iommu/amd_iommu_v2.c | 1 + b/include/asm-generic/mm_hooks.h | 3 ++- b/include/linux/mm.h | 1 + b/mm/gup.c | 15 ++++++++++----- b/mm/ksm.c | 10 ++++++++-- b/mm/memory.c | 3 ++- 10 files changed, 33 insertions(+), 14 deletions(-)
arch/powerpc/include/asm/mmu_context.h renamed from arch/powerpc/include/asm/mmu_context.h~pkeys-14-gup-fault-foreign-flag +2 -1
@@ -148,7 +148,8 @@ static inline void arch_bprm_mm_init(str { } -static inline bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write) +static inline bool arch_vma_access_permitted (struct vm_area_struct *vma, +bool write,bool foreign) {/* by default, allow everything */ return true;
arch/s390/include/asm/mmu_context.h renamed from arch/s390/include/asm/mmu_context.h~pkeys-14-gup-fault-foreign-flag +2 -1
@@ -130,7 +130,8 @@ static inline void arch_bprm_mm_init(str { } -static inline bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write) +static inline bool arch_vma_access_permitted (struct vm_area_struct *vma, +bool write,bool foreign) {/* by default, allow everything */ return true;
arch/unicore32/include/asm/mmu_context.h renamed from arch/unicore32/include/asm/mmu_context.h~pkeys-14-gup-fault-foreign-flag +2 -1
@@ -97,7 +97,8 @@ static inline void arch_bprm_mm_init(str { } -static inline bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write) +static inline bool arch_vma_access_permitted (struct vm_area_struct *vma, +bool write,bool foreign) {/* by default, allow everything */ return true;
arch/x86/include/asm/mmu_context.h renamed from arch/x86/include/asm/mmu_context.h~pkeys-14-gup-fault-foreign-flag +3 -2
@@ -322,10 +322,11 @@ static inline bool vma_is_foreign(structreturn false; } -static inline bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write) +static inline bool arch_vma_access_permitted (struct vm_area_struct *vma, +bool write,bool foreign) {/* allow access if the VMA is not one from this process */ -if (vma_is_foreign (vma)) +if (foreign ||vma_is_foreign (vma))return true;return __pkru_allows_pkey (vma_pkey (vma), write); }
drivers/iommu/amd_iommu_v2.c renamed from drivers/iommu/amd_iommu_v2.c~pkeys-14-gup-fault-foreign-flag +1 -0
@@ -526,6 +526,7 @@ static void do_fault(struct work_struct flags |=FAULT_FLAG_USER ;if (fault->flags &PPR_FAULT_WRITE ) flags |=FAULT_FLAG_WRITE ; + flags |=FAULT_FLAG_REMOTE ;down_read (&mm->mmap_sem); vma =find_extend_vma (mm, address);
include/asm-generic/mm_hooks.h renamed from include/asm-generic/mm_hooks.h~pkeys-14-gup-fault-foreign-flag +2 -1
@@ -26,7 +26,8 @@ static inline void arch_bprm_mm_init(str { } -static inline bool arch_vma_access_permitted (struct vm_area_struct *vma,bool write) +static inline bool arch_vma_access_permitted (struct vm_area_struct *vma, +bool write,bool foreign) {/* by default, allow everything */ return true;
include/linux/mm.h renamed from include/linux/mm.h~pkeys-14-gup-fault-foreign-flag +1 -0
@@ -251,6 +251,7 @@ extern pgprot_t protection_map[16];#define FAULT_FLAG_KILLABLE 0x10/* The fault task is in SIGKILL killable region */ #define FAULT_FLAG_TRIED 0x20/* Second try */ #define FAULT_FLAG_USER 0x40/* The fault originated in userspace */ +#define FAULT_FLAG_REMOTE 0x80/* faulting for non current tsk/mm */ /* * vm_fault is filled by the the pagefault handler and passed to the vma's
mm/gup.c renamed from mm/gup.c~pkeys-14-gup-fault-foreign-flag +10 -5
@@ -365,6 +365,8 @@ static int faultin_page(struct task_strureturn -ENOENT ;if (*flags &FOLL_WRITE ) fault_flags |=FAULT_FLAG_WRITE ; +if (*flags &FOLL_REMOTE ) + fault_flags |=FAULT_FLAG_REMOTE ;if (nonblocking) fault_flags |=FAULT_FLAG_ALLOW_RETRY ;if (*flags &FOLL_NOWAIT )
@@ -415,11 +417,13 @@ static int faultin_page(struct task_strustatic int check_vma_flags (struct vm_area_struct *vma,unsigned long gup_flags) {vm_flags_t vm_flags = vma->vm_flags; +int write = (gup_flags &FOLL_WRITE ); +int foreign = (gup_flags &FOLL_REMOTE );if (vm_flags & (VM_IO |VM_PFNMAP ))return -EFAULT ; -if (gup_flags &FOLL_WRITE ) { +if (write) {if (!(vm_flags &VM_WRITE )) {if (!(gup_flags &FOLL_FORCE ))return -EFAULT ;
@@ -445,7 +449,7 @@ static int check_vma_flags(struct vm_areif (!(vm_flags &VM_MAYREAD ))return -EFAULT ; } -if (!arch_vma_access_permitted (vma, (gup_flags &FOLL_WRITE ))) +if (!arch_vma_access_permitted (vma, write, foreign))return -EFAULT ;return 0 ; }
@@ -615,7 +619,8 @@ EXPORT_SYMBOL(__get_user_pages);bool vma_permits_fault (struct vm_area_struct *vma,unsigned int fault_flags) { -bool write = !!(fault_flags &FAULT_FLAG_WRITE ); +bool write = !!(fault_flags &FAULT_FLAG_WRITE ); +bool foreign = !!(fault_flags &FAULT_FLAG_REMOTE );vm_flags_t vm_flags = write ?VM_WRITE :VM_READ ;if (!(vm_flags & vma->vm_flags))
@@ -623,9 +628,9 @@ bool vma_permits_fault(struct vm_area_st/* * The architecture might have a hardware protection -* mechanism other than read/write that can deny access +* mechanism other than read/write that can deny access. */ -if (!arch_vma_access_permitted (vma, write)) +if (!arch_vma_access_permitted (vma, write, foreign))return false;return true;
mm/ksm.c renamed from mm/ksm.c~pkeys-14-gup-fault-foreign-flag +8 -2
@@ -359,6 +359,10 @@ static inline bool ksm_test_exit(struct* in case the application has unmapped and remapped mm,addr meanwhile. * Could a ksm page appear anywhere else? Actually yes, in a VM_PFNMAP * mmap of /dev/mem or /dev/kmem, where we would not want to touch it. +* +* FAULT_FLAG/FOLL_REMOTE are because we do this outside the context +* of the process that owns 'vma'. We also do not want to enforce +* protection keys here anyway. */ static int break_ksm (struct vm_area_struct *vma,unsigned long addr) {
@@ -367,12 +371,14 @@ static int break_ksm(struct vm_area_stru do { cond_resched(); - page = follow_page(vma, addr, FOLL_GET | FOLL_MIGRATION); + page = follow_page(vma, addr, + FOLL_GET | FOLL_MIGRATION | FOLL_REMOTE); if (IS_ERR_OR_NULL(page)) break; if (PageKsm(page)) ret = handle_mm_fault(vma->vm_mm, vma, addr, - FAULT_FLAG_WRITE); + FAULT_FLAG_WRITE | + FAULT_FLAG_REMOTE); else ret = VM_FAULT_WRITE; put_page(page);
mm/memory.c renamed from mm/memory.c~pkeys-14-gup-fault-foreign-flag +2 -1
@@ -3358,7 +3358,8 @@ static int __handle_mm_fault(struct mm_spmd_t *pmd;pte_t *pte; -if (!arch_vma_access_permitted (vma, flags &FAULT_FLAG_WRITE )) +if (!arch_vma_access_permitted (vma, flags &FAULT_FLAG_WRITE , + flags &FAULT_FLAG_REMOTE ))return VM_FAULT_SIGSEGV ;if (unlikely (is_vm_hugetlb_page (vma)))
_
PATCH 21/33 x86, pkeys: optimize fault handling in access_error()
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
We might not strictly have to make modifictions to access_error() to check the VMA here.
If we do not, we will do this:
1. app sets VMA pkey to K
2. app touches a !present page
3. do_page_fault(), allocates and maps page, sets pte.pkey=K
4. return to userspace
5. touch instruction reexecutes, but triggers PF_PK
6. do PKEY signal
What happens with this patch applied:
1. app sets VMA pkey to K
2. app touches a !present page
3. do_page_fault() notices that K is inaccessible
4. do PKEY signal
We basically skip the fault that does an allocation.
So what this lets us do is protect areas from even being *populated* unless it is accessible according to protection keys. That seems handy to me and makes protection keys work more like an mprotect()'d mapping.
---
b/arch/x86/mm/fault.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
arch/x86/mm/fault.c renamed from arch/x86/mm/fault.c~pkeys-15-access_error +15 -0
@@ -900,10 +900,16 @@ bad_area(struct pt_regs *regs, unsignedstatic inline bool bad_area_access_from_pkeys (unsigned long error_code,struct vm_area_struct *vma) { +/* This code is always called on the current mm */ +bool foreign = false; +if (!boot_cpu_has (X86_FEATURE_OSPKE ))return false;if (error_code &PF_PK )return true; +/* this checks permission keys on the VMA: */ +if (!arch_vma_access_permitted (vma, (error_code &PF_WRITE ), foreign)) +return true;return false; }
@@ -1091,6 +1097,8 @@ int show_unhandled_signals = 1;static inline int access_error (unsigned long error_code,struct vm_area_struct *vma) { +/* This is only called for the current mm, so: */ +bool foreign = false;/* * Access or read was blocked by protection keys. We do * this check before any others because we do not want
@@ -1099,6 +1107,13 @@ access_error(unsigned long error_code, s*/ if (error_code &PF_PK )return 1 ; +/* +* Make sure to check the VMA so that we do not perform +* faults just to hit a PF_PK as soon as we fill in a +* page. +*/ +if (!arch_vma_access_permitted (vma, (error_code &PF_WRITE ), foreign)) +return 1 ;if (error_code &PF_WRITE ) {/* write, present and write, not present: */
_
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/mm/pkeys: Optimize fault handling in access_error()
x86/mm/pkeys: Optimize fault handling in access_error()
Commit-ID: 07f146f53e8de826e4afa3a88ea65bdb13c24959 Gitweb: http://git.kernel.org/tip/07f146f53e8de826e4afa3a88ea65bdb13c24959 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:22 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 19:46:28 +0100
x86/mm/pkeys: Optimize fault handling in access_error()
We might not strictly have to make modifictions to access_error() to check the VMA here.
If we do not, we will do this:
1. app sets VMA pkey to K
2. app touches a !present page
3. do_page_fault(), allocates and maps page, sets pte.pkey=K
4. return to userspace
5. touch instruction reexecutes, but triggers PF_PK
6. do PKEY signal
What happens with this patch applied:
1. app sets VMA pkey to K
2. app touches a !present page
3. do_page_fault() notices that K is inaccessible
4. do PKEY signal
We basically skip the fault that does an allocation.
So what this lets us do is protect areas from even being *populated* unless it is accessible according to protection keys. That seems handy to me and makes protection keys work more like an mprotect()'d mapping.
--- arch/x86/mm/fault.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
arch/x86/mm/fault.c +15 -0
@@ -900,10 +900,16 @@ bad_area(struct pt_regs *regs, unsigned long error_code, unsigned long address)static inline bool bad_area_access_from_pkeys (unsigned long error_code,struct vm_area_struct *vma) { +/* This code is always called on the current mm */ +bool foreign = false; +if (!boot_cpu_has (X86_FEATURE_OSPKE ))return false;if (error_code &PF_PK )return true; +/* this checks permission keys on the VMA: */ +if (!arch_vma_access_permitted (vma, (error_code &PF_WRITE ), foreign)) +return true;return false; }
@@ -1091,6 +1097,8 @@ int show_unhandled_signals = 1;static inline int access_error (unsigned long error_code,struct vm_area_struct *vma) { +/* This is only called for the current mm, so: */ +bool foreign = false;/* * Access or read was blocked by protection keys. We do * this check before any others because we do not want
@@ -1099,6 +1107,13 @@ access_error(unsigned long error_code, struct vm_area_struct *vma)*/ if (error_code &PF_PK )return 1 ; +/* +* Make sure to check the VMA so that we do not perform +* faults just to hit a PF_PK as soon as we fill in a +* page. +*/ +if (!arch_vma_access_permitted (vma, (error_code &PF_WRITE ), foreign)) +return 1 ;if (error_code &PF_WRITE ) {/* write, present and write, not present: */
PATCH 22/33 x86, pkeys: differentiate instruction fetches
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
As discussed earlier, we attempt to enforce protection keys in software.
However, the code checks all faults to ensure that they are not violating protection key permissions. It was assumed that all faults are either write faults where we check PKRU[key].WD (write disable) or read faults where we check the AD (access disable) bit.
But, there is a third category of faults for protection keys:
instruction faults. Instruction faults never run afoul of protection keys because they do not affect instruction fetches.
So, plumb the PF_INSTR bit down in to the arch_vma_access_permitted() function where we do the protection key checks.
We also add a new FAULT_FLAG_INSTRUCTION. This is because handle_mm_fault() is not passed the architecture-specific error_code where we keep PF_INSTR, so we need to encode the instruction fetch information in to the arch-generic fault flags.
---
b/arch/powerpc/include/asm/mmu_context.h | 2 +- b/arch/s390/include/asm/mmu_context.h | 2 +- b/arch/x86/include/asm/mmu_context.h | 5 ++++- b/arch/x86/mm/fault.c | 8 ++++++-- b/include/asm-generic/mm_hooks.h | 2 +- b/include/linux/mm.h | 1 + b/mm/gup.c | 11 +++++++++-- b/mm/memory.c | 1 + 8 files changed, 24 insertions(+), 8 deletions(-)
arch/powerpc/include/asm/mmu_context.h renamed from arch/powerpc/include/asm/mmu_context.h~pkeys-16-allow-execute-on-unreadable +1 -1
@@ -149,7 +149,7 @@ static inline void arch_bprm_mm_init(str }static inline bool arch_vma_access_permitted (struct vm_area_struct *vma, -bool write,bool foreign) +bool write,bool execute,bool foreign) {/* by default, allow everything */ return true;
arch/s390/include/asm/mmu_context.h renamed from arch/s390/include/asm/mmu_context.h~pkeys-16-allow-execute-on-unreadable +1 -1
@@ -131,7 +131,7 @@ static inline void arch_bprm_mm_init(str }static inline bool arch_vma_access_permitted (struct vm_area_struct *vma, -bool write,bool foreign) +bool write,bool execute,bool foreign) {/* by default, allow everything */ return true;
arch/x86/include/asm/mmu_context.h renamed from arch/x86/include/asm/mmu_context.h~pkeys-16-allow-execute-on-unreadable +4 -1
@@ -323,8 +323,11 @@ static inline bool vma_is_foreign(struct }static inline bool arch_vma_access_permitted (struct vm_area_struct *vma, -bool write,bool foreign) +bool write,bool execute,bool foreign) { +/* pkeys never affect instruction fetches */ +if (execute) +return true;/* allow access if the VMA is not one from this process */ if (foreign ||vma_is_foreign (vma))return true;
arch/x86/mm/fault.c renamed from arch/x86/mm/fault.c~pkeys-16-allow-execute-on-unreadable +6 -2
@@ -908,7 +908,8 @@ static inline bool bad_area_access_from_if (error_code &PF_PK )return true;/* this checks permission keys on the VMA: */ -if (!arch_vma_access_permitted (vma, (error_code &PF_WRITE ), foreign)) +if (!arch_vma_access_permitted (vma, (error_code &PF_WRITE ), + (error_code &PF_INSTR ), foreign))return true;return false; }
@@ -1112,7 +1113,8 @@ access_error(unsigned long error_code, s* faults just to hit a PF_PK as soon as we fill in a * page. */ -if (!arch_vma_access_permitted (vma, (error_code &PF_WRITE ), foreign)) +if (!arch_vma_access_permitted (vma, (error_code &PF_WRITE ), + (error_code &PF_INSTR ), foreign))return 1 ;if (error_code &PF_WRITE ) {
@@ -1267,6 +1269,8 @@ __do_page_fault(struct pt_regs *regs, unif (error_code &PF_WRITE ) flags |=FAULT_FLAG_WRITE ; +if (error_code &PF_INSTR ) + flags |=FAULT_FLAG_INSTRUCTION ;/* * When running in the kernel we expect faults to occur only to
include/asm-generic/mm_hooks.h renamed from include/asm-generic/mm_hooks.h~pkeys-16-allow-execute-on-unreadable +1 -1
@@ -27,7 +27,7 @@ static inline void arch_bprm_mm_init(str }static inline bool arch_vma_access_permitted (struct vm_area_struct *vma, -bool write,bool foreign) +bool write,bool execute,bool foreign) {/* by default, allow everything */ return true;
include/linux/mm.h renamed from include/linux/mm.h~pkeys-16-allow-execute-on-unreadable +1 -0
@@ -252,6 +252,7 @@ extern pgprot_t protection_map[16];#define FAULT_FLAG_TRIED 0x20/* Second try */ #define FAULT_FLAG_USER 0x40/* The fault originated in userspace */ #define FAULT_FLAG_REMOTE 0x80/* faulting for non current tsk/mm */ +#define FAULT_FLAG_INSTRUCTION 0x100/* The fault was during an instruction fetch */ /* * vm_fault is filled by the the pagefault handler and passed to the vma's
mm/gup.c renamed from mm/gup.c~pkeys-16-allow-execute-on-unreadable +9 -2
@@ -449,7 +449,11 @@ static int check_vma_flags(struct vm_areif (!(vm_flags &VM_MAYREAD ))return -EFAULT ; } -if (!arch_vma_access_permitted (vma, write, foreign)) +/* +* gups are always data accesses, not instruction +* fetches, so execute=false here +*/ +if (!arch_vma_access_permitted (vma, write, false, foreign))return -EFAULT ;return 0 ; }
@@ -629,8 +633,11 @@ bool vma_permits_fault(struct vm_area_st/* * The architecture might have a hardware protection * mechanism other than read/write that can deny access. +* +* gup always represents data access, not instruction +* fetches, so execute=false here: */ -if (!arch_vma_access_permitted (vma, write, foreign)) +if (!arch_vma_access_permitted (vma, write, false, foreign))return false;return true;
mm/memory.c renamed from mm/memory.c~pkeys-16-allow-execute-on-unreadable +1 -0
@@ -3359,6 +3359,7 @@ static int __handle_mm_fault(struct mm_spte_t *pte;if (!arch_vma_access_permitted (vma, flags &FAULT_FLAG_WRITE , + flags &FAULT_FLAG_INSTRUCTION , flags &FAULT_FLAG_REMOTE ))return VM_FAULT_SIGSEGV ;
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] mm/core, x86/mm/pkeys: Differentiate instruction fetches
mm/core, x86/mm/pkeys: Differentiate instruction fetches
Commit-ID: d61172b4b695b821388cdb6088a41d431bcbb93b Gitweb: http://git.kernel.org/tip/d61172b4b695b821388cdb6088a41d431bcbb93b Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:24 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 19:46:29 +0100
mm/core, x86/mm/pkeys: Differentiate instruction fetches
As discussed earlier, we attempt to enforce protection keys in software.
However, the code checks all faults to ensure that they are not violating protection key permissions. It was assumed that all faults are either write faults where we check PKRU[key].WD (write disable) or read faults where we check the AD (access disable) bit.
But, there is a third category of faults for protection keys:
instruction faults. Instruction faults never run afoul of protection keys because they do not affect instruction fetches.
So, plumb the PF_INSTR bit down in to the arch_vma_access_permitted() function where we do the protection key checks.
We also add a new FAULT_FLAG_INSTRUCTION. This is because handle_mm_fault() is not passed the architecture-specific error_code where we keep PF_INSTR, so we need to encode the instruction fetch information in to the arch-generic fault flags.
--- arch/powerpc/include/asm/mmu_context.h | 2 +- arch/s390/include/asm/mmu_context.h | 2 +- arch/x86/include/asm/mmu_context.h | 5 ++++- arch/x86/mm/fault.c | 8 ++++++-- include/asm-generic/mm_hooks.h | 2 +- include/linux/mm.h | 1 + mm/gup.c | 11 +++++++++-- mm/memory.c | 1 + 8 files changed, 24 insertions(+), 8 deletions(-)
arch/powerpc/include/asm/mmu_context.h +1 -1
@@ -149,7 +149,7 @@ static inline void arch_bprm_mm_init(struct mm_struct *mm, }static inline bool arch_vma_access_permitted (struct vm_area_struct *vma, -bool write,bool foreign) +bool write,bool execute,bool foreign) {/* by default, allow everything */ return true;
arch/s390/include/asm/mmu_context.h +1 -1
@@ -131,7 +131,7 @@ static inline void arch_bprm_mm_init(struct mm_struct *mm, }static inline bool arch_vma_access_permitted (struct vm_area_struct *vma, -bool write,bool foreign) +bool write,bool execute,bool foreign) {/* by default, allow everything */ return true;
arch/x86/include/asm/mmu_context.h +4 -1
@@ -323,8 +323,11 @@ static inline bool vma_is_foreign(struct vm_area_struct *vma) }static inline bool arch_vma_access_permitted (struct vm_area_struct *vma, -bool write,bool foreign) +bool write,bool execute,bool foreign) { +/* pkeys never affect instruction fetches */ +if (execute) +return true;/* allow access if the VMA is not one from this process */ if (foreign ||vma_is_foreign (vma))return true;
arch/x86/mm/fault.c +6 -2
@@ -908,7 +908,8 @@ static inline bool bad_area_access_from_pkeys(unsigned long error_code,if (error_code &PF_PK )return true;/* this checks permission keys on the VMA: */ -if (!arch_vma_access_permitted (vma, (error_code &PF_WRITE ), foreign)) +if (!arch_vma_access_permitted (vma, (error_code &PF_WRITE ), + (error_code &PF_INSTR ), foreign))return true;return false; }
@@ -1112,7 +1113,8 @@ access_error(unsigned long error_code, struct vm_area_struct *vma)* faults just to hit a PF_PK as soon as we fill in a * page. */ -if (!arch_vma_access_permitted (vma, (error_code &PF_WRITE ), foreign)) +if (!arch_vma_access_permitted (vma, (error_code &PF_WRITE ), + (error_code &PF_INSTR ), foreign))return 1 ;if (error_code &PF_WRITE ) {
@@ -1267,6 +1269,8 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code,if (error_code &PF_WRITE ) flags |=FAULT_FLAG_WRITE ; +if (error_code &PF_INSTR ) + flags |=FAULT_FLAG_INSTRUCTION ;/* * When running in the kernel we expect faults to occur only to
include/asm-generic/mm_hooks.h +1 -1
@@ -27,7 +27,7 @@ static inline void arch_bprm_mm_init(struct mm_struct *mm, }static inline bool arch_vma_access_permitted (struct vm_area_struct *vma, -bool write,bool foreign) +bool write,bool execute,bool foreign) {/* by default, allow everything */ return true;
include/linux/mm.h +1 -0
@@ -252,6 +252,7 @@ extern pgprot_t protection_map[16];#define FAULT_FLAG_TRIED 0x20/* Second try */ #define FAULT_FLAG_USER 0x40/* The fault originated in userspace */ #define FAULT_FLAG_REMOTE 0x80/* faulting for non current tsk/mm */ +#define FAULT_FLAG_INSTRUCTION 0x100/* The fault was during an instruction fetch */ /* * vm_fault is filled by the the pagefault handler and passed to the vma's
mm/gup.c +9 -2
@@ -449,7 +449,11 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags)if (!(vm_flags &VM_MAYREAD ))return -EFAULT ; } -if (!arch_vma_access_permitted (vma, write, foreign)) +/* +* gups are always data accesses, not instruction +* fetches, so execute=false here +*/ +if (!arch_vma_access_permitted (vma, write, false, foreign))return -EFAULT ;return 0 ; }
@@ -629,8 +633,11 @@ bool vma_permits_fault(struct vm_area_struct *vma, unsigned int fault_flags)/* * The architecture might have a hardware protection * mechanism other than read/write that can deny access. +* +* gup always represents data access, not instruction +* fetches, so execute=false here: */ -if (!arch_vma_access_permitted (vma, write, foreign)) +if (!arch_vma_access_permitted (vma, write, false, foreign))return false;return true;
mm/memory.c +1 -0
@@ -3380,6 +3380,7 @@ static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,pte_t *pte;if (!arch_vma_access_permitted (vma, flags &FAULT_FLAG_WRITE , + flags &FAULT_FLAG_INSTRUCTION , flags &FAULT_FLAG_REMOTE ))return VM_FAULT_SIGSEGV ;
PATCH 23/33 x86, pkeys: dump PKRU with other kernel registers
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
Protection Keys never affect kernel mappings. But, they can affect whether the kernel will fault when it touches a user mapping. The kernel doesn't touch user mappings without some careful choreography and these accesses don't generally result in oopses. But, if one does, we definitely want to have PKRU available so we can figure out if protection keys played a role.
---
b/arch/x86/kernel/process_64.c | 2 ++ 1 file changed, 2 insertions(+)
arch/x86/kernel/process_64.c renamed from arch/x86/kernel/process_64.c~pkeys-30-kernel-error-dumps +2 -0
@@ -116,6 +116,8 @@ void __show_regs(struct pt_regs *regs, iprintk (KERN_DEFAULT "DR0: %016lx DR1: %016lx DR2: %016lx\n" , d0, d1, d2);printk (KERN_DEFAULT "DR3: %016lx DR6: %016lx DR7: %016lx\n" , d3, d6, d7); +if (boot_cpu_has (X86_FEATURE_OSPKE )) +printk (KERN_DEFAULT "PKRU: %08x\n" ,read_pkru ()); }void release_thread (struct task_struct *dead_task)
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/mm/pkeys: Dump PKRU with other kernel registers
x86/mm/pkeys: Dump PKRU with other kernel registers
Commit-ID: c0b17b5bd4b7b98e7c6b67c9f69343b64711271b Gitweb: http://git.kernel.org/tip/c0b17b5bd4b7b98e7c6b67c9f69343b64711271b Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:25 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 19:46:29 +0100
x86/mm/pkeys: Dump PKRU with other kernel registers
Protection Keys never affect kernel mappings. But, they can affect whether the kernel will fault when it touches a user mapping. The kernel doesn't touch user mappings without some careful choreography and these accesses don't generally result in oopses. But, if one does, we definitely want to have PKRU available so we can figure out if protection keys played a role.
--- arch/x86/kernel/process_64.c | 2 ++ 1 file changed, 2 insertions(+)
arch/x86/kernel/process_64.c +2 -0
@@ -116,6 +116,8 @@ void __show_regs(struct pt_regs *regs, int all)printk (KERN_DEFAULT "DR0: %016lx DR1: %016lx DR2: %016lx\n" , d0, d1, d2);printk (KERN_DEFAULT "DR3: %016lx DR6: %016lx DR7: %016lx\n" , d3, d6, d7); +if (boot_cpu_has (X86_FEATURE_OSPKE )) +printk (KERN_DEFAULT "PKRU: %08x\n" ,read_pkru ()); }void release_thread (struct task_struct *dead_task)
PATCH 24/33 x86, pkeys: dump pkey from VMA in /proc/pid/smaps
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
The protection key can now be just as important as read/write permissions on a VMA. We need some debug mechanism to help figure out if it is in play. smaps seems like a logical place to expose it.
arch/x86/kernel/setup.c is a bit of a weirdo place to put this code, but it already had seq_file.h and there was not a much better existing place to put it.
We also use no #ifdef. If protection keys is .config'd out we will effectively get the same function as if we used the weak generic function.
---
b/arch/x86/kernel/setup.c | 9 +++++++++ b/fs/proc/task_mmu.c | 14 ++++++++++++++ 2 files changed, 23 insertions(+)
arch/x86/kernel/setup.c renamed from arch/x86/kernel/setup.c~pkeys-40-smaps +9 -0
@@ -112,6 +112,7 @@#include <asm/alternative.h> #include <asm/prom.h> #include <asm/microcode.h> +#include <asm/mmu_context.h> /* * max_low_pfn_mapped: highest direct mapped pfn under 4GB
@@ -1282,3 +1283,11 @@ static int __init register_kernel_offsetreturn 0 ; }__initcall (register_kernel_offset_dumper); + +void arch_show_smap (struct seq_file *m,struct vm_area_struct *vma) +{ +if (!boot_cpu_has (X86_FEATURE_OSPKE )) +return ; + +seq_printf (m,"ProtectionKey: %8u\n" ,vma_pkey (vma)); +}
fs/proc/task_mmu.c renamed from fs/proc/task_mmu.c~pkeys-40-smaps +14 -0
@@ -660,11 +660,20 @@ static void show_smap_vma_flags(struct s [ilog2(VM_MERGEABLE)] = "mg", [ilog2(VM_UFFD_MISSING)]= "um", [ilog2 (VM_UFFD_WP )] ="uw" , +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +/* These come out via ProtectionKey: */ + [ilog2(VM_PKEY_BIT0)] = "", + [ilog2(VM_PKEY_BIT1)] = "", + [ilog2(VM_PKEY_BIT2)] = "", + [ilog2(VM_PKEY_BIT3)] = "", +#endif };size_t i;seq_puts (m,"VmFlags: " );for (i =0 ; i <BITS_PER_LONG ; i++) { +if (!mnemonics[i][0 ]) +continue ;if (vma->vm_flags & (1UL << i)) {seq_printf (m,"%c%c " , mnemonics[i][0 ], mnemonics[i][1 ]);
@@ -702,6 +711,10 @@ static int smaps_hugetlb_range(pte_t *pt }#endif /* HUGETLB_PAGE */ +void __weak arch_show_smap (struct seq_file *m,struct vm_area_struct *vma) +{ +} +static int show_smap (struct seq_file *m,void *v,int is_pid) {struct vm_area_struct *vma = v;
@@ -783,6 +796,7 @@ static int show_smap(struct seq_file *m, (vma->vm_flags &VM_LOCKED ) ? (unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0); +arch_show_smap (m, vma);show_smap_vma_flags (m, vma);m_cache_vma (m, vma);return 0 ;
_
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/mm/pkeys: Dump pkey from VMA in /proc/pid/ smaps
x86/mm/pkeys: Dump pkey from VMA in /proc/pid/smaps
Commit-ID: c1192f8428414679c8126180e690f8daa1d4d98a Gitweb: http://git.kernel.org/tip/c1192f8428414679c8126180e690f8daa1d4d98a Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:27 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 19:46:29 +0100
x86/mm/pkeys: Dump pkey from VMA in /proc/pid/smaps
The protection key can now be just as important as read/write permissions on a VMA. We need some debug mechanism to help figure out if it is in play. smaps seems like a logical place to expose it.
arch/x86/kernel/setup.c is a bit of a weirdo place to put this code, but it already had seq_file.h and there was not a much better existing place to put it.
We also use no #ifdef. If protection keys is .config'd out we will effectively get the same function as if we used the weak generic function.
--- arch/x86/kernel/setup.c | 9 +++++++++ fs/proc/task_mmu.c | 14 ++++++++++++++ 2 files changed, 23 insertions(+)
arch/x86/kernel/setup.c +9 -0
@@ -112,6 +112,7 @@#include <asm/alternative.h> #include <asm/prom.h> #include <asm/microcode.h> +#include <asm/mmu_context.h> /* * max_low_pfn_mapped: highest direct mapped pfn under 4GB
@@ -1282,3 +1283,11 @@ static int __init register_kernel_offset_dumper(void)return 0 ; }__initcall (register_kernel_offset_dumper); + +void arch_show_smap (struct seq_file *m,struct vm_area_struct *vma) +{ +if (!boot_cpu_has (X86_FEATURE_OSPKE )) +return ; + +seq_printf (m,"ProtectionKey: %8u\n" ,vma_pkey (vma)); +}
fs/proc/task_mmu.c +14 -0
@@ -660,11 +660,20 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma) [ilog2(VM_MERGEABLE)] = "mg", [ilog2(VM_UFFD_MISSING)]= "um", [ilog2 (VM_UFFD_WP )] ="uw" , +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +/* These come out via ProtectionKey: */ + [ilog2(VM_PKEY_BIT0)] = "", + [ilog2(VM_PKEY_BIT1)] = "", + [ilog2(VM_PKEY_BIT2)] = "", + [ilog2(VM_PKEY_BIT3)] = "", +#endif };size_t i;seq_puts (m,"VmFlags: " );for (i =0 ; i <BITS_PER_LONG ; i++) { +if (!mnemonics[i][0 ]) +continue ;if (vma->vm_flags & (1UL << i)) {seq_printf (m,"%c%c " , mnemonics[i][0 ], mnemonics[i][1 ]);
@@ -702,6 +711,10 @@ static int smaps_hugetlb_range(pte_t *pte, unsigned long hmask, }#endif /* HUGETLB_PAGE */ +void __weak arch_show_smap (struct seq_file *m,struct vm_area_struct *vma) +{ +} +static int show_smap (struct seq_file *m,void *v,int is_pid) {struct vm_area_struct *vma = v;
@@ -783,6 +796,7 @@ static int show_smap(struct seq_file *m, void *v, int is_pid) (vma->vm_flags &VM_LOCKED ) ? (unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0); +arch_show_smap (m, vma);show_smap_vma_flags (m, vma);m_cache_vma (m, vma);return 0 ;
PATCH 25/33 x86, pkeys: add Kconfig prompt to existing config option
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
I don't have a strong opinion on whether we need this or not. Protection Keys has relatively little code associated with it, and it is not a heavyweight feature to keep enabled. However, I can imagine that folks would still appreciate being able to disable it.
Here's the option if folks want it.
---
b/arch/x86/Kconfig | 10 ++++++++++ 1 file changed, 10 insertions(+)
arch/x86/Kconfig renamed from arch/x86/Kconfig~pkeys-40-kconfig-prompt +10 -0
@@ -1715,8 +1715,18 @@ config X86_INTEL_MPX If unsure, say N. config X86_INTEL_MEMORY_PROTECTION_KEYS + prompt "Intel Memory Protection Keys" def_bool y + # Note: only available in 64-bit mode depends on CPU_SUP_INTEL && X86_64 + ---help--- + Memory Protection Keys provides a mechanism for enforcing + page-based protections, but without requiring modification of the + page tables when an application changes protection domains. + + For details, see Documentation/x86/protection-keys.txt + + If unsure, say y. config EFI bool "EFI runtime service support"
_
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/mm/pkeys: Add Kconfig prompt to existing config option
x86/mm/pkeys: Add Kconfig prompt to existing config option
Commit-ID: 284244a9876225eb73102aff41d4492f65cb2868 Gitweb: http://git.kernel.org/tip/284244a9876225eb73102aff41d4492f65cb2868 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:28 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 19:46:30 +0100
x86/mm/pkeys: Add Kconfig prompt to existing config option
I don't have a strong opinion on whether we need this or not. Protection Keys has relatively little code associated with it, and it is not a heavyweight feature to keep enabled. However, I can imagine that folks would still appreciate being able to disable it.
Here's the option if folks want it.
--- arch/x86/Kconfig | 10 ++++++++++ 1 file changed, 10 insertions(+)
arch/x86/Kconfig +10 -0
@@ -1716,8 +1716,18 @@ config X86_INTEL_MPX If unsure, say N. config X86_INTEL_MEMORY_PROTECTION_KEYS + prompt "Intel Memory Protection Keys" def_bool y + # Note: only available in 64-bit mode depends on CPU_SUP_INTEL && X86_64 + ---help--- + Memory Protection Keys provides a mechanism for enforcing + page-based protections, but without requiring modification of the + page tables when an application changes protection domains. + + For details, see Documentation/x86/protection-keys.txt + + If unsure, say y. config EFI bool "EFI runtime service support"
PATCH 26/33 x86, pkeys: actually enable Memory Protection Keys in CPU
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
This sets the bit in 'cr4' to actually enable the protection keys feature. We also include a boot-time disable for the feature "nopku".
Seting X86_CR4_PKE will cause the X86_FEATURE_OSPKE cpuid bit to appear set. At this point in boot, identify_cpu() has already run the actual CPUID instructions and populated the "cpu features" structures. We need to go back and re-run identify_cpu() to make sure it gets updated values.
We *could* simply re-populate the 11th word of the cpuid data, but this is probably quick enough.
Also note that with the cpu_has() check and X86_FEATURE_PKU present in disabled-features.h, we do not need an #ifdef for setup_pku().
---
b/Documentation/kernel-parameters.txt | 3 ++ b/arch/x86/kernel/cpu/common.c | 41 ++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+)
arch/x86/kernel/cpu/common.c renamed from arch/x86/kernel/cpu/common.c~pkeys-50-should-be-last-patch +41 -0
@@ -288,6 +288,46 @@ static __always_inline void setup_smap(s }/* +* Protection Keys are not available in 32-bit mode. +*/ +static bool pku_disabled; +static __always_inline void setup_pku(struct cpuinfo_x86 *c) +{ +if (!cpu_has (c,X86_FEATURE_PKU )) +return ; +if (pku_disabled) +return ; + +cr4_set_bits (X86_CR4_PKE ); +/* +* Seting X86_CR4_PKE will cause the X86_FEATURE_OSPKE +* cpuid bit to be set. We need to ensure that we +* update that bit in this CPU's "cpu_info". +*/ +get_cpu_cap (c); +} +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +static __init int setup_disable_pku (char *arg) +{ +/* +* Do not clear the X86_FEATURE_PKU bit. All of the +* runtime checks are against OSPKE so clearing the +* bit does nothing. +* +* This way, we will see "pku" in cpuinfo, but not +* "ospke", which is exactly what we want. It shows +* that the CPU has PKU, but the OS has not enabled it. +* This happens to be exactly how a system would look +* if we disabled the config option. +*/ +pr_info ("x86: 'nopku' specified, disabling Memory Protection Keys\n" ); + pku_disabled = true; +return 1 ; +} +__setup ("nopku" , setup_disable_pku); +#endif /* CONFIG_X86_64 */ + +/* * Some CPU features depend on higher CPUID levels, which may not always * be available due to CPUID level capping or broken virtualization * software. Add those features to this table to auto-disable them.
@@ -944,6 +984,7 @@ static void identify_cpu(struct cpuinfo_init_hypervisor (c);x86_init_rdrand (c);x86_init_cache_qos (c); +setup_pku (c);/* * Clear/Set all flags overriden by options, need do it
Documentation/kernel-parameters.txt renamed from Documentation/kernel-parameters.txt~pkeys-50-should-be-last-patch +3 -0
@@ -976,6 +976,9 @@ bytes respectively. Such letter suffixes See Documentation/x86/intel_mpx.txt for more information about the feature. + nopku [X86] Disable Memory Protection Keys CPU feature found + in some Intel CPUs. + eagerfpu= [X86] on enable eager fpu restore off disable eager fpu restore
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/mm/pkeys: Actually enable Memory Protection Keys in the CPU
x86/mm/pkeys: Actually enable Memory Protection Keys in the CPU
Commit-ID: 0697694564c84f4c9320e5d103d0191297a20023 Gitweb: http://git.kernel.org/tip/0697694564c84f4c9320e5d103d0191297a20023 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:29 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 19:46:30 +0100
x86/mm/pkeys: Actually enable Memory Protection Keys in the CPU
This sets the bit in 'cr4' to actually enable the protection keys feature. We also include a boot-time disable for the feature "nopku".
Seting X86_CR4_PKE will cause the X86_FEATURE_OSPKE cpuid bit to appear set. At this point in boot, identify_cpu() has already run the actual CPUID instructions and populated the "cpu features" structures. We need to go back and re-run identify_cpu() to make sure it gets updated values.
We *could* simply re-populate the 11th word of the cpuid data, but this is probably quick enough.
Also note that with the cpu_has() check and X86_FEATURE_PKU present in disabled-features.h, we do not need an #ifdef for setup_pku().
--- Documentation/kernel-parameters.txt | 3 +++ arch/x86/kernel/cpu/common.c | 43 +++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+)
Documentation/kernel-parameters.txt +3 -0
@@ -976,6 +976,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. See Documentation/x86/intel_mpx.txt for more information about the feature. + nopku [X86] Disable Memory Protection Keys CPU feature found + in some Intel CPUs. + eagerfpu= [X86] on enable eager fpu restore off disable eager fpu restore
arch/x86/kernel/cpu/common.c +43 -0
55 lines not on this page · raw message
PATCH 27/33 mm, multi-arch: pass a protection key in to calc_vm_flag_bits()
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
This plumbs a protection key through calc_vm_flag_bits(). We could have done this in calc_vm_prot_bits(), but I did not feel super strongly which way to go. It was pretty arbitrary which one to use.
---
b/arch/powerpc/include/asm/mman.h | 5 +++-- b/drivers/char/agp/frontend.c | 2 +- b/drivers/staging/android/ashmem.c | 4 ++-- b/include/linux/mman.h | 6 +++--- b/mm/mmap.c | 2 +- b/mm/mprotect.c | 2 +- b/mm/nommu.c | 2 +- 7 files changed, 12 insertions(+), 11 deletions(-)
arch/powerpc/include/asm/mman.h renamed from arch/powerpc/include/asm/mman.h~pkeys-70-calc_vm_prot_bits +3 -2
@@ -18,11 +18,12 @@* This file is included by linux/mman.h, so we can't use cacl_vm_prot_bits() * here. How important is the optimization? */ -static inline unsigned long arch_calc_vm_prot_bits (unsigned long prot) +static inline unsigned long arch_calc_vm_prot_bits (unsigned long prot, +unsigned long pkey) {return (prot &PROT_SAO ) ?VM_SAO :0 ; } -#define arch_calc_vm_prot_bits (prot) arch_calc_vm_prot_bits(prot) +#define arch_calc_vm_prot_bits (prot, pkey) arch_calc_vm_prot_bits(prot, pkey)static inline pgprot_t arch_vm_get_page_prot (unsigned long vm_flags) {
drivers/char/agp/frontend.c renamed from drivers/char/agp/frontend.c~pkeys-70-calc_vm_prot_bits +1 -1
@@ -156,7 +156,7 @@ static pgprot_t agp_convert_mmap_flags(i {unsigned long prot_bits; - prot_bits =calc_vm_prot_bits (prot) |VM_SHARED ; + prot_bits =calc_vm_prot_bits (prot,0 ) |VM_SHARED ;return vm_get_page_prot (prot_bits); }
drivers/staging/android/ashmem.c renamed from drivers/staging/android/ashmem.c~pkeys-70-calc_vm_prot_bits +2 -2
@@ -372,8 +372,8 @@ static int ashmem_mmap(struct file *file }/* requested protection bits must match our allowed protection mask */ -if (unlikely ((vma->vm_flags & ~calc_vm_prot_bits (asma->prot_mask)) & -calc_vm_prot_bits (PROT_MASK ))) { +if (unlikely ((vma->vm_flags & ~calc_vm_prot_bits (asma->prot_mask,0 )) & +calc_vm_prot_bits (PROT_MASK ,0 ))) { ret = -EPERM ; goto out; }
include/linux/mman.h renamed from include/linux/mman.h~pkeys-70-calc_vm_prot_bits +3 -3
@@ -35,7 +35,7 @@ static inline void vm_unacct_memory(long*/ #ifndef arch_calc_vm_prot_bits -#define arch_calc_vm_prot_bits (prot) 0 +#define arch_calc_vm_prot_bits (prot, pkey) 0#endif #ifndef arch_vm_get_page_prot
@@ -70,12 +70,12 @@ static inline int arch_validate_prot(uns* Combine the mmap "prot" argument into "vm_flags" used internally. */ static inline unsigned long -calc_vm_prot_bits (unsigned long prot) +calc_vm_prot_bits (unsigned long prot,unsigned long pkey) {return _calc_vm_trans (prot,PROT_READ ,VM_READ ) |_calc_vm_trans (prot,PROT_WRITE ,VM_WRITE ) |_calc_vm_trans (prot,PROT_EXEC ,VM_EXEC ) | -arch_calc_vm_prot_bits (prot); +arch_calc_vm_prot_bits (prot, pkey); }/*
mm/mmap.c renamed from mm/mmap.c~pkeys-70-calc_vm_prot_bits +1 -1
@@ -1313,7 +1313,7 @@ unsigned long do_mmap(struct file *file,* to. we assume access permissions have been handled by the open * of the memory object, so we don't do any here. */ - vm_flags |=calc_vm_prot_bits (prot) |calc_vm_flag_bits (flags) | + vm_flags |=calc_vm_prot_bits (prot,0 ) |calc_vm_flag_bits (flags) | mm->def_flags |VM_MAYREAD |VM_MAYWRITE |VM_MAYEXEC ;if (flags &MAP_LOCKED )
mm/mprotect.c renamed from mm/mprotect.c~pkeys-70-calc_vm_prot_bits +1 -1
@@ -378,7 +378,7 @@ SYSCALL_DEFINE3(mprotect, unsigned long,if ((prot &PROT_READ ) && (current->personality &READ_IMPLIES_EXEC )) prot |=PROT_EXEC ; - vm_flags =calc_vm_prot_bits (prot); + vm_flags =calc_vm_prot_bits (prot,0 );down_write (¤t->mm->mmap_sem);
mm/nommu.c renamed from mm/nommu.c~pkeys-70-calc_vm_prot_bits +1 -1
@@ -1082,7 +1082,7 @@ static unsigned long determine_vm_flags( {unsigned long vm_flags; - vm_flags =calc_vm_prot_bits (prot) |calc_vm_flag_bits (flags); + vm_flags =calc_vm_prot_bits (prot,0 ) |calc_vm_flag_bits (flags);/* vm_flags |= mm->def_flags; */ if (!(capabilities &NOMMU_MAP_DIRECT )) {
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] mm/core, arch, powerpc: Pass a protection key in to calc_vm_flag_bits()
mm/core, arch, powerpc: Pass a protection key in to calc_vm_flag_bits()
Commit-ID: e6bfb70959a0ca6ddedb29e779a293c6f71ed0e7 Gitweb: http://git.kernel.org/tip/e6bfb70959a0ca6ddedb29e779a293c6f71ed0e7 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:31 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 19:46:30 +0100
mm/core, arch, powerpc: Pass a protection key in to calc_vm_flag_bits()
This plumbs a protection key through calc_vm_flag_bits(). We could have done this in calc_vm_prot_bits(), but I did not feel super strongly which way to go. It was pretty arbitrary which one to use.
--- arch/powerpc/include/asm/mman.h | 5 +++-- drivers/char/agp/frontend.c | 2 +- drivers/staging/android/ashmem.c | 4 ++-- include/linux/mman.h | 6 +++--- mm/mmap.c | 2 +- mm/mprotect.c | 2 +- mm/nommu.c | 2 +- 7 files changed, 12 insertions(+), 11 deletions(-)
arch/powerpc/include/asm/mman.h +3 -2
@@ -18,11 +18,12 @@* This file is included by linux/mman.h, so we can't use cacl_vm_prot_bits() * here. How important is the optimization? */ -static inline unsigned long arch_calc_vm_prot_bits (unsigned long prot) +static inline unsigned long arch_calc_vm_prot_bits (unsigned long prot, +unsigned long pkey) {return (prot &PROT_SAO ) ?VM_SAO :0 ; } -#define arch_calc_vm_prot_bits (prot) arch_calc_vm_prot_bits(prot) +#define arch_calc_vm_prot_bits (prot, pkey) arch_calc_vm_prot_bits(prot, pkey)static inline pgprot_t arch_vm_get_page_prot (unsigned long vm_flags) {
drivers/char/agp/frontend.c +1 -1
@@ -156,7 +156,7 @@ static pgprot_t agp_convert_mmap_flags(int prot) {unsigned long prot_bits; - prot_bits =calc_vm_prot_bits (prot) |VM_SHARED ; + prot_bits =calc_vm_prot_bits (prot,0 ) |VM_SHARED ;return vm_get_page_prot (prot_bits); }
drivers/staging/android/ashmem.c +2 -2
@@ -372,8 +372,8 @@ static int ashmem_mmap(struct file *file, struct vm_area_struct *vma) }/* requested protection bits must match our allowed protection mask */ -if (unlikely ((vma->vm_flags & ~calc_vm_prot_bits (asma->prot_mask)) & -calc_vm_prot_bits (PROT_MASK ))) { +if (unlikely ((vma->vm_flags & ~calc_vm_prot_bits (asma->prot_mask,0 )) & +calc_vm_prot_bits (PROT_MASK ,0 ))) { ret = -EPERM ; goto out; }
include/linux/mman.h +3 -3
@@ -35,7 +35,7 @@ static inline void vm_unacct_memory(long pages)*/ #ifndef arch_calc_vm_prot_bits -#define arch_calc_vm_prot_bits (prot) 0 +#define arch_calc_vm_prot_bits (prot, pkey) 0#endif #ifndef arch_vm_get_page_prot
@@ -70,12 +70,12 @@ static inline int arch_validate_prot(unsigned long prot)* Combine the mmap "prot" argument into "vm_flags" used internally. */ static inline unsigned long -calc_vm_prot_bits (unsigned long prot) +calc_vm_prot_bits (unsigned long prot,unsigned long pkey) {return _calc_vm_trans (prot,PROT_READ ,VM_READ ) |_calc_vm_trans (prot,PROT_WRITE ,VM_WRITE ) |_calc_vm_trans (prot,PROT_EXEC ,VM_EXEC ) | -arch_calc_vm_prot_bits (prot); +arch_calc_vm_prot_bits (prot, pkey); }/*
mm/mmap.c +1 -1
@@ -1313,7 +1313,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr,* to. we assume access permissions have been handled by the open * of the memory object, so we don't do any here. */ - vm_flags |=calc_vm_prot_bits (prot) |calc_vm_flag_bits (flags) | + vm_flags |=calc_vm_prot_bits (prot,0 ) |calc_vm_flag_bits (flags) | mm->def_flags |VM_MAYREAD |VM_MAYWRITE |VM_MAYEXEC ;if (flags &MAP_LOCKED )
mm/mprotect.c +1 -1
@@ -380,7 +380,7 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,if ((prot &PROT_READ ) && (current->personality &READ_IMPLIES_EXEC )) prot |=PROT_EXEC ; - vm_flags =calc_vm_prot_bits (prot); + vm_flags =calc_vm_prot_bits (prot,0 );down_write (¤t->mm->mmap_sem);
mm/nommu.c +1 -1
@@ -1082,7 +1082,7 @@ static unsigned long determine_vm_flags(struct file *file, {unsigned long vm_flags; - vm_flags =calc_vm_prot_bits (prot) |calc_vm_flag_bits (flags); + vm_flags =calc_vm_prot_bits (prot,0 ) |calc_vm_flag_bits (flags);/* vm_flags |= mm->def_flags; */ if (!(capabilities &NOMMU_MAP_DIRECT )) {
PATCH 28/33 x86, pkeys: add arch_validate_pkey()
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
The syscall-level code is passed a protection key and need to return an appropriate error code if the protection key is bogus. We will be using this in subsequent patches.
Note that this also begins a series of arch-specific calls that we need to expose in otherwise arch-independent code. We create a linux/pkeys.h header where we will put *all* the stubs for these functions.
---
b/arch/x86/Kconfig | 1 + b/arch/x86/include/asm/pkeys.h | 6 ++++++ b/include/linux/pkeys.h | 25 +++++++++++++++++++++++++ b/mm/Kconfig | 2 ++ 4 files changed, 34 insertions(+)
arch/x86/include/asm/pkeys.h new file +6 -0
@@ -0,0 +1,6 @@ +#ifndef _ASM_X86_PKEYS_H +#define _ASM_X86_PKEYS_H + +#define arch_max_pkey () (boot_cpu_has(X86_FEATURE_OSPKE) ? 16 : 1) + +#endif /*_ASM_X86_PKEYS_H */
arch/x86/Kconfig renamed from arch/x86/Kconfig~pkeys-71-arch_validate_pkey +1 -0
@@ -156,6 +156,7 @@ config X86 select X86_DEV_DMA_OPS if X86_64 select X86_FEATURE_NAMES if PROC_FS select ARCH_USES_HIGH_VMA_FLAGS if X86_INTEL_MEMORY_PROTECTION_KEYS + select ARCH_HAS_PKEYS if X86_INTEL_MEMORY_PROTECTION_KEYS config INSTRUCTION_DECODER def_bool y
include/linux/pkeys.h new file +25 -0
@@ -0,0 +1,25 @@ +#ifndef _LINUX_PKEYS_H +#define _LINUX_PKEYS_H + +#include <linux/mm_types.h> +#include <asm/mmu_context.h> + +#ifdef CONFIG_ARCH_HAS_PKEYS +#include <asm/pkeys.h> +#else /* ! CONFIG_ARCH_HAS_PKEYS */ +#define arch_max_pkey () (1) +#endif /* ! CONFIG_ARCH_HAS_PKEYS */ + +/* +* This is called from mprotect_pkey(). +* +* Returns true if the protection keys is valid. +*/ +static inline bool validate_pkey (int pkey) +{ +if (pkey <0 ) +return false; +return (pkey <arch_max_pkey ()); +} + +#endif /* _LINUX_PKEYS_H */
mm/Kconfig renamed from mm/Kconfig~pkeys-71-arch_validate_pkey +2 -0
@@ -672,3 +672,5 @@ config FRAME_VECTOR config ARCH_USES_HIGH_VMA_FLAGS bool +config ARCH_HAS_PKEYS + bool
_
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] mm/core, x86/mm/pkeys: Add arch_validate_pkey()
mm/core, x86/mm/pkeys: Add arch_validate_pkey()
Commit-ID: 66d375709d2c891acc639538fd3179fa0cbb0daf Gitweb: http://git.kernel.org/tip/66d375709d2c891acc639538fd3179fa0cbb0daf Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:32 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 19:46:31 +0100
mm/core, x86/mm/pkeys: Add arch_validate_pkey()
The syscall-level code is passed a protection key and need to return an appropriate error code if the protection key is bogus. We will be using this in subsequent patches.
Note that this also begins a series of arch-specific calls that we need to expose in otherwise arch-independent code. We create a linux/pkeys.h header where we will put *all* the stubs for these functions.
--- arch/x86/Kconfig | 1 + arch/x86/include/asm/pkeys.h | 6 ++++++ include/linux/pkeys.h | 25 +++++++++++++++++++++++++ mm/Kconfig | 2 ++ 4 files changed, 34 insertions(+)
arch/x86/Kconfig +1 -0
@@ -156,6 +156,7 @@ config X86 select X86_DEV_DMA_OPS if X86_64 select X86_FEATURE_NAMES if PROC_FS select ARCH_USES_HIGH_VMA_FLAGS if X86_INTEL_MEMORY_PROTECTION_KEYS + select ARCH_HAS_PKEYS if X86_INTEL_MEMORY_PROTECTION_KEYS config INSTRUCTION_DECODER def_bool y
arch/x86/include/asm/pkeys.h new file +6 -0
@@ -0,0 +1,6 @@ +#ifndef _ASM_X86_PKEYS_H +#define _ASM_X86_PKEYS_H + +#define arch_max_pkey () (boot_cpu_has(X86_FEATURE_OSPKE) ? 16 : 1) + +#endif /*_ASM_X86_PKEYS_H */
include/linux/pkeys.h new file +25 -0
@@ -0,0 +1,25 @@ +#ifndef _LINUX_PKEYS_H +#define _LINUX_PKEYS_H + +#include <linux/mm_types.h> +#include <asm/mmu_context.h> + +#ifdef CONFIG_ARCH_HAS_PKEYS +#include <asm/pkeys.h> +#else /* ! CONFIG_ARCH_HAS_PKEYS */ +#define arch_max_pkey () (1) +#endif /* ! CONFIG_ARCH_HAS_PKEYS */ + +/* +* This is called from mprotect_pkey(). +* +* Returns true if the protection keys is valid. +*/ +static inline bool validate_pkey (int pkey) +{ +if (pkey <0 ) +return false; +return (pkey <arch_max_pkey ()); +} + +#endif /* _LINUX_PKEYS_H */
mm/Kconfig +2 -0
@@ -672,3 +672,5 @@ config FRAME_VECTOR config ARCH_USES_HIGH_VMA_FLAGS bool +config ARCH_HAS_PKEYS + bool
PATCH 29/33 x86: separate out LDT init from context init
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
The arch-specific mm_context_t is a great place to put protection-key allocation state.
But, we need to initialize the allocation state because pkey 0 is always "allocated". All of the runtime initialization of mm_context_t is done in *_ldt() manipulation functions. This renames the existing LDT functions like this:
init_new_context() -> init_new_context_ldt() destroy_context() -> destroy_context_ldt()
and makes init_new_context() and destroy_context() available for generic use.
---
b/arch/x86/include/asm/mmu_context.h | 21 ++++++++++++++++----- b/arch/x86/kernel/ldt.c | 4 ++-- 2 files changed, 18 insertions(+), 7 deletions(-)
arch/x86/include/asm/mmu_context.h renamed from arch/x86/include/asm/mmu_context.h~pkeys-72-init-ldt-extricate +16 -5
@@ -52,15 +52,15 @@ struct ldt_struct {/* * Used for LDT copy/destruction. */ -int init_new_context (struct task_struct *tsk,struct mm_struct *mm); -void destroy_context (struct mm_struct *mm); +int init_new_context_ldt (struct task_struct *tsk,struct mm_struct *mm); +void destroy_context_ldt (struct mm_struct *mm);#else /* CONFIG_MODIFY_LDT_SYSCALL */ -static inline int init_new_context (struct task_struct *tsk, -struct mm_struct *mm) +static inline int init_new_context_ldt (struct task_struct *tsk, +struct mm_struct *mm) {return 0 ; } -static inline void destroy_context (struct mm_struct *mm) {} +static inline void destroy_context_ldt (struct mm_struct *mm) {}#endif static inline void load_mm_ldt (struct mm_struct *mm)
@@ -104,6 +104,17 @@ static inline void enter_lazy_tlb(struct#endif } +static inline int init_new_context (struct task_struct *tsk, +struct mm_struct *mm) +{ +init_new_context_ldt (tsk, mm); +return 0 ; +} +static inline void destroy_context (struct mm_struct *mm) +{ +destroy_context_ldt (mm); +} +static inline void switch_mm (struct mm_struct *prev,struct mm_struct *next,struct task_struct *tsk) {
arch/x86/kernel/ldt.c renamed from arch/x86/kernel/ldt.c~pkeys-72-init-ldt-extricate +2 -2
@@ -103,7 +103,7 @@ static void free_ldt_struct(struct ldt_s* we do not have to muck with descriptors here, that is * done in switch_mm() as needed. */ -int init_new_context (struct task_struct *tsk,struct mm_struct *mm) +int init_new_context_ldt (struct task_struct *tsk,struct mm_struct *mm) {struct ldt_struct *new_ldt;struct mm_struct *old_mm;
@@ -144,7 +144,7 @@ out_unlock:* * 64bit: Don't touch the LDT register - we're already in the next thread. */ -void destroy_context (struct mm_struct *mm) +void destroy_context_ldt (struct mm_struct *mm) {free_ldt_struct (mm->context.ldt); mm->context.ldt =NULL ;
_
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/mm: Factor out LDT init from context init
x86/mm: Factor out LDT init from context init
Commit-ID: 39a0526fb3f7d93433d146304278477eb463f8af Gitweb: http://git.kernel.org/tip/39a0526fb3f7d93433d146304278477eb463f8af Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:34 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 19:46:31 +0100
x86/mm: Factor out LDT init from context init
The arch-specific mm_context_t is a great place to put protection-key allocation state.
But, we need to initialize the allocation state because pkey 0 is always "allocated". All of the runtime initialization of mm_context_t is done in *_ldt() manipulation functions. This renames the existing LDT functions like this:
init_new_context() -> init_new_context_ldt() destroy_context() -> destroy_context_ldt()
and makes init_new_context() and destroy_context() available for generic use.
--- arch/x86/include/asm/mmu_context.h | 21 ++++++++++++++++----- arch/x86/kernel/ldt.c | 4 ++-- 2 files changed, 18 insertions(+), 7 deletions(-)
arch/x86/include/asm/mmu_context.h +16 -5
@@ -52,15 +52,15 @@ struct ldt_struct {/* * Used for LDT copy/destruction. */ -int init_new_context (struct task_struct *tsk,struct mm_struct *mm); -void destroy_context (struct mm_struct *mm); +int init_new_context_ldt (struct task_struct *tsk,struct mm_struct *mm); +void destroy_context_ldt (struct mm_struct *mm);#else /* CONFIG_MODIFY_LDT_SYSCALL */ -static inline int init_new_context (struct task_struct *tsk, -struct mm_struct *mm) +static inline int init_new_context_ldt (struct task_struct *tsk, +struct mm_struct *mm) {return 0 ; } -static inline void destroy_context (struct mm_struct *mm) {} +static inline void destroy_context_ldt (struct mm_struct *mm) {}#endif static inline void load_mm_ldt (struct mm_struct *mm)
@@ -104,6 +104,17 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)#endif } +static inline int init_new_context (struct task_struct *tsk, +struct mm_struct *mm) +{ +init_new_context_ldt (tsk, mm); +return 0 ; +} +static inline void destroy_context (struct mm_struct *mm) +{ +destroy_context_ldt (mm); +} +static inline void switch_mm (struct mm_struct *prev,struct mm_struct *next,struct task_struct *tsk) {
arch/x86/kernel/ldt.c +2 -2
@@ -103,7 +103,7 @@ static void free_ldt_struct(struct ldt_struct *ldt)* we do not have to muck with descriptors here, that is * done in switch_mm() as needed. */ -int init_new_context (struct task_struct *tsk,struct mm_struct *mm) +int init_new_context_ldt (struct task_struct *tsk,struct mm_struct *mm) {struct ldt_struct *new_ldt;struct mm_struct *old_mm;
@@ -144,7 +144,7 @@ out_unlock:* * 64bit: Don't touch the LDT register - we're already in the next thread. */ -void destroy_context (struct mm_struct *mm) +void destroy_context_ldt (struct mm_struct *mm) {free_ldt_struct (mm->context.ldt); mm->context.ldt =NULL ;
PATCH 30/33 x86, fpu: allow setting of XSAVE state
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
We want to modify the Protection Key rights inside the kernel, so we need to change PKRU's contents. But, if we do a plain 'wrpkru', when we return to userspace we might do an XRSTOR and wipe out the kernel's 'wrpkru'. So, we need to go after PKRU in the xsave buffer.
We do this by:
1. Ensuring that we have the XSAVE registers (fpregs) in the kernel FPU buffer (fpstate)
2. Looking up the location of a given state in the buffer
3. Filling in the stat
4. Ensuring that the hardware knows that state is present there (basically that the 'init optimization' is not in place).
5. Copying the newly-modified state back to the registers if necessary.
---
b/arch/x86/include/asm/fpu/internal.h | 2 b/arch/x86/kernel/fpu/core.c | 63 +++++++++++++++++++++ b/arch/x86/kernel/fpu/xstate.c | 98 +++++++++++++++++++++++++++++++++- 3 files changed, 161 insertions(+), 2 deletions(-)
arch/x86/include/asm/fpu/internal.h renamed from arch/x86/include/asm/fpu/internal.h~pkeys-76-xsave-set +2 -0
@@ -24,6 +24,8 @@extern void fpu__activate_curr (struct fpu *fpu);extern void fpu__activate_fpstate_read (struct fpu *fpu);extern void fpu__activate_fpstate_write (struct fpu *fpu); +extern void fpu__current_fpstate_write_begin (void ); +extern void fpu__current_fpstate_write_end (void );extern void fpu__save (struct fpu *fpu);extern void fpu__restore (struct fpu *fpu);extern int fpu__restore_sig (void __user *buf,int ia32_frame);
arch/x86/kernel/fpu/core.c renamed from arch/x86/kernel/fpu/core.c~pkeys-76-xsave-set +63 -0
69 lines not on this page · raw message
arch/x86/kernel/fpu/xstate.c renamed from arch/x86/kernel/fpu/xstate.c~pkeys-76-xsave-set +96 -2
119 lines not on this page · raw message
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/fpu: Allow setting of XSAVE state
x86/fpu: Allow setting of XSAVE state
Commit-ID: b8b9b6ba9dec3f155c7555cb208ba4078e97aedb Gitweb: http://git.kernel.org/tip/b8b9b6ba9dec3f155c7555cb208ba4078e97aedb Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:35 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 19:46:32 +0100
x86/fpu: Allow setting of XSAVE state
We want to modify the Protection Key rights inside the kernel, so we need to change PKRU's contents. But, if we do a plain 'wrpkru', when we return to userspace we might do an XRSTOR and wipe out the kernel's 'wrpkru'. So, we need to go after PKRU in the xsave buffer.
We do this by:
1. Ensuring that we have the XSAVE registers (fpregs) in the kernel FPU buffer (fpstate)
2. Looking up the location of a given state in the buffer
3. Filling in the stat
4. Ensuring that the hardware knows that state is present there (basically that the 'init optimization' is not in place).
5. Copying the newly-modified state back to the registers if necessary.
--- arch/x86/include/asm/fpu/internal.h | 2 + arch/x86/kernel/fpu/core.c | 63 ++++++++++++++++++++++++ arch/x86/kernel/fpu/xstate.c | 98 ++++++++++++++++++++++++++++++++++++- 3 files changed, 161 insertions(+), 2 deletions(-)
arch/x86/include/asm/fpu/internal.h +2 -0
@@ -25,6 +25,8 @@extern void fpu__activate_curr (struct fpu *fpu);extern void fpu__activate_fpstate_read (struct fpu *fpu);extern void fpu__activate_fpstate_write (struct fpu *fpu); +extern void fpu__current_fpstate_write_begin (void ); +extern void fpu__current_fpstate_write_end (void );extern void fpu__save (struct fpu *fpu);extern void fpu__restore (struct fpu *fpu);extern int fpu__restore_sig (void __user *buf,int ia32_frame);
arch/x86/kernel/fpu/core.c +63 -0
69 lines not on this page · raw message
arch/x86/kernel/fpu/xstate.c +96 -2
119 lines not on this page · raw message
PATCH 31/33 x86, pkeys: allow kernel to modify user pkey rights register
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
The Protection Key Rights for User memory (PKRU) is a 32-bit user-accessible register. It contains two bits for each protection key: one to write-disable (WD) access to memory covered by the key and another to access-disable (AD).
Userspace can read/write the register with the RDPKRU and WRPKRU instructions. But, the register is saved and restored with the XSAVE family of instructions, which means we have to treat it like a floating point register.
The kernel needs to write to the register if it wants to implement execute-only memory or if it implements a system call to change PKRU.
To do this, we need to create a 'pkru_state' buffer, read the old contents in to it, modify it, and then tell the FPU code that there is modified data in there so it can (possibly) move the buffer back in to the registers.
This uses the fpu__xfeature_set_state() function that we defined in the previous patch.
---
b/arch/x86/include/asm/pgtable.h | 5 +- b/arch/x86/include/asm/pkeys.h | 3 + b/arch/x86/kernel/fpu/xstate.c | 74 +++++++++++++++++++++++++++++++++++++++ b/include/linux/pkeys.h | 5 ++ 4 files changed, 85 insertions(+), 2 deletions(-)
arch/x86/include/asm/pgtable.h renamed from arch/x86/include/asm/pgtable.h~pkeys-77-arch_set_user_pkey_access +3 -2
@@ -921,16 +921,17 @@ static inline pte_t pte_swp_clear_soft_d#define PKRU_AD_BIT 0x1#define PKRU_WD_BIT 0x2 +#define PKRU_BITS_PER_PKEY 2static inline bool __pkru_allows_read (u32 pkru,u16 pkey) { -int pkru_pkey_bits = pkey *2 ; +int pkru_pkey_bits = pkey *PKRU_BITS_PER_PKEY ;return !(pkru & (PKRU_AD_BIT << pkru_pkey_bits)); }static inline bool __pkru_allows_write (u32 pkru,u16 pkey) { -int pkru_pkey_bits = pkey *2 ; +int pkru_pkey_bits = pkey *PKRU_BITS_PER_PKEY ;/* * Access-disable disables writes too so we need to check * both bits here.
arch/x86/include/asm/pkeys.h renamed from arch/x86/include/asm/pkeys.h~pkeys-77-arch_set_user_pkey_access +3 -0
@@ -3,4 +3,7 @@#define arch_max_pkey () (boot_cpu_has(X86_FEATURE_OSPKE) ? 16 : 1) +extern int arch_set_user_pkey_access (struct task_struct *tsk,int pkey, +unsigned long init_val); +#endif /*_ASM_X86_PKEYS_H */
arch/x86/kernel/fpu/xstate.c renamed from arch/x86/kernel/fpu/xstate.c~pkeys-77-arch_set_user_pkey_access +74 -0
83 lines not on this page · raw message
include/linux/pkeys.h renamed from include/linux/pkeys.h~pkeys-77-arch_set_user_pkey_access +5 -0
@@ -4,6 +4,11 @@#include <linux/mm_types.h> #include <asm/mmu_context.h> +#define PKEY_DISABLE_ACCESS 0x1 +#define PKEY_DISABLE_WRITE 0x2 +#define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\ + PKEY_DISABLE_WRITE) +#ifdef CONFIG_ARCH_HAS_PKEYS #include <asm/pkeys.h> #else /* ! CONFIG_ARCH_HAS_PKEYS */
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/mm/pkeys: Allow kernel to modify user pkey rights register
x86/mm/pkeys: Allow kernel to modify user pkey rights register
Commit-ID: 8459429693395ca9e8d18101300b120ad9171795 Gitweb: http://git.kernel.org/tip/8459429693395ca9e8d18101300b120ad9171795 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:36 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 19:46:32 +0100
x86/mm/pkeys: Allow kernel to modify user pkey rights register
The Protection Key Rights for User memory (PKRU) is a 32-bit user-accessible register. It contains two bits for each protection key: one to write-disable (WD) access to memory covered by the key and another to access-disable (AD).
Userspace can read/write the register with the RDPKRU and WRPKRU instructions. But, the register is saved and restored with the XSAVE family of instructions, which means we have to treat it like a floating point register.
The kernel needs to write to the register if it wants to implement execute-only memory or if it implements a system call to change PKRU.
To do this, we need to create a 'pkru_state' buffer, read the old contents in to it, modify it, and then tell the FPU code that there is modified data in there so it can (possibly) move the buffer back in to the registers.
This uses the fpu__xfeature_set_state() function that we defined in the previous patch.
--- arch/x86/include/asm/pgtable.h | 5 +-- arch/x86/include/asm/pkeys.h | 3 ++ arch/x86/kernel/fpu/xstate.c | 74 ++++++++++++++++++++++++++++++++++++++++++ include/linux/pkeys.h | 5 +++ 4 files changed, 85 insertions(+), 2 deletions(-)
arch/x86/include/asm/pgtable.h +3 -2
@@ -921,16 +921,17 @@ static inline pte_t pte_swp_clear_soft_dirty(pte_t pte)#define PKRU_AD_BIT 0x1#define PKRU_WD_BIT 0x2 +#define PKRU_BITS_PER_PKEY 2static inline bool __pkru_allows_read (u32 pkru,u16 pkey) { -int pkru_pkey_bits = pkey *2 ; +int pkru_pkey_bits = pkey *PKRU_BITS_PER_PKEY ;return !(pkru & (PKRU_AD_BIT << pkru_pkey_bits)); }static inline bool __pkru_allows_write (u32 pkru,u16 pkey) { -int pkru_pkey_bits = pkey *2 ; +int pkru_pkey_bits = pkey *PKRU_BITS_PER_PKEY ;/* * Access-disable disables writes too so we need to check * both bits here.
arch/x86/include/asm/pkeys.h +3 -0
@@ -3,4 +3,7 @@#define arch_max_pkey () (boot_cpu_has(X86_FEATURE_OSPKE) ? 16 : 1) +extern int arch_set_user_pkey_access (struct task_struct *tsk,int pkey, +unsigned long init_val); +#endif /*_ASM_X86_PKEYS_H */
arch/x86/kernel/fpu/xstate.c +74 -0
83 lines not on this page · raw message
include/linux/pkeys.h +5 -0
@@ -4,6 +4,11 @@#include <linux/mm_types.h> #include <asm/mmu_context.h> +#define PKEY_DISABLE_ACCESS 0x1 +#define PKEY_DISABLE_WRITE 0x2 +#define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\ + PKEY_DISABLE_WRITE) +#ifdef CONFIG_ARCH_HAS_PKEYS #include <asm/pkeys.h> #else /* ! CONFIG_ARCH_HAS_PKEYS */
PATCH 32/33 x86, pkeys: create an x86 arch_calc_vm_prot_bits() for VMA flags
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
calc_vm_prot_bits() takes PROT_{READ,WRITE,EXECUTE} bits and turns them in to the vma->vm_flags/VM_* bits. We need to do a similar thing for protection keys.
We take a protection key (4 bits) and encode it in to the 4 VM_PKEY_* bits.
Note: this code is not new. It was simply a part of the mprotect_pkey() patch in the past. I broke it out for use in the execute-only support.
---
b/arch/x86/include/uapi/asm/mman.h | 6 ++++++ 1 file changed, 6 insertions(+)
arch/x86/include/uapi/asm/mman.h renamed from arch/x86/include/uapi/asm/mman.h~pkeys-78-arch_calc_vm_prot_bits +6 -0
@@ -20,6 +20,12 @@ ((vm_flags) & VM_PKEY_BIT1 ? _PAGE_PKEY_BIT1 : 0) | \ ((vm_flags) & VM_PKEY_BIT2 ? _PAGE_PKEY_BIT2 : 0) | \ ((vm_flags) & VM_PKEY_BIT3 ? _PAGE_PKEY_BIT3 : 0)) + +#define arch_calc_vm_prot_bits (prot, key) ( \ + ((key) & 0x1 ? VM_PKEY_BIT0 : 0) | \ + ((key) & 0x2 ? VM_PKEY_BIT1 : 0) | \ + ((key) & 0x4 ? VM_PKEY_BIT2 : 0) | \ + ((key) & 0x8 ? VM_PKEY_BIT3 : 0))#endif #include <asm-generic/mman.h>
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] x86/mm/pkeys: Create an x86 arch_calc_vm_prot_bits () for VMA flags
x86/mm/pkeys: Create an x86 arch_calc_vm_prot_bits() for VMA flags
Commit-ID: 878ba03932d757ce4e954db4defec74a0de0435b Gitweb: http://git.kernel.org/tip/878ba03932d757ce4e954db4defec74a0de0435b Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:37 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 19:46:32 +0100
x86/mm/pkeys: Create an x86 arch_calc_vm_prot_bits() for VMA flags
calc_vm_prot_bits() takes PROT_{READ,WRITE,EXECUTE} bits and turns them in to the vma->vm_flags/VM_* bits. We need to do a similar thing for protection keys.
We take a protection key (4 bits) and encode it in to the 4 VM_PKEY_* bits.
Note: this code is not new. It was simply a part of the mprotect_pkey() patch in the past. I broke it out for use in the execute-only support.
--- arch/x86/include/uapi/asm/mman.h | 6 ++++++ 1 file changed, 6 insertions(+)
arch/x86/include/uapi/asm/mman.h +6 -0
@@ -20,6 +20,12 @@ ((vm_flags) & VM_PKEY_BIT1 ? _PAGE_PKEY_BIT1 : 0) | \ ((vm_flags) & VM_PKEY_BIT2 ? _PAGE_PKEY_BIT2 : 0) | \ ((vm_flags) & VM_PKEY_BIT3 ? _PAGE_PKEY_BIT3 : 0)) + +#define arch_calc_vm_prot_bits (prot, key) ( \ + ((key) & 0x1 ? VM_PKEY_BIT0 : 0) | \ + ((key) & 0x2 ? VM_PKEY_BIT1 : 0) | \ + ((key) & 0x4 ? VM_PKEY_BIT2 : 0) | \ + ((key) & 0x8 ? VM_PKEY_BIT3 : 0))#endif #include <asm-generic/mman.h>
PATCH 33/33 x86, pkeys: execute-only support
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
Protection keys provide new page-based protection in hardware. But, they have an interesting attribute: they only affect data accesses and never affect instruction fetches. That means that if we set up some memory which is set as "access-disabled" via protection keys, we can still execute from it.
This patch uses protection keys to set up mappings to do just that. If a user calls:
mmap(..., PROT_EXEC); or mprotect(ptr, sz, PROT_EXEC);
(note PROT_EXEC-only without PROT_READ/WRITE), the kernel will notice this, and set a special protection key on the memory. It also sets the appropriate bits in the Protection Keys User Rights (PKRU) register so that the memory becomes unreadable and unwritable.
I haven't found any userspace that does this today. With this facility in place, we expect userspace to move to use it eventually. Userspace _could_ start doing this today. Any PROT_EXEC calls get converted to PROT_READ inside the kernel, and would transparently be upgraded to "true" PROT_EXEC with this code. IOW, userspace never has to do any PROT_EXEC runtime detection.
This feature provides enhanced protection against leaking executable memory contents. This helps thwart attacks which are attempting to find ROP gadgets on the fly.
But, the security provided by this approach is not comprehensive. The PKRU register which controls access permissions is a normal user register writable from unprivileged userspace. An attacker who can execute the 'wrpkru' instruction can easily disable the protection provided by this feature.
The protection key that is used for execute-only support is permanently dedicated at compile time. This is fine for now because there is currently no API to set a protection key other than this one.
Despite there being a constant PKRU value across the entire system, we do not set it unless this feature is in use in a process. That is to preserve the PKRU XSAVE 'init state', which can lead to faster context switches.
PKRU *is* a user register and the kernel is modifying it. That means that code doing:
pkru = rdpkru() pkru |= 0x100; mmap(..., PROT_EXEC); wrpkru(pkru);
could lose the bits in PKRU that enforce execute-only permissions. To avoid this, we suggest avoiding ever calling mmap() or mprotect() when the PKRU value is expected to be unstable.
---
b/arch/x86/include/asm/pkeys.h | 25 ++++++++++ b/arch/x86/kernel/fpu/xstate.c | 2 b/arch/x86/mm/Makefile | 2 b/arch/x86/mm/fault.c | 10 ++++ b/arch/x86/mm/pkeys.c | 101 +++++++++++++++++++++++++++++++++++++++++ b/include/linux/pkeys.h | 3 + b/mm/mmap.c | 10 +++- b/mm/mprotect.c | 8 +-- 8 files changed, 154 insertions(+), 7 deletions(-)
arch/x86/include/asm/pkeys.h renamed from arch/x86/include/asm/pkeys.h~pkeys-79-xonly +25 -0
@@ -6,4 +6,29 @@extern int arch_set_user_pkey_access (struct task_struct *tsk,int pkey,unsigned long init_val); +/* +* Try to dedicate one of the protection keys to be used as an +* execute-only protection key. +*/ +#define PKEY_DEDICATED_EXECUTE_ONLY 15 +extern int __execute_only_pkey (struct mm_struct *mm); +static inline int execute_only_pkey (struct mm_struct *mm) +{ +if (!boot_cpu_has (X86_FEATURE_OSPKE )) +return 0 ; + +return __execute_only_pkey (mm); +} + +extern int __arch_override_mprotect_pkey (struct vm_area_struct *vma, +int prot,int pkey); +static inline int arch_override_mprotect_pkey (struct vm_area_struct *vma, +int prot,int pkey) +{ +if (!boot_cpu_has (X86_FEATURE_OSPKE )) +return 0 ; + +return __arch_override_mprotect_pkey (vma, prot, pkey); +} +#endif /*_ASM_X86_PKEYS_H */
arch/x86/kernel/fpu/xstate.c renamed from arch/x86/kernel/fpu/xstate.c~pkeys-79-xonly +0 -2
@@ -877,8 +877,6 @@ int arch_set_user_pkey_access(struct tasint pkey_shift = (pkey *PKRU_BITS_PER_PKEY );u32 new_pkru_bits =0 ; -if (!validate_pkey (pkey)) -return -EINVAL ;/* * This check implies XSAVE support. OSPKE only gets * set if we enable XSAVE and we enable PKU in XCR0.
arch/x86/mm/fault.c renamed from arch/x86/mm/fault.c~pkeys-79-xonly +10 -0
@@ -1108,6 +1108,16 @@ access_error(unsigned long error_code, s*/ if (error_code &PF_PK )return 1 ; + +if (!(error_code &PF_INSTR )) { +/* +* Assume all accesses require either read or execute +* permissions. This is not an instruction access, so +* it requires read permissions. +*/ +if (!(vma->vm_flags &VM_READ )) +return 1 ; + }/* * Make sure to check the VMA so that we do not perform * faults just to hit a PF_PK as soon as we fill in a
arch/x86/mm/Makefile renamed from arch/x86/mm/Makefile~pkeys-79-xonly +2 -0
@@ -34,3 +34,5 @@ obj-$(CONFIG_ACPI_NUMA) += srat.o obj-$(CONFIG_NUMA_EMU) += numa_emulation.o obj-$(CONFIG_X86_INTEL_MPX) += mpx.o +obj-$(CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS) += pkeys.o +
arch/x86/mm/pkeys.c new file +101 -0
101 lines not on this page · raw message
include/linux/pkeys.h renamed from include/linux/pkeys.h~pkeys-79-xonly +3 -0
@@ -13,6 +13,9 @@#include <asm/pkeys.h> #else /* ! CONFIG_ARCH_HAS_PKEYS */ #define arch_max_pkey () (1) +#define execute_only_pkey (mm) (0) +#define arch_override_mprotect_pkey (vma, prot, pkey) (0) +#define PKEY_DEDICATED_EXECUTE_ONLY 0#endif /* ! CONFIG_ARCH_HAS_PKEYS */ /*
mm/mmap.c renamed from mm/mmap.c~pkeys-79-xonly +9 -1
@@ -43,6 +43,7 @@#include <linux/printk.h> #include <linux/userfaultfd_k.h> #include <linux/moduleparam.h> +#include <linux/pkeys.h> #include <asm/uaccess.h> #include <asm/cacheflush.h>
@@ -1270,6 +1271,7 @@ unsigned long do_mmap(struct file *file, unsigned long pgoff, unsigned long *populate) { struct mm_struct *mm = current->mm; +int pkey =0 ; *populate =0 ;
@@ -1309,11 +1311,17 @@ unsigned long do_mmap(struct file *file,if (offset_in_page (addr))return addr; +if (prot ==PROT_EXEC ) { + pkey =execute_only_pkey (mm); +if (pkey <0 ) + pkey =0 ; + } +/* Do simple checking here so the lower-level routines won't have * to. we assume access permissions have been handled by the open * of the memory object, so we don't do any here. */ - vm_flags |=calc_vm_prot_bits (prot,0 ) |calc_vm_flag_bits (flags) | + vm_flags |=calc_vm_prot_bits (prot, pkey) |calc_vm_flag_bits (flags) | mm->def_flags |VM_MAYREAD |VM_MAYWRITE |VM_MAYEXEC ;if (flags &MAP_LOCKED )
mm/mprotect.c renamed from mm/mprotect.c~pkeys-79-xonly +4 -4
@@ -24,6 +24,7 @@#include <linux/migrate.h> #include <linux/perf_event.h> #include <linux/ksm.h> +#include <linux/pkeys.h> #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/cacheflush.h>
@@ -352,7 +353,7 @@ fail: SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, unsigned long, prot) { -unsigned long vm_flags, nstart, end, tmp, reqprot; +unsigned long nstart, end, tmp, reqprot;struct vm_area_struct *vma, *prev;int error = -EINVAL ;const int grows = prot & (PROT_GROWSDOWN |PROT_GROWSUP );
@@ -378,8 +379,6 @@ SYSCALL_DEFINE3(mprotect, unsigned long,if ((prot &PROT_READ ) && (current->personality &READ_IMPLIES_EXEC )) prot |=PROT_EXEC ; - vm_flags =calc_vm_prot_bits (prot,0 ); -down_write (¤t->mm->mmap_sem); vma =find_vma (current->mm, start);
@@ -409,10 +408,11 @@ SYSCALL_DEFINE3(mprotect, unsigned long,for (nstart = start ; ; ) {unsigned long newflags; +int pkey =arch_override_mprotect_pkey (vma, prot,-1 );/* Here we know that vma->vm_start <= nstart < vma->vm_end. */ - newflags = vm_flags; + newflags =calc_vm_prot_bits (prot, pkey); newflags |= (vma->vm_flags & ~(VM_READ |VM_WRITE |VM_EXEC ));/* newflags >> 4 shift VM_MAY% in place of VM_% */
_
Re: [PATCH 33/33] x86, pkeys: execute-only support
Quoted 22 lines · Dave Hansen
From: Dave Hansen <[email protected]>
Protection keys provide new page-based protection in hardware. But, they have an interesting attribute: they only affect data accesses and never affect instruction fetches. That means that if we set up some memory which is set as "access-disabled" via protection keys, we can still execute from it.
This patch uses protection keys to set up mappings to do just that. If a user calls:
mmap(..., PROT_EXEC); or mprotect(ptr, sz, PROT_EXEC);(note PROT_EXEC-only without PROT_READ/WRITE), the kernel will notice this, and set a special protection key on the memory. It also sets the appropriate bits in the Protection Keys User Rights (PKRU) register so that the memory becomes unreadable and unwritable.
Quoted 7 lines
I haven't found any userspace that does this today. With this facility in place, we expect userspace to move to use it eventually. Userspace _could_ start doing this today. Any
PROT_EXECcalls get converted toPROT_READinside the kernel, and would transparently be upgraded to "true"PROT_EXECwith this code. IOW, userspace never has to do anyPROT_EXECruntime detection.
Random thought while skimming email:
Is there a way to detect this feature's availability without userspace having to set up a segv handler and attempting to read a PROT_EXEC-only region? (i.e. cpu flag for protection keys, or a way to check the protection to see if PROT_READ got added automatically, etc?)
-Kees
Signature · 8 lines
Kees Cook Chrome OS & Brillo Security -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 33/33] x86, pkeys: execute-only support
Quoted 5 lines · Kees Cook
Is there a way to detect this feature's availability without userspace having to set up a segv handler and attempting to read a PROT_EXEC-only region? (i.e. cpu flag for protection keys, or a way to check the protection to see if
PROT_READgot added automatically, etc?)
You can kinda do it with /proc/$pid/(s)maps. Here's smaps, for instance:
Quoted 3 lines
00401000-00402000 --xp 00001000 08:14 4897479
/root/pkeys/pkey-xonlySize: 4 kB Rss: 4 kB
...
Quoted 5 lines
KernelPageSize: 4 kB MMUPageSize: 4 kB Locked: 0 kB ProtectionKey: 15 VmFlags: ex mr mw me dw
You can see "--x" and the ProtectionKey itself being nonzero. That's a reasonable indication. There's also the "OSPKE" cpuid bit which only shows up when the kernel has enabled protection keys. This is _separate_ from the bit that says whether the processor support pkeys.
I check them in test code like this:
Quoted 29 lines
static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx){ /* ecx is often an input as well as an output. */ asm volatile( "cpuid;" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) : "0" (*eax), "2" (*ecx)); }/* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx) */
#defineX86_FEATURE_PKU(1<<3) /* Protection Keys for Userspace */
#defineX86_FEATURE_OSPKE(1<<4) /* OS Protection Keys Enable */static inline int
cpu_has_pku(void){ unsigned int eax; unsigned int ebx; unsigned int ecx; unsigned int edx; eax = 0x7; ecx = 0x0; __cpuid(&eax, &ebx, &ecx, &edx); if (!(ecx & X86_FEATURE_PKU)) { dprintf2("cpu does not have PKU\n");
Quoted 8 lines
return 0;
}
if (!(ecx & X86_FEATURE_OSPKE)) {
dprintf2("cpu does not have OSPKE\n");
return 0;
}
return 1;
}--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 33/33] x86, pkeys: execute-only support
Quoted 7 lines · Dave Hansen
Quoted 5 lines · Kees Cook
Is there a way to detect this feature's availability without userspace having to set up a segv handler and attempting to read a PROT_EXEC-only region? (i.e. cpu flag for protection keys, or a way to check the protection to see if
PROT_READgot added automatically, etc?)
Quoted 11 lines
You can kinda do it with /proc/$pid/(s)maps. Here's smaps, for instance:
Quoted 3 lines
00401000-00402000 --xp 00001000 08:14 4897479
/root/pkeys/pkey-xonlySize: 4 kB Rss: 4 kB...
Quoted 5 lines
KernelPageSize: 4 kB MMUPageSize: 4 kB Locked: 0 kB ProtectionKey: 15 VmFlags: ex mr mw me dw
Ah-ha, perfect. Thanks!
Quoted 5 lines
You can see "--x" and the ProtectionKey itself being nonzero. That's a reasonable indication. There's also the "OSPKE" cpuid bit which only shows up when the kernel has enabled protection keys. This is _separate_ from the bit that says whether the processor support pkeys.
Quoted 40 lines
I check them in test code like this:
Quoted 37 lines
static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx){ /* ecx is often an input as well as an output. */ asm volatile( "cpuid;" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) : "0" (*eax), "2" (*ecx)); }/* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx) */
#defineX86_FEATURE_PKU(1<<3) /* Protection Keys for Userspace */
#defineX86_FEATURE_OSPKE(1<<4) /* OS Protection Keys Enable */static inline int
cpu_has_pku(void){ unsigned int eax; unsigned int ebx; unsigned int ecx; unsigned int edx; eax = 0x7; ecx = 0x0; __cpuid(&eax, &ebx, &ecx, &edx); if (!(ecx & X86_FEATURE_PKU)) { dprintf2("cpu does not have PKU\n"); return 0; } if (!(ecx & X86_FEATURE_OSPKE)) { dprintf2("cpu does not have OSPKE\n"); return 0; } return 1; }
Great, thanks for the example!
-Kees
Signature · 8 lines
Kees Cook Chrome OS & Brillo Security -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 33/33] x86, pkeys: execute-only support
In reply to Kees CookQuoted 32 lines · Kees Cook
Quoted 22 lines · Dave Hansen
From: Dave Hansen <[email protected]>
Protection keys provide new page-based protection in hardware. But, they have an interesting attribute: they only affect data accesses and never affect instruction fetches. That means that if we set up some memory which is set as "access-disabled" via protection keys, we can still execute from it.
This patch uses protection keys to set up mappings to do just that. If a user calls:
mmap(..., PROT_EXEC); or mprotect(ptr, sz, PROT_EXEC);(note PROT_EXEC-only without PROT_READ/WRITE), the kernel will notice this, and set a special protection key on the memory. It also sets the appropriate bits in the Protection Keys User Rights (PKRU) register so that the memory becomes unreadable and unwritable.
Quoted 7 lines
I haven't found any userspace that does this today. With this facility in place, we expect userspace to move to use it eventually. Userspace _could_ start doing this today. Any
PROT_EXECcalls get converted toPROT_READinside the kernel, and would transparently be upgraded to "true"PROT_EXECwith this code. IOW, userspace never has to do anyPROT_EXECruntime detection.
Quoted 8 lines
Random thought while skimming email:
Is there a way to detect this feature's availability without userspace having to set up a segv handler and attempting to read a PROT_EXEC-only region? (i.e. cpu flag for protection keys, or a way to check the protection to see if
PROT_READgot added automatically, etc?)
We could add an HWCAP.
--Andy
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 33/33] x86, pkeys: execute-only support
Quoted 7 lines · Andy Lutomirski
Quoted 6 lines
Quoted 6 lines
Is there a way to detect this feature's availability without userspace having to set up a segv handler and attempting to read a PROT_EXEC-only region? (i.e. cpu flag for protection keys, or a way to check the protection to see if
PROT_READgot added automatically, etc?)We could add an HWCAP.
I'll bite. What's an HWCAP?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 33/33] x86, pkeys: execute-only support
Quoted 10 lines · Dave Hansen
Quoted 7 lines · Andy Lutomirski
Quoted 6 lines
Quoted 6 lines
Is there a way to detect this feature's availability without userspace having to set up a segv handler and attempting to read a PROT_EXEC-only region? (i.e. cpu flag for protection keys, or a way to check the protection to see if
PROT_READgot added automatically, etc?)We could add an HWCAP.
I'll bite. What's an HWCAP?
It's a CPU capability vector that's passed to every program as an auxv entry. On x86, ELF_HWCAP is useless (it's already fully used up for pointless purposes for CPUID stuff), but ELF_HWCAP2 could be added and a bit could be defined like HWCAP2_PROT_EXEC_ONLY.
Some day, WRFSBASE, etc will be advertised via ELF_HWCAP2, I suspect.
--Andy
Signature · 8 lines
Andy Lutomirski AMA Capital Management, LLC -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dave Hansen
merge bot[tip:mm/pkeys] mm/core, x86/mm/pkeys: Add execute-only protection keys support
In reply to Dave Hansenmm/core, x86/mm/pkeys: Add execute-only protection keys support
Commit-ID: 62b5f7d013fc455b8db26cf01e421f4c0d264b92 Gitweb: http://git.kernel.org/tip/62b5f7d013fc455b8db26cf01e421f4c0d264b92 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 12 Feb 2016 13:02:40 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 18 Feb 2016 19:46:33 +0100
mm/core, x86/mm/pkeys: Add execute-only protection keys support
Protection keys provide new page-based protection in hardware. But, they have an interesting attribute: they only affect data accesses and never affect instruction fetches. That means that if we set up some memory which is set as "access-disabled" via protection keys, we can still execute from it.
This patch uses protection keys to set up mappings to do just that. If a user calls:
mmap(..., PROT_EXEC); or mprotect(ptr, sz, PROT_EXEC);
(note PROT_EXEC-only without PROT_READ/WRITE), the kernel will notice this, and set a special protection key on the memory. It also sets the appropriate bits in the Protection Keys User Rights (PKRU) register so that the memory becomes unreadable and unwritable.
I haven't found any userspace that does this today. With this facility in place, we expect userspace to move to use it eventually. Userspace _could_ start doing this today. Any PROT_EXEC calls get converted to PROT_READ inside the kernel, and would transparently be upgraded to "true" PROT_EXEC with this code. IOW, userspace never has to do any PROT_EXEC runtime detection.
This feature provides enhanced protection against leaking executable memory contents. This helps thwart attacks which are attempting to find ROP gadgets on the fly.
But, the security provided by this approach is not comprehensive. The PKRU register which controls access permissions is a normal user register writable from unprivileged userspace. An attacker who can execute the 'wrpkru' instruction can easily disable the protection provided by this feature.
The protection key that is used for execute-only support is permanently dedicated at compile time. This is fine for now because there is currently no API to set a protection key other than this one.
Despite there being a constant PKRU value across the entire system, we do not set it unless this feature is in use in a process. That is to preserve the PKRU XSAVE 'init state', which can lead to faster context switches.
PKRU *is* a user register and the kernel is modifying it. That means that code doing:
pkru = rdpkru() pkru |= 0x100; mmap(..., PROT_EXEC); wrpkru(pkru);
could lose the bits in PKRU that enforce execute-only permissions. To avoid this, we suggest avoiding ever calling mmap() or mprotect() when the PKRU value is expected to be unstable.
--- arch/x86/include/asm/pkeys.h | 25 +++++++++++ arch/x86/kernel/fpu/xstate.c | 2 - arch/x86/mm/Makefile | 2 + arch/x86/mm/fault.c | 10 +++++ arch/x86/mm/pkeys.c | 101 +++++++++++++++++++++++++++++++++++++++++++ include/linux/pkeys.h | 3 ++ mm/mmap.c | 10 ++++- mm/mprotect.c | 8 ++-- 8 files changed, 154 insertions(+), 7 deletions(-)
arch/x86/include/asm/pkeys.h +25 -0
@@ -6,4 +6,29 @@extern int arch_set_user_pkey_access (struct task_struct *tsk,int pkey,unsigned long init_val); +/* +* Try to dedicate one of the protection keys to be used as an +* execute-only protection key. +*/ +#define PKEY_DEDICATED_EXECUTE_ONLY 15 +extern int __execute_only_pkey (struct mm_struct *mm); +static inline int execute_only_pkey (struct mm_struct *mm) +{ +if (!boot_cpu_has (X86_FEATURE_OSPKE )) +return 0 ; + +return __execute_only_pkey (mm); +} + +extern int __arch_override_mprotect_pkey (struct vm_area_struct *vma, +int prot,int pkey); +static inline int arch_override_mprotect_pkey (struct vm_area_struct *vma, +int prot,int pkey) +{ +if (!boot_cpu_has (X86_FEATURE_OSPKE )) +return 0 ; + +return __arch_override_mprotect_pkey (vma, prot, pkey); +} +#endif /*_ASM_X86_PKEYS_H */
arch/x86/kernel/fpu/xstate.c +0 -2
@@ -877,8 +877,6 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,int pkey_shift = (pkey *PKRU_BITS_PER_PKEY );u32 new_pkru_bits =0 ; -if (!validate_pkey (pkey)) -return -EINVAL ;/* * This check implies XSAVE support. OSPKE only gets * set if we enable XSAVE and we enable PKU in XCR0.
arch/x86/mm/Makefile +2 -0
@@ -34,3 +34,5 @@ obj-$(CONFIG_ACPI_NUMA) += srat.o obj-$(CONFIG_NUMA_EMU) += numa_emulation.o obj-$(CONFIG_X86_INTEL_MPX) += mpx.o +obj-$(CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS) += pkeys.o +
arch/x86/mm/fault.c +10 -0
@@ -1108,6 +1108,16 @@ access_error(unsigned long error_code, struct vm_area_struct *vma)*/ if (error_code &PF_PK )return 1 ; + +if (!(error_code &PF_INSTR )) { +/* +* Assume all accesses require either read or execute +* permissions. This is not an instruction access, so +* it requires read permissions. +*/ +if (!(vma->vm_flags &VM_READ )) +return 1 ; + }/* * Make sure to check the VMA so that we do not perform * faults just to hit a PF_PK as soon as we fill in a
arch/x86/mm/pkeys.c new file +101 -0
101 lines not on this page · raw message
include/linux/pkeys.h +3 -0
@@ -13,6 +13,9 @@#include <asm/pkeys.h> #else /* ! CONFIG_ARCH_HAS_PKEYS */ #define arch_max_pkey () (1) +#define execute_only_pkey (mm) (0) +#define arch_override_mprotect_pkey (vma, prot, pkey) (0) +#define PKEY_DEDICATED_EXECUTE_ONLY 0#endif /* ! CONFIG_ARCH_HAS_PKEYS */ /*
mm/mmap.c +9 -1
@@ -43,6 +43,7 @@#include <linux/printk.h> #include <linux/userfaultfd_k.h> #include <linux/moduleparam.h> +#include <linux/pkeys.h> #include <asm/uaccess.h> #include <asm/cacheflush.h>
@@ -1270,6 +1271,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr, unsigned long pgoff, unsigned long *populate) { struct mm_struct *mm = current->mm; +int pkey =0 ; *populate =0 ;
@@ -1309,11 +1311,17 @@ unsigned long do_mmap(struct file *file, unsigned long addr,if (offset_in_page (addr))return addr; +if (prot ==PROT_EXEC ) { + pkey =execute_only_pkey (mm); +if (pkey <0 ) + pkey =0 ; + } +/* Do simple checking here so the lower-level routines won't have * to. we assume access permissions have been handled by the open * of the memory object, so we don't do any here. */ - vm_flags |=calc_vm_prot_bits (prot,0 ) |calc_vm_flag_bits (flags) | + vm_flags |=calc_vm_prot_bits (prot, pkey) |calc_vm_flag_bits (flags) | mm->def_flags |VM_MAYREAD |VM_MAYWRITE |VM_MAYEXEC ;if (flags &MAP_LOCKED )
mm/mprotect.c +4 -4
@@ -24,6 +24,7 @@#include <linux/migrate.h> #include <linux/perf_event.h> #include <linux/ksm.h> +#include <linux/pkeys.h> #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/cacheflush.h>
@@ -354,7 +355,7 @@ fail: SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, unsigned long, prot) { -unsigned long vm_flags, nstart, end, tmp, reqprot; +unsigned long nstart, end, tmp, reqprot;struct vm_area_struct *vma, *prev;int error = -EINVAL ;const int grows = prot & (PROT_GROWSDOWN |PROT_GROWSUP );
@@ -380,8 +381,6 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,if ((prot &PROT_READ ) && (current->personality &READ_IMPLIES_EXEC )) prot |=PROT_EXEC ; - vm_flags =calc_vm_prot_bits (prot,0 ); -down_write (¤t->mm->mmap_sem); vma =find_vma (current->mm, start);
@@ -411,10 +410,11 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,for (nstart = start ; ; ) {unsigned long newflags; +int pkey =arch_override_mprotect_pkey (vma, prot,-1 );/* Here we know that vma->vm_start <= nstart < vma->vm_end. */ - newflags = vm_flags; + newflags =calc_vm_prot_bits (prot, pkey); newflags |= (vma->vm_flags & ~(VM_READ |VM_WRITE |VM_EXEC ));/* newflags >> 4 shift VM_MAY% in place of VM_% */
Quoted 1 line · Dave Hansen
81 files changed, 1393 insertions(+), 233 deletions(-)
The MIPS defconfig cross-build failed for me - log attached below.
Thanks,
Ingo
===============>
CC security/keys/request_key_auth.o
In file included from /home/mingo/tip/arch/mips/include/asm/termios.h:12:0,
from /home/mingo/tip/include/uapi/linux/termios.h:5,
from /home/mingo/tip/include/linux/tty.h:6,
from /home/mingo/tip/kernel/signal.c:18:/home/mingo/tip/kernel/signal.c: In function 'copy_siginfo_to_user':/home/mingo/tip/include/uapi/asm-generic/siginfo.h:145:37: error: 'struct <anonymous>' has no member named '_pkey'
#define si_pkey _sifields._sigfault._pkey
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:441:15: note: in definition of macro '__put_user_nocheck'
__typeof__(*(ptr)) __pu_val; \
^
/home/mingo/tip/kernel/signal.c:2714:11: note: in expansion of macro '__put_user'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/kernel/signal.c:2714:42: note: in expansion of macro 'si_pkey'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/include/uapi/asm-generic/siginfo.h:145:37: error: 'const struct <anonymous>' has no member named '_pkey'
#define si_pkey _sifields._sigfault._pkey
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:444:14: note: in definition of macro '__put_user_nocheck'
__pu_val = (x); \
^
/home/mingo/tip/kernel/signal.c:2714:11: note: in expansion of macro '__put_user'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/kernel/signal.c:2714:28: note: in expansion of macro 'si_pkey'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/include/uapi/asm-generic/siginfo.h:145:37: error: 'struct <anonymous>' has no member named '_pkey'
#define si_pkey _sifields._sigfault._pkey
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:430:10: note: in definition of macro '__put_user_common'
switch (size) { \
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:446:3: note: in expansion of macro '__put_kernel_common'
__put_kernel_common(ptr, size); \
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:214:2: note: in expansion of macro '__put_user_nocheck'
__put_user_nocheck((x), (ptr), sizeof(*(ptr)))
^/home/mingo/tip/kernel/signal.c:2714:11: note: in expansion of macro '__put_user'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/kernel/signal.c:2714:42: note: in expansion of macro 'si_pkey'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/include/uapi/asm-generic/siginfo.h:145:37: error: 'struct <anonymous>' has no member named '_pkey'
#define si_pkey _sifields._sigfault._pkey
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:241:51: note: in definition of macro '__m'
#define __m(x) (*(struct __large_struct __user *)(x))
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:431:10: note: in expansion of macro '__put_data_asm'
case 1: __put_data_asm(user_sb, ptr); break; \
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:384:40: note: in expansion of macro '__put_user_common'
#define __put_kernel_common(ptr, size) __put_user_common(ptr, size)
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:446:3: note: in expansion of macro '__put_kernel_common'
__put_kernel_common(ptr, size); \
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:214:2: note: in expansion of macro '__put_user_nocheck'
__put_user_nocheck((x), (ptr), sizeof(*(ptr)))
^/home/mingo/tip/kernel/signal.c:2714:11: note: in expansion of macro '__put_user'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/kernel/signal.c:2714:42: note: in expansion of macro 'si_pkey'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/include/uapi/asm-generic/siginfo.h:145:37: error: 'struct <anonymous>' has no member named '_pkey'
#define si_pkey _sifields._sigfault._pkey
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:241:51: note: in definition of macro '__m'
#define __m(x) (*(struct __large_struct __user *)(x))
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:432:10: note: in expansion of macro '__put_data_asm'
case 2: __put_data_asm(user_sh, ptr); break; \
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:384:40: note: in expansion of macro '__put_user_common'
#define __put_kernel_common(ptr, size) __put_user_common(ptr, size)
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:446:3: note: in expansion of macro '__put_kernel_common'
__put_kernel_common(ptr, size); \
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:214:2: note: in expansion of macro '__put_user_nocheck'
__put_user_nocheck((x), (ptr), sizeof(*(ptr)))
^/home/mingo/tip/kernel/signal.c:2714:11: note: in expansion of macro '__put_user'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/kernel/signal.c:2714:42: note: in expansion of macro 'si_pkey'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/include/uapi/asm-generic/siginfo.h:145:37: error: 'struct <anonymous>' has no member named '_pkey'
#define si_pkey _sifields._sigfault._pkey
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:241:51: note: in definition of macro '__m'
#define __m(x) (*(struct __large_struct __user *)(x))
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:433:10: note: in expansion of macro '__put_data_asm'
case 4: __put_data_asm(user_sw, ptr); break; \
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:384:40: note: in expansion of macro '__put_user_common'
#define __put_kernel_common(ptr, size) __put_user_common(ptr, size)
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:446:3: note: in expansion of macro '__put_kernel_common'
__put_kernel_common(ptr, size); \
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:214:2: note: in expansion of macro '__put_user_nocheck'
__put_user_nocheck((x), (ptr), sizeof(*(ptr)))
^/home/mingo/tip/kernel/signal.c:2714:11: note: in expansion of macro '__put_user'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/kernel/signal.c:2714:42: note: in expansion of macro 'si_pkey'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/include/uapi/asm-generic/siginfo.h:145:37: error: 'struct <anonymous>' has no member named '_pkey'
#define si_pkey _sifields._sigfault._pkey
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:505:34: note: in definition of macro '__put_data_asm_ll32'
: "0" (0), "r" (__pu_val), "r" (ptr), \
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:434:10: note: in expansion of macro '__PUT_DW'
case 8: __PUT_DW(user_sd, ptr); break; \
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:384:40: note: in expansion of macro '__put_user_common'
#define __put_kernel_common(ptr, size) __put_user_common(ptr, size)
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:446:3: note: in expansion of macro '__put_kernel_common'
__put_kernel_common(ptr, size); \
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:214:2: note: in expansion of macro '__put_user_nocheck'
__put_user_nocheck((x), (ptr), sizeof(*(ptr)))
^/home/mingo/tip/kernel/signal.c:2714:11: note: in expansion of macro '__put_user'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/kernel/signal.c:2714:42: note: in expansion of macro 'si_pkey'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/include/uapi/asm-generic/siginfo.h:145:37: error: 'struct <anonymous>' has no member named '_pkey'
#define si_pkey _sifields._sigfault._pkey
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:430:10: note: in definition of macro '__put_user_common'
switch (size) { \
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:214:2: note: in expansion of macro '__put_user_nocheck'
__put_user_nocheck((x), (ptr), sizeof(*(ptr)))
^/home/mingo/tip/kernel/signal.c:2714:11: note: in expansion of macro '__put_user'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/kernel/signal.c:2714:42: note: in expansion of macro 'si_pkey'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/include/uapi/asm-generic/siginfo.h:145:37: error: 'struct <anonymous>' has no member named '_pkey'
#define si_pkey _sifields._sigfault._pkey
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:241:51: note: in definition of macro '__m'
#define __m(x) (*(struct __large_struct __user *)(x))
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:431:10: note: in expansion of macro '__put_data_asm'
case 1: __put_data_asm(user_sb, ptr); break; \
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:449:3: note: in expansion of macro '__put_user_common'
__put_user_common(ptr, size); \
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:214:2: note: in expansion of macro '__put_user_nocheck'
__put_user_nocheck((x), (ptr), sizeof(*(ptr)))
^/home/mingo/tip/kernel/signal.c:2714:11: note: in expansion of macro '__put_user'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/kernel/signal.c:2714:42: note: in expansion of macro 'si_pkey'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
CC security/keys/user_defined.o
/home/mingo/tip/include/uapi/asm-generic/siginfo.h:145:37: error: 'struct <anonymous>' has no member named '_pkey'
#define si_pkey _sifields._sigfault._pkey
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:241:51: note: in definition of macro '__m'
#define __m(x) (*(struct __large_struct __user *)(x))
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:432:10: note: in expansion of macro '__put_data_asm'
case 2: __put_data_asm(user_sh, ptr); break; \
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:449:3: note: in expansion of macro '__put_user_common'
__put_user_common(ptr, size); \
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:214:2: note: in expansion of macro '__put_user_nocheck'
__put_user_nocheck((x), (ptr), sizeof(*(ptr)))
^/home/mingo/tip/kernel/signal.c:2714:11: note: in expansion of macro '__put_user'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/kernel/signal.c:2714:42: note: in expansion of macro 'si_pkey'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/include/uapi/asm-generic/siginfo.h:145:37: error: 'struct <anonymous>' has no member named '_pkey'
#define si_pkey _sifields._sigfault._pkey
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:241:51: note: in definition of macro '__m'
#define __m(x) (*(struct __large_struct __user *)(x))
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:433:10: note: in expansion of macro '__put_data_asm'
case 4: __put_data_asm(user_sw, ptr); break; \
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:449:3: note: in expansion of macro '__put_user_common'
__put_user_common(ptr, size); \
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:214:2: note: in expansion of macro '__put_user_nocheck'
__put_user_nocheck((x), (ptr), sizeof(*(ptr)))
^/home/mingo/tip/kernel/signal.c:2714:11: note: in expansion of macro '__put_user'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/kernel/signal.c:2714:42: note: in expansion of macro 'si_pkey'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/include/uapi/asm-generic/siginfo.h:145:37: error: 'struct <anonymous>' has no member named '_pkey'
#define si_pkey _sifields._sigfault._pkey
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:505:34: note: in definition of macro '__put_data_asm_ll32'
: "0" (0), "r" (__pu_val), "r" (ptr), \
^
/home/mingo/tip/arch/mips/include/asm/uaccess.h:434:10: note: in expansion of macro '__PUT_DW'
case 8: __PUT_DW(user_sd, ptr); break; \
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:449:3: note: in expansion of macro '__put_user_common'
__put_user_common(ptr, size); \
^/home/mingo/tip/arch/mips/include/asm/uaccess.h:214:2: note: in expansion of macro '__put_user_nocheck'
__put_user_nocheck((x), (ptr), sizeof(*(ptr)))
^/home/mingo/tip/kernel/signal.c:2714:11: note: in expansion of macro '__put_user'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
/home/mingo/tip/kernel/signal.c:2714:42: note: in expansion of macro 'si_pkey'
err |= __put_user(from->si_pkey, &to->si_pkey);
^
CC mm/mmzone.o
CC mm/vmstat.o
UPD kernel/config_data.h
CC mm/backing-dev.o
CC security/keys/proc.o
CC fs/open.o
CC fs/read_write.o
CC mm/mm_init.o
CC fs/file_table.o
CC security/keys/sysctl.o
LD arch/mips/sgi-ip22/built-in.o
CC mm/mmu_context.o
CC fs/super.o
CC fs/char_dev.o
CC fs/stat.o
/home/mingo/tip/scripts/Makefile.build:258: recipe for target 'kernel/signal.o' failed
make[2]: *** [kernel/signal.o] Error 1
make[2]: *** Waiting for unfinished jobs....
CC mm/percpu.o
CC fs/exec.o
CC kernel/locking/percpu-rwsem.o
CC kernel/locking/rwsem.o
CC fs/pipe.o
CC mm/slab_common.o
LD arch/mips/vdso/built-in.o
CC mm/compaction.o
CC kernel/locking/rwsem-spinlock.o
CC kernel/locking/rtmutex.o
CC kernel/irq/autoprobe.o
CC fs/namei.o
CC fs/fcntl.o
CC kernel/irq/irqdomain.o
CC kernel/rcu/sync.o
CC kernel/rcu/srcu.o
CC kernel/rcu/tiny.o
CC kernel/time/posix-timers.o
CC mm/vmacache.o
CC kernel/sched/idle_task.o
CC kernel/sched/fair.o
CC kernel/sched/rt.o
CC fs/ioctl.o
CC mm/interval_tree.o
CC kernel/sched/deadline.o
CC fs/readdir.o
CC mm/workingset.o
CC mm/list_lru.o
CC mm/debug.o
CC crypto/api.o
CC crypto/cipher.o
CC mm/gup.o
CC mm/highmem.o
CC kernel/irq/proc.o
CC kernel/sched/stop_task.o
CC kernel/sched/wait.o
CC mm/memory.o
CC kernel/sched/completion.o
CC kernel/sched/idle.o
CC mm/mincore.o
CC fs/select.o
CC kernel/sched/debug.o
CC kernel/time/posix-cpu-timers.o
CC fs/dcache.o
CC fs/inode.o
CC kernel/time/timekeeping.o
CC fs/attr.o
CC mm/mmap.o
CC mm/mprotect.o
CC kernel/time/ntp.o
CC mm/mlock.o
CC crypto/compress.o
CC fs/file.o
CC fs/bad_inode.o
CC mm/mremap.o
CC kernel/time/clocksource.o
CC fs/filesystems.o
CC mm/msync.o
CC mm/rmap.o
LD kernel/power/built-in.o
CC block/bio.o
CC kernel/time/jiffies.o
CC mm/vmalloc.o
CC kernel/time/timer_list.o
CC crypto/memneq.o
CC fs/namespace.o
CC mm/pagewalk.o
CC block/blk-core.o
CC crypto/crypto_wq.o
CC block/elevator.o
CC fs/seq_file.o
LD sound/built-in.o
CC kernel/time/timeconv.o
CC kernel/time/timecounter.o
CC mm/pgtable-generic.o
CC crypto/algapi.o
CC crypto/scatterwalk.o
CC block/blk-tag.o
CC kernel/time/posix-clock.o
CC fs/xattr.o
LD init/mounts.o
CC kernel/time/clockevents.o
LD ipc/built-in.o
LD init/built-in.o
CC kernel/time/alarmtimer.o
CC fs/libfs.o
CC kernel/time/tick-common.o
CC mm/process_vm_access.o
CC crypto/proc.o
CC mm/bootmem.o
CC mm/init-mm.o
CC block/blk-sysfs.o
CC fs/fs-writeback.o
CC kernel/time/sched_clock.o
CC block/blk-flush.o
CC fs/pnode.o
LD firmware/built-in.o
CC block/blk-settings.o
CC crypto/aead.o
CC block/blk-ioc.o
CC block/blk-map.o
CC fs/splice.o
CC kernel/time/tick-oneshot.o
CC mm/fadvise.o
CC mm/madvise.o
CC block/blk-exec.o
CC fs/sync.o
LD kernel/bpf/built-in.o
CC kernel/time/tick-sched.o
CC crypto/ablkcipher.o
CC crypto/blkcipher.o
CC fs/utimes.o
CC crypto/skcipher.o
CC fs/stack.o
CC fs/fs_struct.o
LD arch/mips/power/built-in.o
CC block/blk-merge.o
LD kernel/locking/built-in.o
CC mm/page_io.o
CC fs/statfs.o
LD security/keys/built-in.o
CC mm/memblock.o
LD security/built-in.o
CC fs/nsfs.o
CC fs/fs_pin.o
CC mm/swap_state.o
CC crypto/chainiv.o
CC fs/buffer.o
LD arch/mips/kernel/built-in.o
CC mm/swapfile.o
CC crypto/eseqiv.o
CC fs/block_dev.o
CC mm/migrate.o
CC crypto/ahash.o
CC crypto/pcompress.o
CC mm/slab.o
CC mm/dmapool.o
CC crypto/akcipher.o
LD arch/mips/mm/built-in.o
CC crypto/shash.o
CC fs/direct-io.o
LD kernel/irq/built-in.o
CC block/blk-softirq.o
LD arch/mips/built-in.o
CC crypto/algboss.o
CC block/blk-timeout.o
CC crypto/testmgr.o
CC block/blk-lib.o
CC crypto/hmac.o
CC block/blk-mq.o
CC crypto/crypto_null.o
CC crypto/md5.o
CC block/blk-mq-sysfs.o
LD kernel/rcu/built-in.o
CC block/blk-mq-tag.o
CC block/blk-mq-cpu.o
CC fs/mpage.o
CC block/blk-mq-cpumap.o
LD drivers/auxdisplay/built-in.o
CC block/ioctl.o
LD drivers/amba/built-in.o
CC block/scsi_ioctl.o
CC block/partition-generic.o
CC fs/proc_namespace.o
LD drivers/block/built-in.o
CC crypto/aes_generic.o
CC block/badblocks.o
CC block/genhd.o
CC block/ioprio.o
CC block/bsg-lib.o
CC block/bsg.o
LD drivers/bus/built-in.o
CC block/noop-iosched.o
CC crypto/crc32c_generic.o
LD drivers/block/aoe/built-in.o
CC block/deadline-iosched.o
CC block/partitions/check.o
LD arch/mips/fw/arc/built-in.o
CC block/partitions/msdos.o
CC net/socket.o
CC drivers/cdrom/cdrom.o
CC arch/mips/fw/arc/arc_con.o
CC block/cfq-iosched.o
CC crypto/rng.o
LD crypto/crypto.o
LD fs/exofs/built-in.o
LD fs/autofs4/built-in.o
LD net/802/built-in.o
CC drivers/char/mem.o
LD fs/exportfs/built-in.o
CC fs/devpts/inode.o
CC drivers/char/random.o
CC drivers/char/misc.o
LD net/dns_resolver/built-in.o
LD fs/efs/built-in.o
LD drivers/char/agp/built-in.o
LD fs/coda/built-in.o
CC drivers/base/component.o
CC block/partitions/sgi.o
CC arch/mips/fw/arc/cmdline.o
CC block/partitions/efi.o
LD drivers/clk/bcm/built-in.o
CC drivers/base/core.o
CC drivers/clocksource/i8253.o
CC net/ethernet/eth.o
LD drivers/clk/built-in.o
LD fs/ext2/built-in.o
LD drivers/connector/built-in.o
CC arch/mips/fw/arc/env.o
LD fs/cifs/built-in.o
CC net/key/af_key.o
CC arch/mips/fw/arc/file.o
LD drivers/crypto/built-in.o
LD fs/fuse/built-in.o
LD drivers/firewire/built-in.o
CC drivers/base/bus.o
CC arch/mips/fw/arc/identify.o
CC lib/lockref.o
CC net/netlink/af_netlink.o
LD arch/mips/fw/lib/built-in.o
CC arch/mips/fw/lib/cmdline.o
LD fs/fat/built-in.o
CC net/packet/af_packet.o
CC net/core/request_sock.o
CC net/core/sock.o
CC arch/mips/fw/arc/init.o
CC net/core/skbuff.o
LD kernel/printk/built-in.o
CC net/core/datagram.o
CC net/core/stream.o
CC net/core/scm.o
LD fs/isofs/built-in.o
CC fs/jbd2/commit.o
CC fs/jbd2/transaction.o
CC fs/kernfs/mount.o
CC net/netfilter/nf_log.o
CC net/core/gen_stats.o
CC net/netfilter/core.o
LD net/phonet/built-in.o
CC fs/kernfs/inode.o
CC fs/jbd2/recovery.o
CC fs/jbd2/revoke.o
CC fs/jbd2/journal.o
LD drivers/firmware/broadcom/built-in.o
CC fs/jbd2/checkpoint.o
LD drivers/gpio/built-in.o
CC fs/kernfs/dir.o
CC arch/mips/lib/iomap.o
LD fs/nfs_common/built-in.o
LD fs/nls/built-in.o
LD fs/minix/built-in.o
CC arch/mips/fw/arc/misc.o
CC fs/kernfs/file.o
CC fs/ext4/balloc.o
LD drivers/firmware/built-in.o
CC fs/kernfs/symlink.o
CC net/core/gen_estimator.o
CC drivers/base/dd.o
AR arch/mips/fw/lib/lib.a
CC net/core/secure_seq.o
CC net/core/net_namespace.o
LD fs/lockd/built-in.o
CC net/core/flow_dissector.o
CC arch/mips/lib/dump_tlb.o
CC net/netfilter/nf_queue.o
CC net/core/dev.o
CC net/core/sysctl_net_core.o
CC net/netfilter/nf_sockopt.o
CC net/core/dev_addr_lists.o
CC net/core/dst.o
CC net/core/neighbour.o
CC arch/mips/fw/arc/promlib.o
CC net/core/ethtool.o
LD net/rfkill/built-in.o
CC net/core/rtnetlink.o
CC net/core/netevent.o
LD fs/nfsd/built-in.o
CC net/core/utils.o
LD crypto/cryptomgr.o
CC net/core/link_watch.o
CC net/core/sock_diag.o
CC net/core/filter.o
CC net/core/tso.o
CC net/core/dev_ioctl.o
LD fs/nfs/built-in.o
CC lib/div64.o
CC lib/bcd.o
CC drivers/base/syscore.o
CC fs/ext4/dir.o
CC net/ipv6/af_inet6.o
CC net/ipv6/anycast.o
CC fs/ext4/bitmap.o
CC net/sched/sch_generic.o
CC net/ipv6/ip6_output.o
LD fs/omfs/built-in.o
CC arch/mips/fw/arc/salone.o
LD drivers/clocksource/built-in.o
CC net/ipv4/inetpeer.o
CC net/ipv4/route.o
LD fs/devpts/devpts.o
CC arch/mips/lib/ashrdi3.o
CC arch/mips/lib/ashldi3.o
CC lib/sort.o
/home/mingo/tip/mm/page_alloc.c: In function 'free_area_init_nodes':
/home/mingo/tip/mm/page_alloc.c:5712:34: warning: array subscript is below array bounds [-Warray-bounds]
arch_zone_highest_possible_pfn[i-1];
^
CC net/ipv6/ip6_input.o
LD kernel/sched/built-in.o
LD fs/devpts/built-in.o
CC net/sched/sch_mq.o
CC fs/notify/fsnotify.o
LD virt/lib/built-in.o
CC fs/ext4/file.o
CC drivers/hid/hid-core.o
CC fs/ext4/fsync.o
CC fs/ext4/ialloc.o
LD virt/built-in.o
CC lib/parser.o
CC arch/mips/fw/arc/time.o
LD drivers/gpu/vga/built-in.o
CC net/sched/sch_api.o
LD drivers/gpu/drm/bridge/built-in.o
LD drivers/hsi/clients/built-in.o
CC net/ipv4/protocol.o
CC arch/mips/math-emu/cp1emu.o
LD kernel/time/built-in.o
CC fs/notify/notification.o
CC drivers/base/driver.o
LD drivers/gpu/drm/i2c/built-in.o
CC drivers/hid/hid-input.o
CC drivers/base/class.o
CC arch/mips/lib/bswapsi.o
CC arch/mips/lib/bswapdi.o
CC arch/mips/lib/cmpdi2.o
LD block/partitions/built-in.o
/home/mingo/tip/Makefile:950: recipe for target 'kernel' failed
make[1]: *** [kernel] Error 2
make[1]: *** Waiting for unfinished jobs....
CC arch/mips/math-emu/ieee754dp.o
LD drivers/hsi/controllers/built-in.o
CC drivers/base/platform.o
CC drivers/hid/hidraw.o
CC arch/mips/lib/lshrdi3.o
CC arch/mips/lib/ucmpdi2.o
LD drivers/gpu/drm/tilcdc/built-in.o
LD drivers/gpu/drm/panel/built-in.o
LD drivers/hsi/built-in.o
AS arch/mips/lib/csum_partial.o
CC fs/proc/task_mmu.o
LD drivers/hwtracing/intel_th/built-in.o--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>