-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[libc] Implement pkey_alloc/free/get/set/mprotect for x86_64 linux #162362
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-libc Author: Jackson Stogel (jtstogel) ChangesThis patch provides definitions for
This is my first addition to LLVM libc. It's likely I've missed something that needs updating -- ample feedback is welcome! Patch is 30.82 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/162362.diff 22 Files Affected:
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 87b78a337b875..4c56d23d96877 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -264,6 +264,11 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.mman.munlock
libc.src.sys.mman.munlockall
libc.src.sys.mman.munmap
+ libc.src.sys.mman.pkey_alloc
+ libc.src.sys.mman.pkey_free
+ libc.src.sys.mman.pkey_get
+ libc.src.sys.mman.pkey_mprotect
+ libc.src.sys.mman.pkey_set
libc.src.sys.mman.remap_file_pages
libc.src.sys.mman.posix_madvise
libc.src.sys.mman.shm_open
diff --git a/libc/src/sys/mman/CMakeLists.txt b/libc/src/sys/mman/CMakeLists.txt
index 4d4c2ad376050..c7be1eddacb5e 100644
--- a/libc/src/sys/mman/CMakeLists.txt
+++ b/libc/src/sys/mman/CMakeLists.txt
@@ -86,6 +86,41 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.msync
)
+add_entrypoint_object(
+ pkey_alloc
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.pkey_alloc
+)
+
+add_entrypoint_object(
+ pkey_free
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.pkey_free
+)
+
+add_entrypoint_object(
+ pkey_get
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.pkey_get
+)
+
+add_entrypoint_object(
+ pkey_mprotect
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.pkey_mprotect
+)
+
+add_entrypoint_object(
+ pkey_set
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.pkey_set
+)
+
add_entrypoint_object(
remap_file_pages
ALIAS
diff --git a/libc/src/sys/mman/linux/CMakeLists.txt b/libc/src/sys/mman/linux/CMakeLists.txt
index 7181bb98a187f..1c79180cbcabb 100644
--- a/libc/src/sys/mman/linux/CMakeLists.txt
+++ b/libc/src/sys/mman/linux/CMakeLists.txt
@@ -1,3 +1,10 @@
+add_subdirectory(generic)
+set(ARCH_SUBDIRECTORY generic)
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
+ add_subdirectory(${LIBC_TARGET_ARCHITECTURE})
+ set(ARCH_SUBDIRECTORY ${LIBC_TARGET_ARCHITECTURE})
+endif()
+
add_entrypoint_object(
madvise
SRCS
@@ -166,6 +173,74 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ pkey_alloc
+ SRCS
+ pkey_alloc.cpp
+ HDRS
+ ../pkey_alloc.h
+ DEPENDS
+ libc.include.sys_mman
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ pkey_free
+ SRCS
+ pkey_free.cpp
+ HDRS
+ ../pkey_free.h
+ DEPENDS
+ libc.include.sys_mman
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ pkey_get
+ SRCS
+ pkey_get.cpp
+ HDRS
+ ../pkey_get.h
+ DEPENDS
+ libc.include.sys_mman
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+ .${ARCH_SUBDIRECTORY}.pkey_common
+)
+
+add_entrypoint_object(
+ pkey_mprotect
+ SRCS
+ pkey_mprotect.cpp
+ HDRS
+ ../pkey_mprotect.h
+ DEPENDS
+ libc.include.sys_mman
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.sys.mman.mprotect
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ pkey_set
+ SRCS
+ pkey_set.cpp
+ HDRS
+ ../pkey_set.h
+ DEPENDS
+ libc.include.sys_mman
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+ .${ARCH_SUBDIRECTORY}.pkey_common
+)
+
add_entrypoint_object(
remap_file_pages
SRCS
diff --git a/libc/src/sys/mman/linux/generic/CMakeLists.txt b/libc/src/sys/mman/linux/generic/CMakeLists.txt
new file mode 100644
index 0000000000000..42b6d96c8387e
--- /dev/null
+++ b/libc/src/sys/mman/linux/generic/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_header_library(
+ pkey_common
+ HDRS
+ pkey_common.h
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.src.__support.common
+ libc.src.__support.error_or
+)
diff --git a/libc/src/sys/mman/linux/generic/pkey_common.h b/libc/src/sys/mman/linux/generic/pkey_common.h
new file mode 100644
index 0000000000000..0811cfb77d4b0
--- /dev/null
+++ b/libc/src/sys/mman/linux/generic/pkey_common.h
@@ -0,0 +1,25 @@
+#ifndef LLVM_SYS_MMAN_LINUX_GENERIC_PKEY_COMMON_H_
+#define LLVM_SYS_MMAN_LINUX_GENERIC_PKEY_COMMON_H_
+
+#include "hdr/errno_macros.h" // For ENOSYS
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace pkey_common {
+
+LIBC_INLINE ErrorOr<int> pkey_get(int pkey) {
+ (void)pkey;
+ return Error(ENOSYS);
+}
+
+LIBC_INLINE ErrorOr<int> pkey_set(int pkey, unsigned int access_rights) {
+ (void)pkey;
+ (void)access_rights;
+ return Error(ENOSYS);
+}
+
+} // namespace pkey_common
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_SYS_MMAN_LINUX_GENERIC_PKEY_COMMON_H_
diff --git a/libc/src/sys/mman/linux/pkey_alloc.cpp b/libc/src/sys/mman/linux/pkey_alloc.cpp
new file mode 100644
index 0000000000000..baf32013bc5c7
--- /dev/null
+++ b/libc/src/sys/mman/linux/pkey_alloc.cpp
@@ -0,0 +1,37 @@
+//===---------- Linux implementation of the Linux pkey_alloc function -----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/mman/pkey_alloc.h"
+
+#include "hdr/errno_macros.h" // For ENOSYS
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, pkey_alloc,
+ (unsigned int flags, unsigned int access_rights)) {
+#if !defined(SYS_pkey_alloc)
+ libc_errno = ENOSYS;
+ return -1;
+#else
+ int ret =
+ LIBC_NAMESPACE::syscall_impl<int>(SYS_pkey_alloc, flags, access_rights);
+ if (ret < 0) {
+ libc_errno = static_cast<int>(-ret);
+ return -1;
+ }
+ return static_cast<int>(ret);
+#endif
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/mman/linux/pkey_free.cpp b/libc/src/sys/mman/linux/pkey_free.cpp
new file mode 100644
index 0000000000000..0228971bd10f6
--- /dev/null
+++ b/libc/src/sys/mman/linux/pkey_free.cpp
@@ -0,0 +1,35 @@
+//===---------- Linux implementation of the Linux pkey_free function ------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/mman/pkey_free.h"
+
+#include "hdr/errno_macros.h" // For ENOSYS
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, pkey_free, (int pkey)) {
+#if !defined(SYS_pkey_free)
+ libc_errno = ENOSYS;
+ return -1;
+#else
+ int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_pkey_free, pkey);
+ if (ret < 0) {
+ libc_errno = static_cast<int>(-ret);
+ return -1;
+ }
+ return 0;
+#endif
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/mman/linux/pkey_get.cpp b/libc/src/sys/mman/linux/pkey_get.cpp
new file mode 100644
index 0000000000000..623b7930c7a23
--- /dev/null
+++ b/libc/src/sys/mman/linux/pkey_get.cpp
@@ -0,0 +1,35 @@
+//===---------- Linux implementation of the Linux pkey_mprotect function --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/mman/pkey_get.h"
+
+#include "hdr/errno_macros.h" // For ENOSYS
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/architectures.h"
+
+#if defined(LIBC_TARGET_ARCH_IS_X86_64)
+#include "src/sys/mman/linux/x86_64/pkey_common.h"
+#else
+#include "src/sys/mman/linux/generic/pkey_common.h"
+#endif
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, pkey_get, (int pkey)) {
+ ErrorOr<int> ret = LIBC_NAMESPACE::pkey_common::pkey_get(pkey);
+ if (!ret.has_value()) {
+ libc_errno = ret.error();
+ return -1;
+ }
+ return ret.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/mman/linux/pkey_mprotect.cpp b/libc/src/sys/mman/linux/pkey_mprotect.cpp
new file mode 100644
index 0000000000000..15c5d9db39b33
--- /dev/null
+++ b/libc/src/sys/mman/linux/pkey_mprotect.cpp
@@ -0,0 +1,45 @@
+//===---------- Linux implementation of the Linux pkey_mprotect function --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/mman/pkey_mprotect.h"
+
+#include "hdr/errno_macros.h" // For ENOSYS
+#include "hdr/types/size_t.h"
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/sys/mman/mprotect.h"
+
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, pkey_mprotect,
+ (void *addr, size_t len, int prot, int pkey)) {
+ // Fall back to mprotect if pkey is -1
+ // to maintain compatibility with kernel versions that don't support pkey.
+ if (pkey == -1) {
+ return LIBC_NAMESPACE::mprotect(addr, len, prot);
+ }
+
+#if !defined(SYS_pkey_mprotect)
+ libc_errno = ENOSYS;
+ return -1;
+#else
+ int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_pkey_mprotect, addr, len,
+ prot, pkey);
+ if (ret < 0) {
+ libc_errno = -ret;
+ return -1;
+ }
+ return 0;
+#endif
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/mman/linux/pkey_set.cpp b/libc/src/sys/mman/linux/pkey_set.cpp
new file mode 100644
index 0000000000000..7921443f688d3
--- /dev/null
+++ b/libc/src/sys/mman/linux/pkey_set.cpp
@@ -0,0 +1,35 @@
+//===---------- Linux implementation of the Linux pkey_mprotect function --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/mman/pkey_set.h"
+
+#include "hdr/errno_macros.h" // For ENOSYS
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+
+#if defined(LIBC_TARGET_ARCH_IS_X86_64)
+#include "src/sys/mman/linux/x86_64/pkey_common.h"
+#else
+#include "src/sys/mman/linux/generic/pkey_common.h"
+#endif
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, pkey_set, (int pkey, unsigned int access_rights)) {
+ ErrorOr<int> ret = LIBC_NAMESPACE::pkey_common::pkey_set(pkey, access_rights);
+ if (!ret.has_value()) {
+ libc_errno = ret.error();
+ return -1;
+ }
+ return ret.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/mman/linux/x86_64/CMakeLists.txt b/libc/src/sys/mman/linux/x86_64/CMakeLists.txt
new file mode 100644
index 0000000000000..1ce23af6dbd2a
--- /dev/null
+++ b/libc/src/sys/mman/linux/x86_64/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_header_library(
+ pkey_common
+ HDRS
+ pkey_common.h
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.stdint_proxy
+ libc.src.__support.common
+ libc.src.__support.error_or
+)
diff --git a/libc/src/sys/mman/linux/x86_64/pkey_common.h b/libc/src/sys/mman/linux/x86_64/pkey_common.h
new file mode 100644
index 0000000000000..bffa9feaed06c
--- /dev/null
+++ b/libc/src/sys/mman/linux/x86_64/pkey_common.h
@@ -0,0 +1,71 @@
+#ifndef LLVM_SYS_MMAN_LINUX_X86_64_PKEY_COMMON_H_
+#define LLVM_SYS_MMAN_LINUX_X86_64_PKEY_COMMON_H_
+
+#include "hdr/errno_macros.h" // For ENOSYS
+#include "hdr/stdint_proxy.h"
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+
+#if !defined(LIBC_TARGET_ARCH_IS_X86_64)
+#error "Invalid include"
+#endif
+
+namespace LIBC_NAMESPACE_DECL {
+namespace pkey_common {
+namespace internal {
+
+constexpr int MAX_KEY = 15;
+constexpr int KEY_MASK = 0x3;
+constexpr int BITS_PER_KEY = 2;
+
+// This will SIGILL on CPUs that don't support PKU / OSPKE,
+// but this case should never be reached as a prior pkey_alloc invocation
+// would have failed more gracefully.
+LIBC_INLINE uint32_t read_prku() {
+ uint32_t pkru = 0;
+ uint32_t edx = 0;
+ LIBC_INLINE_ASM("rdpkru" : "=a"(pkru), "=d"(edx) : "c"(0));
+ return pkru;
+}
+
+// This will SIGILL on CPUs that don't support PKU / OSPKE,
+// but this case should never be reached as a prior pkey_alloc invocation
+// would have failed more gracefully.
+LIBC_INLINE void write_prku(uint32_t pkru) {
+ LIBC_INLINE_ASM("wrpkru" : : "a"(pkru), "d"(0), "c"(0));
+}
+
+} // namespace internal
+
+// x86_64 implementation of pkey_get.
+// Returns the access rights for the given pkey on success, errno otherwise.
+LIBC_INLINE ErrorOr<int> pkey_get(int pkey) {
+ if (pkey < 0 || pkey > internal::MAX_KEY) {
+ return Error(EINVAL);
+ }
+
+ uint32_t pkru = internal::read_prku();
+ return (pkru >> (pkey * internal::BITS_PER_KEY)) & internal::KEY_MASK;
+}
+
+// x86_64 implementation of pkey_set.
+// Returns 0 on success, errno otherwise.
+LIBC_INLINE ErrorOr<int> pkey_set(int pkey, unsigned int access_rights) {
+ if (pkey < 0 || pkey > internal::MAX_KEY ||
+ access_rights > internal::KEY_MASK) {
+ return Error(EINVAL);
+ }
+
+ uint32_t pkru = internal::read_prku();
+ pkru &= ~(internal::KEY_MASK << (pkey * internal::BITS_PER_KEY));
+ pkru |=
+ ((access_rights & internal::KEY_MASK) << (pkey * internal::BITS_PER_KEY));
+ internal::write_prku(pkru);
+
+ return 0;
+}
+
+} // namespace pkey_common
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_SYS_MMAN_LINUX_X86_64_PKEY_COMMON_H_
diff --git a/libc/src/sys/mman/pkey_alloc.h b/libc/src/sys/mman/pkey_alloc.h
new file mode 100644
index 0000000000000..c63c6a36c8021
--- /dev/null
+++ b/libc/src/sys/mman/pkey_alloc.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pkey_alloc function -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_MMAN_PKEY_ALLOC_H
+#define LLVM_LIBC_SRC_SYS_MMAN_PKEY_ALLOC_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pkey_alloc(unsigned int flags, unsigned int access_rights);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_MMAN_PKEY_ALLOC_H
diff --git a/libc/src/sys/mman/pkey_free.h b/libc/src/sys/mman/pkey_free.h
new file mode 100644
index 0000000000000..a357e9b8c847b
--- /dev/null
+++ b/libc/src/sys/mman/pkey_free.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pkey_free function ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_MMAN_PKEY_FREE_H
+#define LLVM_LIBC_SRC_SYS_MMAN_PKEY_FREE_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pkey_free(int pkey);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_MMAN_PKEY_FREE_H
diff --git a/libc/src/sys/mman/pkey_get.h b/libc/src/sys/mman/pkey_get.h
new file mode 100644
index 0000000000000..d41afe08ae371
--- /dev/null
+++ b/libc/src/sys/mman/pkey_get.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pkey_get function -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_MMAN_PKEY_GET_H
+#define LLVM_LIBC_SRC_SYS_MMAN_PKEY_GET_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pkey_get(int pkey);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_MMAN_PKEY_GET_H
diff --git a/libc/src/sys/mman/pkey_mprotect.h b/libc/src/sys/mman/pkey_mprotect.h
new file mode 100644
index 0000000000000..4d19348ef09db
--- /dev/null
+++ b/libc/src/sys/mman/pkey_mprotect.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for pkey_mprotect function --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_MMAN_PKEY_MPROTECT_H
+#define LLVM_LIBC_SRC_SYS_MMAN_PKEY_MPROTECT_H
+
+#include "src/__support/macros/config.h"
+#include "hdr/types/size_t.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pkey_mprotect(void *addr, size_t len, int prot, int pkey);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_MMAN_PKEY_MPROTECT_H
diff --git a/libc/src/sys/mman/pkey_set.h b/libc/src/sys/mman/pkey_set.h
new file mode 100644
index 0000000000000..55bafbd11d709
--- /dev/null
+++ b/libc/src/sys/mman/pkey_set.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pkey_set function -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_MMAN_PKEY_SET_H
+#define LLVM_LIBC_SRC_SYS_MMAN_PKEY_SET_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pkey_set(int pkey, unsigned int access_rights);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_MMAN_PKEY_SET_H
diff --git a/libc/test/src/sys/mman/linux/CMakeLists.txt b/libc/test/src/sys/mman/linux/CMakeLists.txt
index a362c1cf61cbc..721f89961f7c0 100644
--- a/libc/test/src/sys/mman/linux/CMakeLists.txt
+++ b/libc/test/src/sys/mman/linux/CMakeLists.txt
@@ -67,6 +67,27 @@ add_libc_unittest(
)
+add_libc_unittest(
+ pkey_test
+ SUITE
+ libc_sys_mman_unittests
+ SRCS
+ pkey_test.cpp
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.signal_macros
+ libc.hdr.types.size_t
+ libc.src.sys.mman.mmap
+ libc.src.sys.mman.munmap
+ libc.src.sys.mman.pkey_alloc
+ libc.src.sys.mman.pkey_free
+ libc.src.sys.mman.pkey_get
+ libc.src.sys.mman.pkey_mprotect
+ libc.src.sys.mman.pkey_set
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
+
add_libc_unittest(
posix_madvise_test
SUITE
diff --git a/libc/test/src/sys/mman/linux/pkey_test.cpp b/libc/test/src/sys/mman/linux/pkey_test.cpp
new file mode 100644
index 0000000000000..9c6feae2d457b
--- /dev/null
+++ b/libc/test/src/sys/mman/linux/pkey_test.cpp
@@ -0,0 +1,241 @@
+//===-- Unit tests for pkey functions -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall this looks good, but you need to update the headergen file in include/sys/mman.yaml
LIBC_INLINE uint32_t read_prku() { | ||
uint32_t pkru = 0; | ||
uint32_t edx = 0; | ||
LIBC_INLINE_ASM("rdpkru" : "=a"(pkru), "=d"(edx) : "c"(0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we migrating back to the macro approach for ASM?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't realize there was a preference. Switched to use asm volatile
directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For setjmp/longjmp we used [[gnu::naked]]
so that the whole function was assembly. I'd need to dig up the discussion but I'd say either is probably fine in this case.
namespace pkey_common { | ||
|
||
LIBC_INLINE ErrorOr<int> pkey_get(int pkey) { | ||
(void)pkey; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use [[maybe_unused]]
on pkey
declaration instead.
return Error(ENOSYS); | ||
} | ||
|
||
LIBC_INLINE ErrorOr<int> pkey_set(int pkey, unsigned int access_rights) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use [[maybe_unused]]
instead of (void)
// Fall back to mprotect if pkey is -1 | ||
// to maintain compatibility with kernel versions that don't support pkey. | ||
if (pkey == -1) { | ||
return LIBC_NAMESPACE::mprotect(addr, len, prot); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this entrypoint dependency be broken up?
LIBC_INLINE uint32_t read_prku() { | ||
uint32_t pkru = 0; | ||
uint32_t edx = 0; | ||
asm volatile("rdpkru" : "=a"(pkru), "=d"(edx) : "c"(0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think clang has a builtin for this: https://github.com/llvm/llvm-project/blob/main/clang/lib/Headers/pkuintrin.h
// but this case should never be reached as a prior pkey_alloc invocation | ||
// would have failed more gracefully. | ||
LIBC_INLINE void write_prku(uint32_t pkru) { | ||
asm volatile("wrpkru" : : "a"(pkru), "d"(0), "c"(0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang probably has builtin for this: https://github.com/llvm/llvm-project/blob/main/clang/lib/Headers/pkuintrin.h
} | ||
|
||
uint32_t pkru = internal::read_prku(); | ||
return (pkru >> (pkey * internal::BITS_PER_KEY)) & internal::KEY_MASK; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it possible to overflow on this shift?
pkru &= ~(internal::KEY_MASK << (pkey * internal::BITS_PER_KEY)); | ||
pkru |= | ||
((access_rights & internal::KEY_MASK) << (pkey * internal::BITS_PER_KEY)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similar question about potential overflow here.
libc.test.UnitTest.ErrnoCheckingTest | ||
libc.test.UnitTest.ErrnoSetterMatcher |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we don't need these any more, right @vonosmas ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we do? At least I didn't remember making any changes that would make these dependencies added automatically.
This patch provides definitions for
pkey_*
functions for linux x86_64.alloc
,free
, andmprotect
are simple syscall wrappers.pkey_set
andpkey_get
modify architecture-specific registers. The logic for these live in architecture specific directories:libc/src/sys/mman/linux/x86_64/pkey_common.h
has a real implementationlibc/src/sys/mman/linux/generic/pkey_common.h
contains stubs that just returnENOSYS
.This is my first addition to LLVM libc. It's likely I've missed something that needs updating -- ample feedback is welcome!