Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1283499 > unrolled thread
| Started by | Dave Hansen <dave@sr71.net> |
|---|---|
| First post | 2015-12-04 02:20 +0100 |
| Last post | 2015-12-05 00:40 +0100 |
| Articles | 20 on this page of 55 — 4 participants |
Back to article view | Back to linux.kernel
[PATCH 00/34] x86: Memory Protection Keys (v5) Dave Hansen <dave@sr71.net> - 2015-12-04 02:20 +0100
[PATCH 09/34] x86, pkeys: store protection in high VMA flags Dave Hansen <dave@sr71.net> - 2015-12-04 02:20 +0100
Re: [PATCH 09/34] x86, pkeys: store protection in high VMA flags Thomas Gleixner <tglx@linutronix.de> - 2015-12-08 15:20 +0100
[PATCH 32/34] x86, pkeys: add pkey set/get syscalls Dave Hansen <dave@sr71.net> - 2015-12-04 02:20 +0100
[PATCH 29/34] x86: separate out LDT init from context init Dave Hansen <dave@sr71.net> - 2015-12-04 02:20 +0100
[PATCH 31/34] x86, pkeys: allocation/free syscalls Dave Hansen <dave@sr71.net> - 2015-12-04 02:20 +0100
[PATCH 12/34] signals, pkeys: notify userspace about protection key faults Dave Hansen <dave@sr71.net> - 2015-12-04 02:20 +0100
[PATCH 20/34] x86, pkeys: differentiate instruction fetches Dave Hansen <dave@sr71.net> - 2015-12-04 02:20 +0100
Re: [PATCH 20/34] x86, pkeys: differentiate instruction fetches Thomas Gleixner <tglx@linutronix.de> - 2015-12-08 19:20 +0100
[PATCH 19/34] x86, pkeys: optimize fault handling in access_error() Dave Hansen <dave@sr71.net> - 2015-12-04 02:20 +0100
Re: [PATCH 19/34] x86, pkeys: optimize fault handling in access_error() Thomas Gleixner <tglx@linutronix.de> - 2015-12-08 19:20 +0100
[PATCH 18/34] mm: add gup flag to indicate "foreign" mm access Dave Hansen <dave@sr71.net> - 2015-12-04 02:20 +0100
[PATCH 27/34] x86, pkeys: make mprotect_key() mask off additional vm_flags Dave Hansen <dave@sr71.net> - 2015-12-04 02:20 +0100
Re: [PATCH 27/34] x86, pkeys: make mprotect_key() mask off additional vm_flags Thomas Gleixner <tglx@linutronix.de> - 2015-12-08 19:50 +0100
[PATCH 23/34] x86, pkeys: add Kconfig prompt to existing config option Dave Hansen <dave@sr71.net> - 2015-12-04 02:20 +0100
Re: [PATCH 23/34] x86, pkeys: add Kconfig prompt to existing config option Thomas Gleixner <tglx@linutronix.de> - 2015-12-08 19:30 +0100
[PATCH 25/34] x86, pkeys: add arch_validate_pkey() Dave Hansen <dave@sr71.net> - 2015-12-04 02:20 +0100
Re: [PATCH 25/34] x86, pkeys: add arch_validate_pkey() Thomas Gleixner <tglx@linutronix.de> - 2015-12-08 19:50 +0100
[PATCH 33/34] x86, pkeys: actually enable Memory Protection Keys in CPU Dave Hansen <dave@sr71.net> - 2015-12-04 02:20 +0100
[PATCH 26/34] mm: implement new mprotect_key() system call Dave Hansen <dave@sr71.net> - 2015-12-04 02:20 +0100
Re: [PATCH 26/34] mm: implement new mprotect_key() system call "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> - 2015-12-05 08:00 +0100
Re: [PATCH 26/34] mm: implement new mprotect_key() system call Dave Hansen <dave@sr71.net> - 2015-12-07 17:50 +0100
Re: [PATCH 26/34] mm: implement new mprotect_key() system call "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> - 2015-12-09 12:10 +0100
Re: [PATCH 26/34] mm: implement new mprotect_key() system call Dave Hansen <dave@sr71.net> - 2015-12-09 16:50 +0100
Re: [PATCH 26/34] mm: implement new mprotect_key() system call "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> - 2015-12-09 17:50 +0100
Re: [PATCH 26/34] mm: implement new mprotect_key() system call Dave Hansen <dave@sr71.net> - 2015-12-09 18:10 +0100
Re: [PATCH 26/34] mm: implement new mprotect_key() system call "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> - 2015-12-11 21:20 +0100
[PATCH 24/34] mm, multi-arch: pass a protection key in to calc_vm_flag_bits() Dave Hansen <dave@sr71.net> - 2015-12-04 02:20 +0100
[PATCH 22/34] x86, pkeys: dump PTE pkey in /proc/pid/smaps Dave Hansen <dave@sr71.net> - 2015-12-04 02:20 +0100
[PATCH 14/34] x86, pkeys: add functions to fetch PKRU Dave Hansen <dave@sr71.net> - 2015-12-04 02:30 +0100
Re: [PATCH 14/34] x86, pkeys: add functions to fetch PKRU Thomas Gleixner <tglx@linutronix.de> - 2015-12-08 16:20 +0100
[PATCH 11/34] x86, pkeys: pass VMA down in to fault signal generation code Dave Hansen <dave@sr71.net> - 2015-12-04 02:30 +0100
[PATCH 02/34] x86, fpu: add placeholder for Processor Trace XSAVE state Dave Hansen <dave@sr71.net> - 2015-12-04 02:30 +0100
[PATCH 16/34] x86, mm: simplify get_user_pages() PTE bit handling Dave Hansen <dave@sr71.net> - 2015-12-04 02:30 +0100
Re: [PATCH 16/34] x86, mm: simplify get_user_pages() PTE bit handling Thomas Gleixner <tglx@linutronix.de> - 2015-12-08 19:10 +0100
Re: [PATCH 16/34] x86, mm: simplify get_user_pages() PTE bit handling Dave Hansen <dave@sr71.net> - 2015-12-08 19:40 +0100
[PATCH 10/34] x86, pkeys: arch-specific protection bits Dave Hansen <dave@sr71.net> - 2015-12-04 02:30 +0100
Re: [PATCH 10/34] x86, pkeys: arch-specific protection bitsy Thomas Gleixner <tglx@linutronix.de> - 2015-12-08 16:20 +0100
Re: [PATCH 10/34] x86, pkeys: arch-specific protection bitsy Dave Hansen <dave@sr71.net> - 2015-12-08 17:40 +0100
Re: [PATCH 10/34] x86, pkeys: arch-specific protection bitsy Thomas Gleixner <tglx@linutronix.de> - 2015-12-08 18:30 +0100
Re: [PATCH 10/34] x86, pkeys: arch-specific protection bitsy Dave Hansen <dave@sr71.net> - 2015-12-08 19:10 +0100
Re: [PATCH 10/34] x86, pkeys: arch-specific protection bitsy Thomas Gleixner <tglx@linutronix.de> - 2015-12-08 19:40 +0100
Re: [PATCH 10/34] x86, pkeys: arch-specific protection bitsy Thomas Gleixner <tglx@linutronix.de> - 2015-12-08 19:40 +0100
[PATCH 06/34] x86, pkeys: add PKRU xsave fields and data structure(s) Dave Hansen <dave@sr71.net> - 2015-12-04 02:30 +0100
[PATCH 05/34] x86, pkeys: define new CR4 bit Dave Hansen <dave@sr71.net> - 2015-12-04 02:30 +0100
[PATCH 01/34] mm, gup: introduce concept of "foreign" get_user_pages() Dave Hansen <dave@sr71.net> - 2015-12-04 02:30 +0100
[PATCH 17/34] x86, pkeys: check VMAs and PTEs for protection keys Dave Hansen <dave@sr71.net> - 2015-12-04 02:30 +0100
Re: [PATCH 17/34] x86, pkeys: check VMAs and PTEs for protection keys Thomas Gleixner <tglx@linutronix.de> - 2015-12-08 19:20 +0100
[PATCH 13/34] x86, pkeys: fill in pkey field in siginfo Dave Hansen <dave@sr71.net> - 2015-12-04 02:30 +0100
[PATCH 08/34] x86, pkeys: new page fault error code bit: PF_PK Dave Hansen <dave@sr71.net> - 2015-12-04 02:30 +0100
[PATCH 07/34] x86, pkeys: PTE bits for storing protection key Dave Hansen <dave@sr71.net> - 2015-12-04 02:30 +0100
[PATCH 04/34] x86, pkeys: cpuid bit definition Dave Hansen <dave@sr71.net> - 2015-12-04 02:30 +0100
Re: [PATCH 00/34] x86: Memory Protection Keys (v5) Dave Hansen <dave@sr71.net> - 2015-12-05 00:40 +0100
Re: [PATCH 00/34] x86: Memory Protection Keys (v5) Andy Lutomirski <luto@amacapital.net> - 2015-12-11 21:20 +0100
Re: [PATCH 00/34] x86: Memory Protection Keys (v5) Andy Lutomirski <luto@amacapital.net> - 2015-12-05 00:40 +0100
Page 1 of 3 [1] 2 3 Next page →
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-12-04 02:20 +0100 |
| Subject | [PATCH 00/34] x86: Memory Protection Keys (v5) |
| Message-ID | <qBNct-4nR-3@gated-at.bofh.it> |
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. It provides a mechanism for enforcing
page-based protections, but without requiring modification of the
page tables when an application changes protection domains. See
the Documentation/ patch for more details.
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. 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 (with the new syscall):
git://git.kernel.org/pub/scm/linux/kernel/git/daveh/x86-pkeys.git pkeys-v014
=== diffstat ===
Dave Hansen (34):
mm, gup: introduce concept of "foreign" get_user_pages()
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: add gup flag to indicate "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 PTE pkey in /proc/pid/smaps
x86, pkeys: add Kconfig prompt to existing config option
mm, multi-arch: pass a protection key in to calc_vm_flag_bits()
x86, pkeys: add arch_validate_pkey()
mm: implement new mprotect_key() system call
x86, pkeys: make mprotect_key() mask off additional vm_flags
x86: wire up mprotect_key() system call
x86: separate out LDT init from context init
x86, fpu: allow setting of XSAVE state
x86, pkeys: allocation/free syscalls
x86, pkeys: add pkey set/get syscalls
x86, pkeys: actually enable Memory Protection Keys in CPU
x86, pkeys: Documentation
Documentation/kernel-parameters.txt | 3 +
Documentation/x86/protection-keys.txt | 53 +++++
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 | 3 +-
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/entry/syscalls/syscall_32.tbl | 5 +
arch/x86/entry/syscalls/syscall_64.tbl | 5 +
arch/x86/include/asm/cpufeature.h | 56 +++--
arch/x86/include/asm/disabled-features.h | 13 ++
arch/x86/include/asm/fpu/internal.h | 2 +
arch/x86/include/asm/fpu/types.h | 12 +
arch/x86/include/asm/fpu/xstate.h | 4 +-
arch/x86/include/asm/mmu.h | 7 +
arch/x86/include/asm/mmu_context.h | 110 ++++++++-
arch/x86/include/asm/pgtable.h | 38 +++
arch/x86/include/asm/pgtable_types.h | 34 ++-
arch/x86/include/asm/pkeys.h | 67 ++++++
arch/x86/include/asm/required-features.h | 5 +
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 | 241 +++++++++++++++++++-
arch/x86/kernel/ldt.c | 4 +-
arch/x86/kernel/process_64.c | 2 +
arch/x86/kernel/setup.c | 9 +
arch/x86/mm/fault.c | 158 +++++++++++--
arch/x86/mm/gup.c | 51 +++--
arch/x86/mm/mpx.c | 4 +-
drivers/char/agp/frontend.c | 2 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 4 +-
drivers/gpu/drm/i915/i915_gem_userptr.c | 2 +-
drivers/gpu/drm/radeon/radeon_ttm.c | 4 +-
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 | 8 +-
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/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 | 5 +
include/asm-generic/mm_hooks.h | 12 +
include/linux/mm.h | 55 ++++-
include/linux/mman.h | 6 +-
include/linux/pkeys.h | 59 +++++
include/uapi/asm-generic/mman-common.h | 5 +
include/uapi/asm-generic/siginfo.h | 17 +-
kernel/events/uprobes.c | 4 +-
kernel/signal.c | 4 +
mm/Kconfig | 13 ++
mm/frame_vector.c | 2 +-
mm/gup.c | 93 ++++++--
mm/ksm.c | 10 +-
mm/memory.c | 8 +-
mm/mempolicy.c | 6 +-
mm/mmap.c | 2 +-
mm/mprotect.c | 136 ++++++++++-
mm/nommu.c | 35 ++-
mm/process_vm_access.c | 6 +-
mm/util.c | 4 +-
net/ceph/pagevec.c | 2 +-
security/tomoyo/domain.c | 9 +-
virt/kvm/async_pf.c | 2 +-
virt/kvm/kvm_main.c | 13 +-
80 files changed, 1470 insertions(+), 223 deletions(-)
Cc: linux-api@vger.kernel.org
Cc: linux-arch@vger.kernel.org
Cc: aarcange@redhat.com
Cc: akpm@linux-foundation.org
Cc: jack@suse.cz
Cc: kirill.shutemov@linux.intel.com
Cc: linux-api@vger.kernel.org
Cc: linux-arch@vger.kernel.org
Cc: n-horiguchi@ah.jp.nec.com
Cc: x86@kernel.org
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-12-04 02:20 +0100 |
| Subject | [PATCH 09/34] x86, pkeys: store protection in high VMA flags |
| Message-ID | <qBNcu-4nR-21@gated-at.bofh.it> |
| In reply to | #1283499 |
From: Dave Hansen <dave.hansen@linux.intel.com> 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". Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> --- b/arch/x86/Kconfig | 1 + b/include/linux/mm.h | 7 +++++++ b/mm/Kconfig | 3 +++ 3 files changed, 11 insertions(+) diff -puN arch/x86/Kconfig~pkeys-07-eat-high-vma-flags arch/x86/Kconfig --- a/arch/x86/Kconfig~pkeys-07-eat-high-vma-flags 2015-12-03 16:21:22.042508764 -0800 +++ b/arch/x86/Kconfig 2015-12-03 16:21:22.050509127 -0800 @@ -152,6 +152,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 diff -puN include/linux/mm.h~pkeys-07-eat-high-vma-flags include/linux/mm.h --- a/include/linux/mm.h~pkeys-07-eat-high-vma-flags 2015-12-03 16:21:22.044508855 -0800 +++ b/include/linux/mm.h 2015-12-03 16:21:22.051509173 -0800 @@ -158,6 +158,13 @@ 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_0 0x100000000UL /* bit only usable on 64-bit architectures */ +#define VM_HIGH_ARCH_1 0x200000000UL /* bit only usable on 64-bit architectures */ +#define VM_HIGH_ARCH_2 0x400000000UL /* bit only usable on 64-bit architectures */ +#define VM_HIGH_ARCH_3 0x800000000UL /* bit only usable on 64-bit architectures */ +#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) diff -puN mm/Kconfig~pkeys-07-eat-high-vma-flags mm/Kconfig --- a/mm/Kconfig~pkeys-07-eat-high-vma-flags 2015-12-03 16:21:22.046508946 -0800 +++ b/mm/Kconfig 2015-12-03 16:21:22.051509173 -0800 @@ -668,3 +668,6 @@ config ZONE_DEVICE config FRAME_VECTOR bool + +config ARCH_USES_HIGH_VMA_FLAGS + bool _ -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2015-12-08 15:20 +0100 |
| Subject | Re: [PATCH 09/34] x86, pkeys: store protection in high VMA flags |
| Message-ID | <qDrhx-3r6-19@gated-at.bofh.it> |
| In reply to | #1283500 |
On Thu, 3 Dec 2015, Dave Hansen wrote: > 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". > > Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-12-04 02:20 +0100 |
| Subject | [PATCH 32/34] x86, pkeys: add pkey set/get syscalls |
| Message-ID | <qBNcu-4nR-27@gated-at.bofh.it> |
| In reply to | #1283499 |
From: Dave Hansen <dave.hansen@linux.intel.com>
This establishes two more system calls for protection key management:
unsigned long pkey_get(int pkey);
int pkey_set(int pkey, unsigned long access_rights);
The return value from pkey_get() and the 'access_rights' passed
to pkey_set() are the same format: a bitmask containing
PKEY_DENY_WRITE and/or PKEY_DENY_ACCESS, or nothing set at all.
These replace userspace's direct use of rdpkru/wrpkru.
With current hardware, the kernel can not enforce that it has
control over a given key. But, this at least allows the kernel
to indicate to userspace that userspace does not control a given
protection key.
The kernel does _not_ enforce that this interface must be used for
changes to PKRU, even for keys it has not "allocated".
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Cc: linux-api@vger.kernel.org
---
b/arch/x86/entry/syscalls/syscall_32.tbl | 2 +
b/arch/x86/entry/syscalls/syscall_64.tbl | 2 +
b/arch/x86/include/asm/mmu_context.h | 2 +
b/arch/x86/include/asm/pkeys.h | 2 -
b/arch/x86/kernel/fpu/xstate.c | 55 +++++++++++++++++++++++++++++--
b/include/linux/pkeys.h | 8 ++++
b/mm/mprotect.c | 34 +++++++++++++++++++
7 files changed, 102 insertions(+), 3 deletions(-)
diff -puN arch/x86/entry/syscalls/syscall_32.tbl~pkey-syscalls-set-get arch/x86/entry/syscalls/syscall_32.tbl
--- a/arch/x86/entry/syscalls/syscall_32.tbl~pkey-syscalls-set-get 2015-12-03 16:21:33.139012003 -0800
+++ b/arch/x86/entry/syscalls/syscall_32.tbl 2015-12-03 16:21:33.151012548 -0800
@@ -386,3 +386,5 @@
377 i386 pkey_mprotect sys_pkey_mprotect
378 i386 pkey_alloc sys_pkey_alloc
379 i386 pkey_free sys_pkey_free
+380 i386 pkey_get sys_pkey_get
+381 i386 pkey_set sys_pkey_set
diff -puN arch/x86/entry/syscalls/syscall_64.tbl~pkey-syscalls-set-get arch/x86/entry/syscalls/syscall_64.tbl
--- a/arch/x86/entry/syscalls/syscall_64.tbl~pkey-syscalls-set-get 2015-12-03 16:21:33.141012094 -0800
+++ b/arch/x86/entry/syscalls/syscall_64.tbl 2015-12-03 16:21:33.152012593 -0800
@@ -335,6 +335,8 @@
326 common pkey_mprotect sys_pkey_mprotect
327 common pkey_alloc sys_pkey_alloc
328 common pkey_free sys_pkey_free
+329 common pkey_get sys_pkey_get
+330 common pkey_set sys_pkey_set
#
# x32-specific system call numbers start at 512 to avoid cache impact
diff -puN arch/x86/include/asm/mmu_context.h~pkey-syscalls-set-get arch/x86/include/asm/mmu_context.h
--- a/arch/x86/include/asm/mmu_context.h~pkey-syscalls-set-get 2015-12-03 16:21:33.142012139 -0800
+++ b/arch/x86/include/asm/mmu_context.h 2015-12-03 16:21:33.152012593 -0800
@@ -340,5 +340,7 @@ static inline bool arch_pte_access_permi
extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
unsigned long init_val);
+extern unsigned long arch_get_user_pkey_access(struct task_struct *tsk,
+ int pkey);
#endif /* _ASM_X86_MMU_CONTEXT_H */
diff -puN arch/x86/include/asm/pkeys.h~pkey-syscalls-set-get arch/x86/include/asm/pkeys.h
--- a/arch/x86/include/asm/pkeys.h~pkey-syscalls-set-get 2015-12-03 16:21:33.144012230 -0800
+++ b/arch/x86/include/asm/pkeys.h 2015-12-03 16:21:33.152012593 -0800
@@ -16,7 +16,7 @@
} while (0)
static inline
-bool mm_pkey_is_allocated(struct mm_struct *mm, unsigned long pkey)
+bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
{
if (!arch_validate_pkey(pkey))
return true;
diff -puN arch/x86/kernel/fpu/xstate.c~pkey-syscalls-set-get arch/x86/kernel/fpu/xstate.c
--- a/arch/x86/kernel/fpu/xstate.c~pkey-syscalls-set-get 2015-12-03 16:21:33.145012275 -0800
+++ b/arch/x86/kernel/fpu/xstate.c 2015-12-03 16:21:33.153012638 -0800
@@ -687,7 +687,7 @@ void fpu__resume_cpu(void)
*
* Note: does not work for compacted buffers.
*/
-void *__raw_xsave_addr(struct xregs_state *xsave, int xstate_feature_mask)
+static void *__raw_xsave_addr(struct xregs_state *xsave, int xstate_feature_mask)
{
int feature_nr = fls64(xstate_feature_mask) - 1;
@@ -862,6 +862,7 @@ out:
#define NR_VALID_PKRU_BITS (CONFIG_NR_PROTECTION_KEYS * 2)
#define PKRU_VALID_MASK (NR_VALID_PKRU_BITS - 1)
+#define PKRU_INIT_STATE 0
/*
* This will go out and modify the XSAVE buffer so that PKRU is
@@ -880,6 +881,9 @@ int arch_set_user_pkey_access(struct tas
int pkey_shift = (pkey * PKRU_BITS_PER_PKEY);
u32 new_pkru_bits = 0;
+ /* Only support manipulating current task for now */
+ if (tsk != current)
+ return -EINVAL;
if (!arch_validate_pkey(pkey))
return -EINVAL;
/*
@@ -907,7 +911,7 @@ int arch_set_user_pkey_access(struct tas
* state.
*/
if (!old_pkru_state)
- new_pkru_state.pkru = 0;
+ new_pkru_state.pkru = PKRU_INIT_STATE;
else
new_pkru_state.pkru = old_pkru_state->pkru;
@@ -932,4 +936,51 @@ int arch_set_user_pkey_access(struct tas
return 0;
}
+
+/*
+ * Figures out what the rights are currently for 'pkey'.
+ * Converts from PKRU's format to the user-visible PKEY_DISABLE_*
+ * format.
+ */
+unsigned long arch_get_user_pkey_access(struct task_struct *tsk, int pkey)
+{
+ struct fpu *fpu = ¤t->thread.fpu;
+ u32 pkru_reg;
+ int ret = 0;
+
+ /* Only support manipulating current task for now */
+ if (tsk != current)
+ return -1;
+ if (!boot_cpu_has(X86_FEATURE_OSPKE))
+ return -1;
+ /*
+ * The contents of PKRU itself are invalid. Consult the
+ * task's XSAVE buffer for PKRU contents. This is much
+ * more expensive than reading PKRU directly, but should
+ * be rare or impossible with eagerfpu mode.
+ */
+ if (!fpu->fpregs_active) {
+ struct xregs_state *xsave = &fpu->state.xsave;
+ struct pkru_state *pkru_state =
+ get_xsave_addr(xsave, XFEATURE_MASK_PKRU);
+ /*
+ * PKRU is in its init state and not present in
+ * the buffer in a saved form.
+ */
+ if (!pkru_state)
+ return PKRU_INIT_STATE;
+
+ return pkru_state->pkru;
+ }
+ /*
+ * Consult the user register directly.
+ */
+ pkru_reg = read_pkru();
+ if (!__pkru_allows_read(pkru_reg, pkey))
+ ret |= PKEY_DISABLE_ACCESS;
+ if (!__pkru_allows_write(pkru_reg, pkey))
+ ret |= PKEY_DISABLE_WRITE;
+
+ return ret;
+}
#endif /* CONFIG_ARCH_HAS_PKEYS */
diff -puN include/linux/pkeys.h~pkey-syscalls-set-get include/linux/pkeys.h
--- a/include/linux/pkeys.h~pkey-syscalls-set-get 2015-12-03 16:21:33.147012366 -0800
+++ b/include/linux/pkeys.h 2015-12-03 16:21:33.153012638 -0800
@@ -43,6 +43,14 @@ static inline int mm_pkey_free(struct mm
static inline int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
unsigned long init_val)
{
+ return -EINVAL;
+}
+
+static inline
+unsigned long arch_get_user_pkey_access(struct task_struct *tsk, int pkey)
+{
+ if (pkey)
+ return -1;
return 0;
}
diff -puN mm/mprotect.c~pkey-syscalls-set-get mm/mprotect.c
--- a/mm/mprotect.c~pkey-syscalls-set-get 2015-12-03 16:21:33.148012412 -0800
+++ b/mm/mprotect.c 2015-12-03 16:21:33.154012684 -0800
@@ -531,3 +531,37 @@ SYSCALL_DEFINE1(pkey_free, int, pkey)
*/
return ret;
}
+
+SYSCALL_DEFINE1(pkey_get, int, pkey)
+{
+ unsigned long ret = 0;
+
+ down_write(¤t->mm->mmap_sem);
+ if (!mm_pkey_is_allocated(current->mm, pkey))
+ ret = -EBADF;
+ up_write(¤t->mm->mmap_sem);
+
+ if (ret)
+ return ret;
+
+ ret = arch_get_user_pkey_access(current, pkey);
+
+ return ret;
+}
+
+SYSCALL_DEFINE2(pkey_set, int, pkey, unsigned long, access_rights)
+{
+ unsigned long ret = 0;
+
+ down_write(¤t->mm->mmap_sem);
+ if (!mm_pkey_is_allocated(current->mm, pkey))
+ ret = -EBADF;
+ up_write(¤t->mm->mmap_sem);
+
+ if (ret)
+ return ret;
+
+ ret = arch_set_user_pkey_access(current, pkey, access_rights);
+
+ return ret;
+}
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-12-04 02:20 +0100 |
| Subject | [PATCH 29/34] x86: separate out LDT init from context init |
| Message-ID | <qBNct-4nR-19@gated-at.bofh.it> |
| In reply to | #1283499 |
From: Dave Hansen <dave.hansen@linux.intel.com>
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.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
---
b/arch/x86/include/asm/mmu_context.h | 21 ++++++++++++++++-----
b/arch/x86/kernel/ldt.c | 4 ++--
2 files changed, 18 insertions(+), 7 deletions(-)
diff -puN arch/x86/include/asm/mmu_context.h~init-ldt-extricate arch/x86/include/asm/mmu_context.h
--- a/arch/x86/include/asm/mmu_context.h~init-ldt-extricate 2015-12-03 16:21:31.585941570 -0800
+++ b/arch/x86/include/asm/mmu_context.h 2015-12-03 16:21:31.590941797 -0800
@@ -53,15 +53,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)
@@ -105,6 +105,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)
{
diff -puN arch/x86/kernel/ldt.c~init-ldt-extricate arch/x86/kernel/ldt.c
--- a/arch/x86/kernel/ldt.c~init-ldt-extricate 2015-12-03 16:21:31.587941660 -0800
+++ b/arch/x86/kernel/ldt.c 2015-12-03 16:21:31.590941797 -0800
@@ -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;
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-12-04 02:20 +0100 |
| Subject | [PATCH 31/34] x86, pkeys: allocation/free syscalls |
| Message-ID | <qBNcu-4nR-29@gated-at.bofh.it> |
| In reply to | #1283499 |
From: Dave Hansen <dave.hansen@linux.intel.com>
This patch adds two new system calls:
int pkey_alloc(unsigned long flags, unsigned long init_access_rights)
int pkey_free(int pkey);
These establish which protection keys are valid for use by
userspace. A key which was not obtained by pkey_alloc() may not
be passed to pkey_mprotect().
In addition, the 'init_access_rights' argument to pkey_alloc() specifies
the rights that will be established for the returned pkey. For instance
pkey = pkey_alloc(flags, PKEY_DENY_WRITE);
will return with the bits set in PKRU such that writing to 'pkey' is
already denied. This keeps userspace from needing to have knowledge
about manipulating PKRU. It is still free to do so if it wishes, but
it is no longer required.
The kernel does _not_ enforce that this interface must be used for
changes to PKRU, even for keys it does not control.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Cc: linux-api@vger.kernel.org
---
b/arch/x86/entry/syscalls/syscall_32.tbl | 2
b/arch/x86/entry/syscalls/syscall_64.tbl | 2
b/arch/x86/include/asm/mmu.h | 7 ++
b/arch/x86/include/asm/mmu_context.h | 8 +++
b/arch/x86/include/asm/pgtable.h | 5 +-
b/arch/x86/include/asm/pkeys.h | 55 ++++++++++++++++++++++
b/arch/x86/kernel/fpu/xstate.c | 75 +++++++++++++++++++++++++++++++
b/include/linux/pkeys.h | 23 +++++++++
b/include/uapi/asm-generic/mman-common.h | 5 ++
b/mm/mprotect.c | 59 +++++++++++++++++++++++-
10 files changed, 238 insertions(+), 3 deletions(-)
diff -puN arch/x86/entry/syscalls/syscall_32.tbl~pkey-allocation-syscalls arch/x86/entry/syscalls/syscall_32.tbl
--- a/arch/x86/entry/syscalls/syscall_32.tbl~pkey-allocation-syscalls 2015-12-03 16:21:32.484982342 -0800
+++ b/arch/x86/entry/syscalls/syscall_32.tbl 2015-12-03 16:21:32.502983159 -0800
@@ -384,3 +384,5 @@
375 i386 membarrier sys_membarrier
376 i386 mlock2 sys_mlock2
377 i386 pkey_mprotect sys_pkey_mprotect
+378 i386 pkey_alloc sys_pkey_alloc
+379 i386 pkey_free sys_pkey_free
diff -puN arch/x86/entry/syscalls/syscall_64.tbl~pkey-allocation-syscalls arch/x86/entry/syscalls/syscall_64.tbl
--- a/arch/x86/entry/syscalls/syscall_64.tbl~pkey-allocation-syscalls 2015-12-03 16:21:32.485982388 -0800
+++ b/arch/x86/entry/syscalls/syscall_64.tbl 2015-12-03 16:21:32.502983159 -0800
@@ -333,6 +333,8 @@
324 common membarrier sys_membarrier
325 common mlock2 sys_mlock2
326 common pkey_mprotect sys_pkey_mprotect
+327 common pkey_alloc sys_pkey_alloc
+328 common pkey_free sys_pkey_free
#
# x32-specific system call numbers start at 512 to avoid cache impact
diff -puN arch/x86/include/asm/mmu_context.h~pkey-allocation-syscalls arch/x86/include/asm/mmu_context.h
--- a/arch/x86/include/asm/mmu_context.h~pkey-allocation-syscalls 2015-12-03 16:21:32.487982478 -0800
+++ b/arch/x86/include/asm/mmu_context.h 2015-12-03 16:21:32.503983204 -0800
@@ -108,7 +108,12 @@ static inline void enter_lazy_tlb(struct
static inline int init_new_context(struct task_struct *tsk,
struct mm_struct *mm)
{
+#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
+ /* pkey 0 is the default and always allocated */
+ mm->context.pkey_allocation_map = 0x1;
+#endif
init_new_context_ldt(tsk, mm);
+
return 0;
}
static inline void destroy_context(struct mm_struct *mm)
@@ -333,4 +338,7 @@ static inline bool arch_pte_access_permi
return __pkru_allows_pkey(pte_flags_pkey(pte_flags(pte)), write);
}
+extern int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
+ unsigned long init_val);
+
#endif /* _ASM_X86_MMU_CONTEXT_H */
diff -puN arch/x86/include/asm/mmu.h~pkey-allocation-syscalls arch/x86/include/asm/mmu.h
--- a/arch/x86/include/asm/mmu.h~pkey-allocation-syscalls 2015-12-03 16:21:32.489982569 -0800
+++ b/arch/x86/include/asm/mmu.h 2015-12-03 16:21:32.503983204 -0800
@@ -22,6 +22,13 @@ typedef struct {
void __user *vdso;
atomic_t perf_rdpmc_allowed; /* nonzero if rdpmc is allowed */
+#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
+ /*
+ * One bit per protection key says whether userspace can
+ * use it or not. protected by mmap_sem.
+ */
+ u16 pkey_allocation_map;
+#endif
} mm_context_t;
#ifdef CONFIG_SMP
diff -puN arch/x86/include/asm/pgtable.h~pkey-allocation-syscalls arch/x86/include/asm/pgtable.h
--- a/arch/x86/include/asm/pgtable.h~pkey-allocation-syscalls 2015-12-03 16:21:32.490982614 -0800
+++ b/arch/x86/include/asm/pgtable.h 2015-12-03 16:21:32.503983204 -0800
@@ -912,16 +912,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 2
static 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.
diff -puN arch/x86/include/asm/pkeys.h~pkey-allocation-syscalls arch/x86/include/asm/pkeys.h
--- a/arch/x86/include/asm/pkeys.h~pkey-allocation-syscalls 2015-12-03 16:21:32.492982705 -0800
+++ b/arch/x86/include/asm/pkeys.h 2015-12-03 16:21:32.504983249 -0800
@@ -7,6 +7,61 @@
#define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | VM_PKEY_BIT3)
+#define mm_pkey_allocation_map(mm) (mm->context.pkey_allocation_map)
+#define mm_set_pkey_allocated(mm, pkey) do { \
+ mm_pkey_allocation_map(mm) |= (1 << pkey); \
+} while (0)
+#define mm_set_pkey_free(mm, pkey) do { \
+ mm_pkey_allocation_map(mm) &= ~(1 << pkey); \
+} while (0)
+
+static inline
+bool mm_pkey_is_allocated(struct mm_struct *mm, unsigned long pkey)
+{
+ if (!arch_validate_pkey(pkey))
+ return true;
+
+ return mm_pkey_allocation_map(mm) & (1 << pkey);
+}
+
+static inline
+int mm_pkey_alloc(struct mm_struct *mm)
+{
+ int all_pkeys_mask = ((1 << arch_max_pkey()) - 1);
+ int ret;
+
+ /*
+ * Are we out of pkeys? We must handle this specially
+ * because ffz() behavior is undefined if there are no
+ * zeros.
+ */
+ if (mm_pkey_allocation_map(mm) == all_pkeys_mask)
+ return -1;
+
+ ret = ffz(mm_pkey_allocation_map(mm));
+
+ mm_set_pkey_allocated(mm, ret);
+
+ return ret;
+}
+
+static inline
+int mm_pkey_free(struct mm_struct *mm, int pkey)
+{
+ /*
+ * pkey 0 is special, always allocated and can never
+ * be freed.
+ */
+ if (!pkey || !arch_validate_pkey(pkey))
+ return -EINVAL;
+ if (!mm_pkey_is_allocated(mm, pkey))
+ return -EINVAL;
+
+ mm_set_pkey_free(mm, pkey);
+
+ return 0;
+}
+
#endif /*_ASM_X86_PKEYS_H */
diff -puN arch/x86/kernel/fpu/xstate.c~pkey-allocation-syscalls arch/x86/kernel/fpu/xstate.c
--- a/arch/x86/kernel/fpu/xstate.c~pkey-allocation-syscalls 2015-12-03 16:21:32.494982796 -0800
+++ b/arch/x86/kernel/fpu/xstate.c 2015-12-03 16:21:32.504983249 -0800
@@ -5,6 +5,8 @@
*/
#include <linux/compat.h>
#include <linux/cpu.h>
+#include <linux/mman.h>
+#include <linux/pkeys.h>
#include <asm/fpu/api.h>
#include <asm/fpu/internal.h>
@@ -775,6 +777,7 @@ const void *get_xsave_field_ptr(int xsav
return get_xsave_addr(&fpu->state.xsave, xsave_state);
}
+#ifdef CONFIG_ARCH_HAS_PKEYS
/*
* Set xfeatures (aka XSTATE_BV) bit for a feature that we want
@@ -855,6 +858,78 @@ out:
* and (possibly) move the fpstate back in to the fpregs.
*/
fpu__current_fpstate_write_end();
+}
+
+#define NR_VALID_PKRU_BITS (CONFIG_NR_PROTECTION_KEYS * 2)
+#define PKRU_VALID_MASK (NR_VALID_PKRU_BITS - 1)
+
+/*
+ * This will go out and modify the XSAVE buffer so that PKRU is
+ * set to a particular state for access to 'pkey'.
+ *
+ * PKRU state does affect kernel access to user memory. We do
+ * not modfiy PKRU *itself* here, only the XSAVE state that will
+ * be restored in to PKRU when we return back to userspace.
+ */
+int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
+ unsigned long init_val)
+{
+ struct xregs_state *xsave = &tsk->thread.fpu.state.xsave;
+ struct pkru_state *old_pkru_state;
+ struct pkru_state new_pkru_state;
+ int pkey_shift = (pkey * PKRU_BITS_PER_PKEY);
+ u32 new_pkru_bits = 0;
+
+ if (!arch_validate_pkey(pkey))
+ return -EINVAL;
+ /*
+ * This check implies XSAVE support. OSPKE only gets
+ * set if we enable XSAVE and we enable PKU in XCR0.
+ */
+ if (!boot_cpu_has(X86_FEATURE_OSPKE))
+ return -EINVAL;
+
+ /* Set the bits we need in PKRU */
+ if (init_val & PKEY_DISABLE_ACCESS)
+ new_pkru_bits |= PKRU_AD_BIT;
+ if (init_val & PKEY_DISABLE_WRITE)
+ new_pkru_bits |= PKRU_WD_BIT;
+
+ /* Shift the bits in to the correct place in PKRU for pkey. */
+ new_pkru_bits <<= pkey_shift;
+
+ /* Locate old copy of the state in the xsave buffer */
+ old_pkru_state = get_xsave_addr(xsave, XFEATURE_MASK_PKRU);
+
+ /*
+ * When state is not in the buffer, it is in the init
+ * state, set it manually. Otherwise, copy out the old
+ * state.
+ */
+ if (!old_pkru_state)
+ new_pkru_state.pkru = 0;
+ else
+ new_pkru_state.pkru = old_pkru_state->pkru;
+
+ /* mask off any old bits in place */
+ new_pkru_state.pkru &= ~((PKRU_AD_BIT|PKRU_WD_BIT) << pkey_shift);
+ /* Set the newly-requested bits */
+ new_pkru_state.pkru |= new_pkru_bits;
+
+ /*
+ * We could theoretically live without zeroing pkru.pad.
+ * The current XSAVE feature state definition says that
+ * only bytes 0->3 are used. But we do not want to
+ * chance leaking kernel stack out to userspace in case a
+ * memcpy() of the whole xsave buffer was done.
+ *
+ * They're in the same cacheline anyway.
+ */
+ new_pkru_state.pad = 0;
+
+ fpu__xfeature_set_state(XFEATURE_MASK_PKRU, &new_pkru_state,
+ sizeof(new_pkru_state));
return 0;
}
+#endif /* CONFIG_ARCH_HAS_PKEYS */
diff -puN include/linux/pkeys.h~pkey-allocation-syscalls include/linux/pkeys.h
--- a/include/linux/pkeys.h~pkey-allocation-syscalls 2015-12-03 16:21:32.495982841 -0800
+++ b/include/linux/pkeys.h 2015-12-03 16:21:32.504983249 -0800
@@ -23,6 +23,29 @@ static inline int vma_pkey(struct vm_are
{
return 0;
}
+
+static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
+{
+ return (pkey == 0);
+}
+
+static inline int mm_pkey_alloc(struct mm_struct *mm)
+{
+ return -1;
+}
+
+static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
+{
+ WARN_ONCE(1, "free of protection key when disabled");
+ return -EINVAL;
+}
+
+static inline int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
+ unsigned long init_val)
+{
+ return 0;
+}
+
#endif /* ! CONFIG_ARCH_HAS_PKEYS */
#endif /* _LINUX_PKEYS_H */
diff -puN include/uapi/asm-generic/mman-common.h~pkey-allocation-syscalls include/uapi/asm-generic/mman-common.h
--- a/include/uapi/asm-generic/mman-common.h~pkey-allocation-syscalls 2015-12-03 16:21:32.497982932 -0800
+++ b/include/uapi/asm-generic/mman-common.h 2015-12-03 16:21:32.505983295 -0800
@@ -71,4 +71,9 @@
#define MAP_HUGE_SHIFT 26
#define MAP_HUGE_MASK 0x3f
+#define PKEY_DISABLE_ACCESS 0x1
+#define PKEY_DISABLE_WRITE 0x2
+#define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\
+ PKEY_DISABLE_WRITE)
+
#endif /* __ASM_GENERIC_MMAN_COMMON_H */
diff -puN mm/mprotect.c~pkey-allocation-syscalls mm/mprotect.c
--- a/mm/mprotect.c~pkey-allocation-syscalls 2015-12-03 16:21:32.498982977 -0800
+++ b/mm/mprotect.c 2015-12-03 16:21:32.505983295 -0800
@@ -23,11 +23,13 @@
#include <linux/mmu_notifier.h>
#include <linux/migrate.h>
#include <linux/perf_event.h>
+#include <linux/pkeys.h>
#include <linux/ksm.h>
#include <linux/pkeys.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/cacheflush.h>
+#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
#include "internal.h"
@@ -355,6 +357,8 @@ static int do_mprotect_pkey(unsigned lon
struct vm_area_struct *vma, *prev;
int error = -EINVAL;
const int grows = prot & (PROT_GROWSDOWN|PROT_GROWSUP);
+ int plain_mprotect = (pkey == -1);
+
prot &= ~(PROT_GROWSDOWN|PROT_GROWSUP);
if (grows == (PROT_GROWSDOWN|PROT_GROWSUP)) /* can't be both */
return -EINVAL;
@@ -379,6 +383,14 @@ static int do_mprotect_pkey(unsigned lon
down_write(¤t->mm->mmap_sem);
+ /*
+ * If userspace did not allocate the pkey, do not let
+ * them use it here.
+ */
+ error = -EINVAL;
+ if (!plain_mprotect && !mm_pkey_is_allocated(current->mm, pkey))
+ goto out;
+
vma = find_vma(current->mm, start);
error = -ENOMEM;
if (!vma)
@@ -420,7 +432,7 @@ static int do_mprotect_pkey(unsigned lon
* If this is a vanilla, non-pkey mprotect, inherit the
* pkey from the VMA we are working on.
*/
- if (pkey == -1)
+ if (plain_mprotect)
newflags = calc_vm_prot_bits(prot, vma_pkey(vma));
else
newflags = calc_vm_prot_bits(prot, pkey);
@@ -474,3 +486,48 @@ SYSCALL_DEFINE4(pkey_mprotect, unsigned
return do_mprotect_pkey(start, len, prot, pkey);
}
+
+SYSCALL_DEFINE2(pkey_alloc, unsigned long, flags, unsigned long, init_val)
+{
+ int pkey;
+ int ret;
+
+ /* No flags supported yet. */
+ if (flags)
+ return -EINVAL;
+ /* check for unsupported init values */
+ if (init_val & ~PKEY_ACCESS_MASK)
+ return -EINVAL;
+
+ down_write(¤t->mm->mmap_sem);
+ pkey = mm_pkey_alloc(current->mm);
+
+ ret = -ENOSPC;
+ if (pkey == -1)
+ goto out;
+
+ ret = arch_set_user_pkey_access(current, pkey, init_val);
+ if (ret) {
+ mm_pkey_free(current->mm, pkey);
+ goto out;
+ }
+ ret = pkey;
+out:
+ up_write(¤t->mm->mmap_sem);
+ return ret;
+}
+
+SYSCALL_DEFINE1(pkey_free, int, pkey)
+{
+ int ret;
+
+ down_write(¤t->mm->mmap_sem);
+ ret = mm_pkey_free(current->mm, pkey);
+ up_write(¤t->mm->mmap_sem);
+
+ /*
+ * We could provie warnings or errors if any VMA still
+ * has the pkey set here.
+ */
+ return ret;
+}
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-12-04 02:20 +0100 |
| Subject | [PATCH 12/34] signals, pkeys: notify userspace about protection key faults |
| Message-ID | <qBNcu-4nR-31@gated-at.bofh.it> |
| In reply to | #1283499 |
From: Dave Hansen <dave.hansen@linux.intel.com>
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.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
---
b/include/uapi/asm-generic/siginfo.h | 17 ++++++++++++-----
b/kernel/signal.c | 4 ++++
2 files changed, 16 insertions(+), 5 deletions(-)
diff -puN include/uapi/asm-generic/siginfo.h~pkeys-09-siginfo-core include/uapi/asm-generic/siginfo.h
--- a/include/uapi/asm-generic/siginfo.h~pkeys-09-siginfo-core 2015-12-03 16:21:23.412570898 -0800
+++ b/include/uapi/asm-generic/siginfo.h 2015-12-03 16:21:23.417571125 -0800
@@ -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
diff -puN kernel/signal.c~pkeys-09-siginfo-core kernel/signal.c
--- a/kernel/signal.c~pkeys-09-siginfo-core 2015-12-03 16:21:23.414570989 -0800
+++ b/kernel/signal.c 2015-12-03 16:21:23.418571170 -0800
@@ -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);
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-12-04 02:20 +0100 |
| Subject | [PATCH 20/34] x86, pkeys: differentiate instruction fetches |
| Message-ID | <qBNcu-4nR-33@gated-at.bofh.it> |
| In reply to | #1283499 |
From: Dave Hansen <dave.hansen@linux.intel.com>
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.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
---
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(-)
diff -puN arch/powerpc/include/asm/mmu_context.h~pkeys-allow-execute-on-unreadable arch/powerpc/include/asm/mmu_context.h
--- a/arch/powerpc/include/asm/mmu_context.h~pkeys-allow-execute-on-unreadable 2015-12-03 16:21:27.286746596 -0800
+++ b/arch/powerpc/include/asm/mmu_context.h 2015-12-03 16:21:27.301747276 -0800
@@ -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;
diff -puN arch/s390/include/asm/mmu_context.h~pkeys-allow-execute-on-unreadable arch/s390/include/asm/mmu_context.h
--- a/arch/s390/include/asm/mmu_context.h~pkeys-allow-execute-on-unreadable 2015-12-03 16:21:27.288746687 -0800
+++ b/arch/s390/include/asm/mmu_context.h 2015-12-03 16:21:27.302747322 -0800
@@ -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;
diff -puN arch/x86/include/asm/mmu_context.h~pkeys-allow-execute-on-unreadable arch/x86/include/asm/mmu_context.h
--- a/arch/x86/include/asm/mmu_context.h~pkeys-allow-execute-on-unreadable 2015-12-03 16:21:27.289746732 -0800
+++ b/arch/x86/include/asm/mmu_context.h 2015-12-03 16:21:27.302747322 -0800
@@ -300,8 +300,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;
diff -puN arch/x86/mm/fault.c~pkeys-allow-execute-on-unreadable arch/x86/mm/fault.c
--- a/arch/x86/mm/fault.c~pkeys-allow-execute-on-unreadable 2015-12-03 16:21:27.291746823 -0800
+++ b/arch/x86/mm/fault.c 2015-12-03 16:21:27.303747367 -0800
@@ -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, un
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
diff -puN include/asm-generic/mm_hooks.h~pkeys-allow-execute-on-unreadable include/asm-generic/mm_hooks.h
--- a/include/asm-generic/mm_hooks.h~pkeys-allow-execute-on-unreadable 2015-12-03 16:21:27.293746914 -0800
+++ b/include/asm-generic/mm_hooks.h 2015-12-03 16:21:27.303747367 -0800
@@ -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;
diff -puN include/linux/mm.h~pkeys-allow-execute-on-unreadable include/linux/mm.h
--- a/include/linux/mm.h~pkeys-allow-execute-on-unreadable 2015-12-03 16:21:27.294746959 -0800
+++ b/include/linux/mm.h 2015-12-03 16:21:27.304747413 -0800
@@ -233,6 +233,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_FOREIGN 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
diff -puN mm/gup.c~pkeys-allow-execute-on-unreadable mm/gup.c
--- a/mm/gup.c~pkeys-allow-execute-on-unreadable 2015-12-03 16:21:27.296747050 -0800
+++ b/mm/gup.c 2015-12-03 16:21:27.304747413 -0800
@@ -396,7 +396,11 @@ static int check_vma_flags(struct vm_are
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=0 here
+ */
+ if (!arch_vma_access_permitted(vma, write, 0, foreign))
return -EFAULT;
return 0;
}
@@ -576,8 +580,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=0 here:
*/
- if (!arch_vma_access_permitted(vma, write, foreign))
+ if (!arch_vma_access_permitted(vma, write, 0, foreign))
return false;
return true;
diff -puN mm/memory.c~pkeys-allow-execute-on-unreadable mm/memory.c
--- a/mm/memory.c~pkeys-allow-execute-on-unreadable 2015-12-03 16:21:27.298747141 -0800
+++ b/mm/memory.c 2015-12-03 16:21:27.306747503 -0800
@@ -3346,6 +3346,7 @@ static int __handle_mm_fault(struct mm_s
pte_t *pte;
if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
+ flags & FAULT_FLAG_INSTRUCTION,
flags & FAULT_FLAG_FOREIGN))
return VM_FAULT_SIGSEGV;
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2015-12-08 19:20 +0100 |
| Subject | Re: [PATCH 20/34] x86, pkeys: differentiate instruction fetches |
| Message-ID | <qDv1L-5NC-5@gated-at.bofh.it> |
| In reply to | #1283505 |
On Thu, 3 Dec 2015, Dave Hansen wrote: > static inline bool arch_vma_access_permitted(struct vm_area_struct *vma, > - bool write, bool foreign) > + bool write, bool execute, bool foreign) .... > + /* > + * gups are always data accesses, not instruction > + * fetches, so execute=0 here Again. Can we please be consistent about booleans? > + */ > + if (!arch_vma_access_permitted(vma, write, 0, foreign)) > return -EFAULT; > return 0; > } > @@ -576,8 +580,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=0 here: > */ > - if (!arch_vma_access_permitted(vma, write, foreign)) > + if (!arch_vma_access_permitted(vma, write, 0, foreign)) > return false; Ditto. Other than that: Reviewed-by: Thomas Gleixner <tglx@linutronix.de> -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-12-04 02:20 +0100 |
| Subject | [PATCH 19/34] x86, pkeys: optimize fault handling in access_error() |
| Message-ID | <qBNcu-4nR-25@gated-at.bofh.it> |
| In reply to | #1283499 |
From: Dave Hansen <dave.hansen@linux.intel.com>
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.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
---
b/arch/x86/mm/fault.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff -puN arch/x86/mm/fault.c~pkeys-15-access_error arch/x86/mm/fault.c
--- a/arch/x86/mm/fault.c~pkeys-15-access_error 2015-12-03 16:21:26.872727820 -0800
+++ b/arch/x86/mm/fault.c 2015-12-03 16:21:26.876728002 -0800
@@ -900,10 +900,16 @@ bad_area(struct pt_regs *regs, unsigned
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 */
+ int foreign = 0;
+
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: */
+ int foreign = 0;
/*
* 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: */
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2015-12-08 19:20 +0100 |
| Subject | Re: [PATCH 19/34] x86, pkeys: optimize fault handling in access_error() |
| Message-ID | <qDv1L-5NC-11@gated-at.bofh.it> |
| In reply to | #1283506 |
On Thu, 3 Dec 2015, Dave Hansen wrote:
> diff -puN arch/x86/mm/fault.c~pkeys-15-access_error arch/x86/mm/fault.c
> --- a/arch/x86/mm/fault.c~pkeys-15-access_error 2015-12-03 16:21:26.872727820 -0800
> +++ b/arch/x86/mm/fault.c 2015-12-03 16:21:26.876728002 -0800
> @@ -900,10 +900,16 @@ bad_area(struct pt_regs *regs, unsigned
> 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 */
> + int foreign = 0;
arch_vma_access_permitted takes a bool ....
> 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: */
> + int foreign = 0;
Ditto.
Other than that: Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-12-04 02:20 +0100 |
| Subject | [PATCH 18/34] mm: add gup flag to indicate "foreign" mm access |
| Message-ID | <qBNcu-4nR-41@gated-at.bofh.it> |
| In reply to | #1283499 |
From: Dave Hansen <dave.hansen@linux.intel.com>
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 add a GUP flag: FOLL_FOREIGN and a fault flag:
FAULT_FLAG_FOREIGN. 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).
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Cc: linux-arch@vger.kernel.org
---
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 | 8 +++++---
b/include/asm-generic/mm_hooks.h | 3 ++-
b/include/linux/mm.h | 2 ++
b/mm/gup.c | 15 ++++++++++-----
b/mm/ksm.c | 10 ++++++++--
b/mm/memory.c | 3 ++-
10 files changed, 38 insertions(+), 17 deletions(-)
diff -puN arch/powerpc/include/asm/mmu_context.h~pkeys-12-gup-fault-foreign-flag arch/powerpc/include/asm/mmu_context.h
--- a/arch/powerpc/include/asm/mmu_context.h~pkeys-12-gup-fault-foreign-flag 2015-12-03 16:21:26.223698386 -0800
+++ b/arch/powerpc/include/asm/mmu_context.h 2015-12-03 16:21:26.241699202 -0800
@@ -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;
diff -puN arch/s390/include/asm/mmu_context.h~pkeys-12-gup-fault-foreign-flag arch/s390/include/asm/mmu_context.h
--- a/arch/s390/include/asm/mmu_context.h~pkeys-12-gup-fault-foreign-flag 2015-12-03 16:21:26.224698431 -0800
+++ b/arch/s390/include/asm/mmu_context.h 2015-12-03 16:21:26.242699248 -0800
@@ -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;
diff -puN arch/unicore32/include/asm/mmu_context.h~pkeys-12-gup-fault-foreign-flag arch/unicore32/include/asm/mmu_context.h
--- a/arch/unicore32/include/asm/mmu_context.h~pkeys-12-gup-fault-foreign-flag 2015-12-03 16:21:26.226698522 -0800
+++ b/arch/unicore32/include/asm/mmu_context.h 2015-12-03 16:21:26.242699248 -0800
@@ -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;
diff -puN arch/x86/include/asm/mmu_context.h~pkeys-12-gup-fault-foreign-flag arch/x86/include/asm/mmu_context.h
--- a/arch/x86/include/asm/mmu_context.h~pkeys-12-gup-fault-foreign-flag 2015-12-03 16:21:26.228698613 -0800
+++ b/arch/x86/include/asm/mmu_context.h 2015-12-03 16:21:26.242699248 -0800
@@ -299,10 +299,11 @@ static inline bool vma_is_foreign(struct
return 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);
}
diff -puN drivers/iommu/amd_iommu_v2.c~pkeys-12-gup-fault-foreign-flag drivers/iommu/amd_iommu_v2.c
--- a/drivers/iommu/amd_iommu_v2.c~pkeys-12-gup-fault-foreign-flag 2015-12-03 16:21:26.229698658 -0800
+++ b/drivers/iommu/amd_iommu_v2.c 2015-12-03 16:21:26.243699293 -0800
@@ -500,9 +500,11 @@ static void do_fault(struct work_struct
struct mm_struct *mm;
struct vm_area_struct *vma;
u64 address;
- int ret, write;
+ int ret, flags;
- write = !!(fault->flags & PPR_FAULT_WRITE);
+ if (fault->flags & PPR_FAULT_WRITE)
+ flags = FAULT_FLAG_WRITE;
+ flags |= FAULT_FLAG_FOREIGN;
mm = fault->state->mm;
address = fault->address;
@@ -523,7 +525,7 @@ static void do_fault(struct work_struct
goto out;
}
- ret = handle_mm_fault(mm, vma, address, write);
+ ret = handle_mm_fault(mm, vma, address, flags);
if (ret & VM_FAULT_ERROR) {
/* failed to service fault */
up_read(&mm->mmap_sem);
diff -puN include/asm-generic/mm_hooks.h~pkeys-12-gup-fault-foreign-flag include/asm-generic/mm_hooks.h
--- a/include/asm-generic/mm_hooks.h~pkeys-12-gup-fault-foreign-flag 2015-12-03 16:21:26.231698749 -0800
+++ b/include/asm-generic/mm_hooks.h 2015-12-03 16:21:26.243699293 -0800
@@ -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;
diff -puN include/linux/mm.h~pkeys-12-gup-fault-foreign-flag include/linux/mm.h
--- a/include/linux/mm.h~pkeys-12-gup-fault-foreign-flag 2015-12-03 16:21:26.233698839 -0800
+++ b/include/linux/mm.h 2015-12-03 16:21:26.244699338 -0800
@@ -232,6 +232,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_FOREIGN 0x80 /* faulting for non current tsk/mm */
/*
* vm_fault is filled by the the pagefault handler and passed to the vma's
@@ -2138,6 +2139,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_FOREIGN 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);
diff -puN mm/gup.c~pkeys-12-gup-fault-foreign-flag mm/gup.c
--- a/mm/gup.c~pkeys-12-gup-fault-foreign-flag 2015-12-03 16:21:26.234698885 -0800
+++ b/mm/gup.c 2015-12-03 16:21:26.245699384 -0800
@@ -310,6 +310,8 @@ static int faultin_page(struct task_stru
return -ENOENT;
if (*flags & FOLL_WRITE)
fault_flags |= FAULT_FLAG_WRITE;
+ if (*flags & FOLL_FOREIGN)
+ fault_flags |= FAULT_FLAG_FOREIGN;
if (nonblocking)
fault_flags |= FAULT_FLAG_ALLOW_RETRY;
if (*flags & FOLL_NOWAIT)
@@ -360,11 +362,13 @@ static int faultin_page(struct task_stru
static 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_FOREIGN);
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;
@@ -392,7 +396,7 @@ static int check_vma_flags(struct vm_are
if (!(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;
}
@@ -562,7 +566,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_FOREIGN);
vm_flags_t vm_flags = write ? VM_WRITE : VM_READ;
if (!(vm_flags & vma->vm_flags))
@@ -570,9 +575,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;
diff -puN mm/ksm.c~pkeys-12-gup-fault-foreign-flag mm/ksm.c
--- a/mm/ksm.c~pkeys-12-gup-fault-foreign-flag 2015-12-03 16:21:26.236698975 -0800
+++ b/mm/ksm.c 2015-12-03 16:21:26.246699429 -0800
@@ -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_FOREIGN 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_FOREIGN);
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_FOREIGN);
else
ret = VM_FAULT_WRITE;
put_page(page);
diff -puN mm/memory.c~pkeys-12-gup-fault-foreign-flag mm/memory.c
--- a/mm/memory.c~pkeys-12-gup-fault-foreign-flag 2015-12-03 16:21:26.238699066 -0800
+++ b/mm/memory.c 2015-12-03 16:21:26.247699474 -0800
@@ -3345,7 +3345,8 @@ static int __handle_mm_fault(struct mm_s
pmd_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_FOREIGN))
return VM_FAULT_SIGSEGV;
if (unlikely(is_vm_hugetlb_page(vma)))
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-12-04 02:20 +0100 |
| Subject | [PATCH 27/34] x86, pkeys: make mprotect_key() mask off additional vm_flags |
| Message-ID | <qBNcu-4nR-39@gated-at.bofh.it> |
| In reply to | #1283499 |
From: Dave Hansen <dave.hansen@linux.intel.com>
Today, mprotect() takes 4 bits of data: PROT_READ/WRITE/EXEC/NONE.
Three of those bits: READ/WRITE/EXEC get translated directly in to
vma->vm_flags by calc_vm_prot_bits(). If a bit is unset in
mprotect()'s 'prot' argument then it must be cleared in vma->vm_flags
during the mprotect() call.
We do the by first calculating the VMA flags we want set, then
clearing the ones we do not want to inherit from the original VMA:
vm_flags = calc_vm_prot_bits(prot, key);
...
newflags = vm_flags;
newflags |= (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC));
However, we *also* want to mask off the original VMA's vm_flags in
which we store the protection key.
To do that, this patch adds a new macro:
ARCH_VM_FLAGS_AFFECTED_BY_MPROTECT
which allows the architecture to specify additional bits that it would
like cleared. We use that to ensure that the VM_PKEY_BIT* bits get
cleared.
This got missed in my testing because I was always going from a pkey=0
VMA to a nonzero one. The current code works when we only set bits
but never clear them. I've fixed this up in my testing.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
---
b/arch/x86/include/asm/pkeys.h | 2 ++
b/include/linux/pkeys.h | 1 +
b/mm/mprotect.c | 9 ++++++++-
3 files changed, 11 insertions(+), 1 deletion(-)
diff -puN arch/x86/include/asm/pkeys.h~pkeys-mask-off-correct-vm_flags arch/x86/include/asm/pkeys.h
--- a/arch/x86/include/asm/pkeys.h~pkeys-mask-off-correct-vm_flags 2015-12-03 16:21:30.666899890 -0800
+++ b/arch/x86/include/asm/pkeys.h 2015-12-03 16:21:30.672900162 -0800
@@ -5,6 +5,8 @@
CONFIG_NR_PROTECTION_KEYS : 1)
#define arch_validate_pkey(pkey) (((pkey) >= 0) && ((pkey) < arch_max_pkey()))
+#define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | VM_PKEY_BIT3)
+
#endif /*_ASM_X86_PKEYS_H */
diff -puN include/linux/pkeys.h~pkeys-mask-off-correct-vm_flags include/linux/pkeys.h
--- a/include/linux/pkeys.h~pkeys-mask-off-correct-vm_flags 2015-12-03 16:21:30.667899935 -0800
+++ b/include/linux/pkeys.h 2015-12-03 16:21:30.672900162 -0800
@@ -7,6 +7,7 @@
#include <asm/pkeys.h>
#include <asm/mmu_context.h>
#else /* ! CONFIG_ARCH_HAS_PKEYS */
+#define ARCH_VM_PKEY_FLAGS 0
/*
* This is called from mprotect_pkey().
diff -puN mm/mprotect.c~pkeys-mask-off-correct-vm_flags mm/mprotect.c
--- a/mm/mprotect.c~pkeys-mask-off-correct-vm_flags 2015-12-03 16:21:30.669900026 -0800
+++ b/mm/mprotect.c 2015-12-03 16:21:30.673900208 -0800
@@ -406,6 +406,13 @@ static int do_mprotect_pkey(unsigned lon
for (nstart = start ; ; ) {
unsigned long newflags;
+ /*
+ * Each mprotect() call explicitly passes r/w/x permissions.
+ * If a permission is not passed to mprotect(), it must be
+ * cleared from the VMA.
+ */
+ unsigned long mask_off_old_flags = VM_READ | VM_WRITE | VM_EXEC;
+ mask_off_old_flags |= ARCH_VM_PKEY_FLAGS;
/* Here we know that vma->vm_start <= nstart < vma->vm_end. */
@@ -417,7 +424,7 @@ static int do_mprotect_pkey(unsigned lon
newflags = calc_vm_prot_bits(prot, vma_pkey(vma));
else
newflags = calc_vm_prot_bits(prot, pkey);
- newflags |= (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC));
+ newflags |= (vma->vm_flags & ~mask_off_old_flags);
/* newflags >> 4 shift VM_MAY% in place of VM_% */
if ((newflags & ~(newflags >> 4)) & (VM_READ | VM_WRITE | VM_EXEC)) {
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2015-12-08 19:50 +0100 |
| Subject | Re: [PATCH 27/34] x86, pkeys: make mprotect_key() mask off additional vm_flags |
| Message-ID | <qDvuO-5Xs-15@gated-at.bofh.it> |
| In reply to | #1283509 |
On Thu, 3 Dec 2015, Dave Hansen wrote: > > From: Dave Hansen <dave.hansen@linux.intel.com> > > Today, mprotect() takes 4 bits of data: PROT_READ/WRITE/EXEC/NONE. > Three of those bits: READ/WRITE/EXEC get translated directly in to > vma->vm_flags by calc_vm_prot_bits(). If a bit is unset in > mprotect()'s 'prot' argument then it must be cleared in vma->vm_flags > during the mprotect() call. > > We do the by first calculating the VMA flags we want set, then > clearing the ones we do not want to inherit from the original VMA: > > vm_flags = calc_vm_prot_bits(prot, key); > ... > newflags = vm_flags; > newflags |= (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC)); > > However, we *also* want to mask off the original VMA's vm_flags in > which we store the protection key. > > To do that, this patch adds a new macro: > > ARCH_VM_FLAGS_AFFECTED_BY_MPROTECT -ENOSUCHMACRO > which allows the architecture to specify additional bits that it would > like cleared. We use that to ensure that the VM_PKEY_BIT* bits get > cleared. Other than that: Reviewed-by: Thomas Gleixner <tglx@linutronix.de> -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-12-04 02:20 +0100 |
| Subject | [PATCH 23/34] x86, pkeys: add Kconfig prompt to existing config option |
| Message-ID | <qBNcu-4nR-35@gated-at.bofh.it> |
| In reply to | #1283499 |
From: Dave Hansen <dave.hansen@linux.intel.com> 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. Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> --- b/arch/x86/Kconfig | 10 ++++++++++ 1 file changed, 10 insertions(+) diff -puN arch/x86/Kconfig~pkeys-40-kconfig-prompt arch/x86/Kconfig --- a/arch/x86/Kconfig~pkeys-40-kconfig-prompt 2015-12-03 16:21:28.726811905 -0800 +++ b/arch/x86/Kconfig 2015-12-03 16:21:28.730812086 -0800 @@ -1682,8 +1682,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" _ -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2015-12-08 19:30 +0100 |
| Subject | Re: [PATCH 23/34] x86, pkeys: add Kconfig prompt to existing config option |
| Message-ID | <qDvbs-5QP-19@gated-at.bofh.it> |
| In reply to | #1283511 |
On Thu, 3 Dec 2015, Dave Hansen wrote: > 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. The tiny kernel folks are happy about every few kB which are NOT added by default. > > Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> > --- > > b/arch/x86/Kconfig | 10 ++++++++++ > 1 file changed, 10 insertions(+) > > diff -puN arch/x86/Kconfig~pkeys-40-kconfig-prompt arch/x86/Kconfig > --- a/arch/x86/Kconfig~pkeys-40-kconfig-prompt 2015-12-03 16:21:28.726811905 -0800 > +++ b/arch/x86/Kconfig 2015-12-03 16:21:28.730812086 -0800 > @@ -1682,8 +1682,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" > _ > -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-12-04 02:20 +0100 |
| Subject | [PATCH 25/34] x86, pkeys: add arch_validate_pkey() |
| Message-ID | <qBNcv-4nR-49@gated-at.bofh.it> |
| In reply to | #1283499 |
From: Dave Hansen <dave.hansen@linux.intel.com>
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.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
---
b/arch/x86/Kconfig | 1 +
b/arch/x86/include/asm/pkeys.h | 10 ++++++++++
b/include/linux/pkeys.h | 22 ++++++++++++++++++++++
b/mm/Kconfig | 2 ++
4 files changed, 35 insertions(+)
diff -puN /dev/null arch/x86/include/asm/pkeys.h
--- /dev/null 2015-07-13 14:24:11.435656502 -0700
+++ b/arch/x86/include/asm/pkeys.h 2015-12-03 16:21:29.710856533 -0800
@@ -0,0 +1,10 @@
+#ifndef _ASM_X86_PKEYS_H
+#define _ASM_X86_PKEYS_H
+
+#define arch_max_pkey() (boot_cpu_has(X86_FEATURE_OSPKE) ? \
+ CONFIG_NR_PROTECTION_KEYS : 1)
+#define arch_validate_pkey(pkey) (((pkey) >= 0) && ((pkey) < arch_max_pkey()))
+
+#endif /*_ASM_X86_PKEYS_H */
+
+
diff -puN arch/x86/Kconfig~pkeys-15-arch_validate_peky arch/x86/Kconfig
--- a/arch/x86/Kconfig~pkeys-15-arch_validate_peky 2015-12-03 16:21:29.705856306 -0800
+++ b/arch/x86/Kconfig 2015-12-03 16:21:29.711856578 -0800
@@ -153,6 +153,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
diff -puN /dev/null include/linux/pkeys.h
--- /dev/null 2015-07-13 14:24:11.435656502 -0700
+++ b/include/linux/pkeys.h 2015-12-03 16:21:29.711856578 -0800
@@ -0,0 +1,22 @@
+#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 */
+
+/*
+ * This is called from mprotect_pkey().
+ *
+ * Returns true if the protection keys is valid.
+ */
+static inline bool arch_validate_pkey(int key)
+{
+ return true;
+}
+#endif /* ! CONFIG_ARCH_HAS_PKEYS */
+
+#endif /* _LINUX_PKEYS_H */
diff -puN mm/Kconfig~pkeys-15-arch_validate_peky mm/Kconfig
--- a/mm/Kconfig~pkeys-15-arch_validate_peky 2015-12-03 16:21:29.707856396 -0800
+++ b/mm/Kconfig 2015-12-03 16:21:29.711856578 -0800
@@ -671,3 +671,5 @@ config FRAME_VECTOR
config ARCH_USES_HIGH_VMA_FLAGS
bool
+config ARCH_HAS_PKEYS
+ bool
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2015-12-08 19:50 +0100 |
| Subject | Re: [PATCH 25/34] x86, pkeys: add arch_validate_pkey() |
| Message-ID | <qDvuO-5Xs-13@gated-at.bofh.it> |
| In reply to | #1283513 |
On Thu, 3 Dec 2015, Dave Hansen wrote: > +#define arch_max_pkey() (boot_cpu_has(X86_FEATURE_OSPKE) ? \ > + CONFIG_NR_PROTECTION_KEYS : 1) Should this really be a config option? Can't that value change ? Thanks, tglx -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-12-04 02:20 +0100 |
| Subject | [PATCH 33/34] x86, pkeys: actually enable Memory Protection Keys in CPU |
| Message-ID | <qBNcv-4nR-59@gated-at.bofh.it> |
| In reply to | #1283499 |
From: Dave Hansen <dave.hansen@linux.intel.com>
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().
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
---
b/Documentation/kernel-parameters.txt | 3 ++
b/arch/x86/kernel/cpu/common.c | 41 ++++++++++++++++++++++++++++++++++
2 files changed, 44 insertions(+)
diff -puN arch/x86/kernel/cpu/common.c~pkeys-50-should-be-last-patch arch/x86/kernel/cpu/common.c
--- a/arch/x86/kernel/cpu/common.c~pkeys-50-should-be-last-patch 2015-12-03 16:21:33.708037809 -0800
+++ b/arch/x86/kernel/cpu/common.c 2015-12-03 16:21:33.714038081 -0800
@@ -289,6 +289,46 @@ static __always_inline void setup_smap(s
}
/*
+ * Protection Keys are not available in 32-bit mode.
+ */
+static bool pku_disabled = false;
+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.
@@ -948,6 +988,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
diff -puN Documentation/kernel-parameters.txt~pkeys-50-should-be-last-patch Documentation/kernel-parameters.txt
--- a/Documentation/kernel-parameters.txt~pkeys-50-should-be-last-patch 2015-12-03 16:21:33.710037900 -0800
+++ b/Documentation/kernel-parameters.txt 2015-12-03 16:21:33.715038127 -0800
@@ -958,6 +958,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 from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Hansen <dave@sr71.net> |
|---|---|
| Date | 2015-12-04 02:20 +0100 |
| Subject | [PATCH 26/34] mm: implement new mprotect_key() system call |
| Message-ID | <qBNcv-4nR-57@gated-at.bofh.it> |
| In reply to | #1283499 |
From: Dave Hansen <dave.hansen@linux.intel.com>
mprotect_key() is just like mprotect, except it also takes a
protection key as an argument. On systems that do not support
protection keys, it still works, but requires that key=0.
Otherwise it does exactly what mprotect does.
I expect it to get used like this, if you want to guarantee that
any mapping you create can *never* be accessed without the right
protection keys set up.
pkey_deny_access(11); // random pkey
int real_prot = PROT_READ|PROT_WRITE;
ptr = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
ret = mprotect_key(ptr, PAGE_SIZE, real_prot, 11);
This way, there is *no* window where the mapping is accessible
since it was always either PROT_NONE or had a protection key set.
We settled on 'unsigned long' for the type of the key here. We
only need 4 bits on x86 today, but I figured that other
architectures might need some more space.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Cc: linux-api@vger.kernel.org
---
b/arch/x86/include/asm/mmu_context.h | 10 +++++++--
b/include/linux/pkeys.h | 7 +++++-
b/mm/Kconfig | 7 ++++++
b/mm/mprotect.c | 36 +++++++++++++++++++++++++++++------
4 files changed, 51 insertions(+), 9 deletions(-)
diff -puN arch/x86/include/asm/mmu_context.h~pkeys-85-mprotect_pkey arch/x86/include/asm/mmu_context.h
--- a/arch/x86/include/asm/mmu_context.h~pkeys-85-mprotect_pkey 2015-12-03 16:21:30.181877894 -0800
+++ b/arch/x86/include/asm/mmu_context.h 2015-12-03 16:21:30.190878302 -0800
@@ -4,6 +4,7 @@
#include <asm/desc.h>
#include <linux/atomic.h>
#include <linux/mm_types.h>
+#include <linux/pkeys.h>
#include <trace/events/tlb.h>
@@ -243,10 +244,14 @@ static inline void arch_unmap(struct mm_
mpx_notify_unmap(mm, vma, start, end);
}
+#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
+/*
+ * If the config option is off, we get the generic version from
+ * include/linux/pkeys.h.
+ */
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;
/*
@@ -259,9 +264,10 @@ static inline int vma_pkey(struct vm_are
*/
pkey = (vma->vm_flags >> vm_pkey_shift) &
(vma_pkey_mask >> vm_pkey_shift);
-#endif
+
return pkey;
}
+#endif
static inline bool __pkru_allows_pkey(u16 pkey, bool write)
{
diff -puN include/linux/pkeys.h~pkeys-85-mprotect_pkey include/linux/pkeys.h
--- a/include/linux/pkeys.h~pkeys-85-mprotect_pkey 2015-12-03 16:21:30.183877985 -0800
+++ b/include/linux/pkeys.h 2015-12-03 16:21:30.190878302 -0800
@@ -2,10 +2,10 @@
#define _LINUX_PKEYS_H
#include <linux/mm_types.h>
-#include <asm/mmu_context.h>
#ifdef CONFIG_ARCH_HAS_PKEYS
#include <asm/pkeys.h>
+#include <asm/mmu_context.h>
#else /* ! CONFIG_ARCH_HAS_PKEYS */
/*
@@ -17,6 +17,11 @@ static inline bool arch_validate_pkey(in
{
return true;
}
+
+static inline int vma_pkey(struct vm_area_struct *vma)
+{
+ return 0;
+}
#endif /* ! CONFIG_ARCH_HAS_PKEYS */
#endif /* _LINUX_PKEYS_H */
diff -puN mm/Kconfig~pkeys-85-mprotect_pkey mm/Kconfig
--- a/mm/Kconfig~pkeys-85-mprotect_pkey 2015-12-03 16:21:30.185878075 -0800
+++ b/mm/Kconfig 2015-12-03 16:21:30.190878302 -0800
@@ -673,3 +673,10 @@ config ARCH_USES_HIGH_VMA_FLAGS
bool
config ARCH_HAS_PKEYS
bool
+
+config NR_PROTECTION_KEYS
+ int
+ # Everything supports a _single_ key, so allow folks to
+ # at least call APIs that take keys, but require that the
+ # key be 0.
+ default 1
diff -puN mm/mprotect.c~pkeys-85-mprotect_pkey mm/mprotect.c
--- a/mm/mprotect.c~pkeys-85-mprotect_pkey 2015-12-03 16:21:30.186878121 -0800
+++ b/mm/mprotect.c 2015-12-03 16:21:30.191878347 -0800
@@ -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>
@@ -344,10 +345,13 @@ fail:
return error;
}
-SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
- unsigned long, prot)
+/*
+ * pkey=-1 when doing a legacy mprotect()
+ */
+static int do_mprotect_pkey(unsigned long start, size_t len,
+ unsigned long prot, int pkey)
{
- 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);
@@ -373,8 +377,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);
@@ -407,7 +409,14 @@ SYSCALL_DEFINE3(mprotect, unsigned long,
/* Here we know that vma->vm_start <= nstart < vma->vm_end. */
- newflags = vm_flags;
+ /*
+ * If this is a vanilla, non-pkey mprotect, inherit the
+ * pkey from the VMA we are working on.
+ */
+ if (pkey == -1)
+ newflags = calc_vm_prot_bits(prot, vma_pkey(vma));
+ else
+ 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_% */
@@ -443,3 +452,18 @@ out:
up_write(¤t->mm->mmap_sem);
return error;
}
+
+SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
+ unsigned long, prot)
+{
+ return do_mprotect_pkey(start, len, prot, -1);
+}
+
+SYSCALL_DEFINE4(pkey_mprotect, unsigned long, start, size_t, len,
+ unsigned long, prot, int, pkey)
+{
+ if (!arch_validate_pkey(pkey))
+ return -EINVAL;
+
+ return do_mprotect_pkey(start, len, prot, pkey);
+}
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
Page 1 of 3 [1] 2 3 Next page →
Back to top | Article view | linux.kernel
csiph-web