lkml.org 
[lkml]   [2022]   [Apr]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH V10 14/44] mm/pkeys: Introduce pks_set_readwrite()
Date
From: Ira Weiny <ira.weiny@intel.com>

When kernel code needs access to a PKS protected page they will need to
change the protections for the pkey to Read/Write.

Define pks_set_readwrite() to update the specified pkey. Define
pks_update_protection() as a helper to do the heavy lifting and allow
for subsequent pks_set_*() calls.

Define PKEY_READ_WRITE rather than use a magic value of '0' in
pks_update_protection().

Finally, ensure preemption is disabled for pks_write_pkrs() because the
context of this call can not generally be predicted.

pks.h is created to avoid conflicts and header dependencies with the
user space pkey code.

Add documentation.

Signed-off-by: Ira Weiny <ira.weiny@intel.com>

---
changes for v9
Move MSR documentation note to this patch
move declarations to incline/linux/pks.h
from rick edgecombe
change pkey type to u8
validate pkey range in pks_update_protection
from 0day
fix documentation link
from dave hansen
s/pks_mk_*/pks_set_*/
use pkey
s/pks_saved_pkrs/pkrs/

changes for v8
define pkey_read_write
make the call inline
clean up the names
use pks_write_pkrs() with preemption disabled
split this out from 'add pks kernel api'
include documentation in this patch
---
Documentation/core-api/protection-keys.rst | 15 +++++++++++
arch/x86/mm/pkeys.c | 31 ++++++++++++++++++++++
include/linux/pks.h | 31 ++++++++++++++++++++++
include/uapi/asm-generic/mman-common.h | 1 +
4 files changed, 78 insertions(+)
create mode 100644 include/linux/pks.h

diff --git a/Documentation/core-api/protection-keys.rst b/Documentation/core-api/protection-keys.rst
index fe63acf5abbe..3af92e1cbffd 100644
--- a/Documentation/core-api/protection-keys.rst
+++ b/Documentation/core-api/protection-keys.rst
@@ -142,3 +142,18 @@ Adding pages to a pkey protected domain

.. kernel-doc:: arch/x86/include/asm/pgtable_types.h
:doc: PKS_KEY_ASSIGNMENT
+
+Changing permissions of individual keys
+---------------------------------------
+
+.. kernel-doc:: include/linux/pks.h
+ :identifiers: pks_set_readwrite
+
+MSR details
+~~~~~~~~~~~
+
+WRMSR is typically an architecturally serializing instruction. However,
+WRMSR(MSR_IA32_PKRS) is an exception. It is not a serializing instruction and
+instead maintains ordering properties similar to WRPKRU. Thus it is safe to
+immediately use a mapping when the pks_set*() functions returns. Check the
+latest SDM for details.
diff --git a/arch/x86/mm/pkeys.c b/arch/x86/mm/pkeys.c
index 39e4c2cbc279..e4cbc79686ea 100644
--- a/arch/x86/mm/pkeys.c
+++ b/arch/x86/mm/pkeys.c
@@ -6,6 +6,7 @@
#include <linux/debugfs.h> /* debugfs_create_u32() */
#include <linux/mm_types.h> /* mm_struct, vma, etc... */
#include <linux/pkeys.h> /* PKEY_* */
+#include <linux/pks.h>
#include <linux/pks-keys.h>
#include <uapi/asm-generic/mman-common.h>

@@ -275,4 +276,34 @@ void pks_setup(void)
cr4_set_bits(X86_CR4_PKS);
}

+/*
+ * Do not call this directly, see pks_set*().
+ *
+ * @pkey: Key for the domain to change
+ * @protection: protection bits to be used
+ *
+ * Protection utilizes the same protection bits specified for User pkeys
+ * PKEY_DISABLE_ACCESS
+ * PKEY_DISABLE_WRITE
+ *
+ */
+void pks_update_protection(u8 pkey, u8 protection)
+{
+ u32 pkrs;
+
+ if (!cpu_feature_enabled(X86_FEATURE_PKS))
+ return;
+
+ if (WARN_ON_ONCE(pkey >= PKS_KEY_MAX))
+ return;
+
+ pkrs = current->thread.pkrs;
+ current->thread.pkrs = pkey_update_pkval(pkrs, pkey,
+ protection);
+ preempt_disable();
+ pks_write_pkrs(current->thread.pkrs);
+ preempt_enable();
+}
+EXPORT_SYMBOL_GPL(pks_update_protection);
+
#endif /* CONFIG_ARCH_ENABLE_SUPERVISOR_PKEYS */
diff --git a/include/linux/pks.h b/include/linux/pks.h
new file mode 100644
index 000000000000..8b705a937b19
--- /dev/null
+++ b/include/linux/pks.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_PKS_H
+#define _LINUX_PKS_H
+
+#ifdef CONFIG_ARCH_ENABLE_SUPERVISOR_PKEYS
+
+#include <linux/types.h>
+
+#include <uapi/asm-generic/mman-common.h>
+
+void pks_update_protection(u8 pkey, u8 protection);
+
+/**
+ * pks_set_readwrite() - Make the domain Read/Write
+ * @pkey: the pkey for which the access should change.
+ *
+ * Allow all access, read and write, to the domain specified by pkey. This is
+ * not a global update and only affects the current running thread.
+ */
+static inline void pks_set_readwrite(u8 pkey)
+{
+ pks_update_protection(pkey, PKEY_READ_WRITE);
+}
+
+#else /* !CONFIG_ARCH_ENABLE_SUPERVISOR_PKEYS */
+
+static inline void pks_set_readwrite(u8 pkey) {}
+
+#endif /* CONFIG_ARCH_ENABLE_SUPERVISOR_PKEYS */
+
+#endif /* _LINUX_PKS_H */
diff --git a/include/uapi/asm-generic/mman-common.h b/include/uapi/asm-generic/mman-common.h
index 6c1aa92a92e4..f179544bd33a 100644
--- a/include/uapi/asm-generic/mman-common.h
+++ b/include/uapi/asm-generic/mman-common.h
@@ -80,6 +80,7 @@
/* compatibility flags */
#define MAP_FILE 0

+#define PKEY_READ_WRITE 0x0
#define PKEY_DISABLE_ACCESS 0x1
#define PKEY_DISABLE_WRITE 0x2
#define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\
--
2.35.1
\
 
 \ /
  Last update: 2022-04-19 19:11    [W:0.858 / U:0.028 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site