Skip to content

Commit 30b1d22

Browse files
committed
Use instrinsics instead of asm. Don't depend on mprotect entrypoint.
1 parent e67b0c5 commit 30b1d22

File tree

12 files changed

+111
-60
lines changed

12 files changed

+111
-60
lines changed

libc/src/sys/mman/linux/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ add_entrypoint_object(
5757
libc.src.errno.errno
5858
)
5959

60+
add_header_library(
61+
mprotect_common
62+
HDRS
63+
mprotect_common.h
64+
DEPENDS
65+
libc.include.sys_syscall
66+
libc.src.__support.OSUtil.osutil
67+
libc.src.errno.errno
68+
libc.src.__support.error_or
69+
)
70+
6071
add_entrypoint_object(
6172
mprotect
6273
SRCS
@@ -68,6 +79,7 @@ add_entrypoint_object(
6879
libc.include.sys_syscall
6980
libc.src.__support.OSUtil.osutil
7081
libc.src.errno.errno
82+
.mprotect_common
7183
)
7284

7385
add_entrypoint_object(
@@ -225,6 +237,7 @@ add_entrypoint_object(
225237
libc.src.__support.OSUtil.osutil
226238
libc.src.sys.mman.mprotect
227239
libc.src.errno.errno
240+
.mprotect_common
228241
)
229242

230243
add_entrypoint_object(

libc/src/sys/mman/linux/generic/pkey_common.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,12 @@
1616
namespace LIBC_NAMESPACE_DECL {
1717
namespace pkey_common {
1818

19-
LIBC_INLINE ErrorOr<int> pkey_get(int pkey) {
20-
(void)pkey;
19+
LIBC_INLINE ErrorOr<int> pkey_get([[maybe_unused]] int pkey) {
2120
return Error(ENOSYS);
2221
}
2322

24-
LIBC_INLINE ErrorOr<int> pkey_set(int pkey, unsigned int access_rights) {
25-
(void)pkey;
26-
(void)access_rights;
23+
LIBC_INLINE ErrorOr<int> pkey_set([[maybe_unused]] int pkey,
24+
[[maybe_unused]] unsigned int access_rights) {
2725
return Error(ENOSYS);
2826
}
2927

libc/src/sys/mman/linux/mprotect.cpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,22 @@
1111
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
1212
#include "src/__support/common.h"
1313

14+
#include "src/__support/error_or.h"
1415
#include "src/__support/libc_errno.h"
1516
#include "src/__support/macros/config.h"
17+
#include "src/sys/mman/linux/mprotect_common.h"
1618
#include <sys/syscall.h> // For syscall numbers.
1719

1820
namespace LIBC_NAMESPACE_DECL {
1921

20-
// This function is currently linux only. It has to be refactored suitably if
21-
// mprotect is to be supported on non-linux operating systems also.
2222
LLVM_LIBC_FUNCTION(int, mprotect, (void *addr, size_t size, int prot)) {
23-
int ret = LIBC_NAMESPACE::syscall_impl<int>(
24-
SYS_mprotect, reinterpret_cast<long>(addr), size, prot);
25-
26-
// A negative return value indicates an error with the magnitude of the
27-
// value being the error code.
28-
if (ret < 0) {
29-
libc_errno = -ret;
23+
ErrorOr<int> result =
24+
LIBC_NAMESPACE::mprotect_common::mprotect_impl(addr, size, prot);
25+
if (!result.has_value()) {
26+
libc_errno = result.error();
3027
return -1;
3128
}
32-
33-
return 0;
29+
return result.value();
3430
}
3531

3632
} // namespace LIBC_NAMESPACE_DECL
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//===---------- Shared Linux implementation of POSIX mprotect. ------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/__support/common.h"
10+
#include "src/__support/error_or.h"
11+
#include "src/__support/libc_errno.h"
12+
#include "src/__support/macros/attributes.h"
13+
#include "src/__support/macros/config.h"
14+
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
15+
#include <sys/syscall.h> // For syscall numbers.
16+
17+
namespace LIBC_NAMESPACE_DECL {
18+
19+
namespace mprotect_common {
20+
21+
// This function is currently linux only. It has to be refactored suitably if
22+
// mprotect is to be supported on non-linux operating systems also.
23+
LIBC_INLINE ErrorOr<int> mprotect_impl(void *addr, size_t size, int prot) {
24+
int ret = LIBC_NAMESPACE::syscall_impl<int>(
25+
SYS_mprotect, reinterpret_cast<long>(addr), size, prot);
26+
27+
// A negative return value indicates an error with the magnitude of the
28+
// value being the error code.
29+
if (ret < 0) {
30+
return Error(-ret);
31+
}
32+
33+
return 0;
34+
}
35+
36+
} // namespace mprotect_common
37+
38+
} // namespace LIBC_NAMESPACE_DECL

libc/src/sys/mman/linux/pkey_alloc.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ LLVM_LIBC_FUNCTION(int, pkey_alloc,
2727
int ret =
2828
LIBC_NAMESPACE::syscall_impl<int>(SYS_pkey_alloc, flags, access_rights);
2929
if (ret < 0) {
30-
libc_errno = static_cast<int>(-ret);
30+
libc_errno = -ret;
3131
return -1;
3232
}
3333
return static_cast<int>(ret);

libc/src/sys/mman/linux/pkey_free.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ LLVM_LIBC_FUNCTION(int, pkey_free, (int pkey)) {
2525
#else
2626
int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_pkey_free, pkey);
2727
if (ret < 0) {
28-
libc_errno = static_cast<int>(-ret);
28+
libc_errno = -ret;
2929
return -1;
3030
}
3131
return 0;

libc/src/sys/mman/linux/pkey_get.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
#include "src/sys/mman/pkey_get.h"
1010

11-
#include "hdr/errno_macros.h" // For ENOSYS
1211
#include "src/__support/common.h"
1312
#include "src/__support/error_or.h"
1413
#include "src/__support/libc_errno.h"

libc/src/sys/mman/linux/pkey_mprotect.cpp

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,34 +12,47 @@
1212
#include "hdr/types/size_t.h"
1313
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
1414
#include "src/__support/common.h"
15+
#include "src/__support/error_or.h"
1516
#include "src/__support/libc_errno.h"
1617
#include "src/__support/macros/config.h"
17-
#include "src/sys/mman/mprotect.h"
18+
#include "src/sys/mman/linux/mprotect_common.h"
1819

1920
#include <sys/syscall.h> // For syscall numbers.
2021

2122
namespace LIBC_NAMESPACE_DECL {
23+
namespace internal {
2224

23-
LLVM_LIBC_FUNCTION(int, pkey_mprotect,
24-
(void *addr, size_t len, int prot, int pkey)) {
25+
LIBC_INLINE ErrorOr<int> pkey_mprotect_impl(void *addr, size_t len, int prot,
26+
int pkey) {
2527
// Fall back to mprotect if pkey is -1
2628
// to maintain compatibility with kernel versions that don't support pkey.
2729
if (pkey == -1) {
28-
return LIBC_NAMESPACE::mprotect(addr, len, prot);
30+
return LIBC_NAMESPACE::mprotect_common::mprotect_impl(addr, len, prot);
2931
}
3032

3133
#if !defined(SYS_pkey_mprotect)
32-
libc_errno = ENOSYS;
33-
return -1;
34+
return Error(ENOSYS);
3435
#else
3536
int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_pkey_mprotect, addr, len,
3637
prot, pkey);
3738
if (ret < 0) {
38-
libc_errno = -ret;
39-
return -1;
39+
return Error(-ret);
4040
}
4141
return 0;
4242
#endif
4343
}
4444

45+
} // namespace internal
46+
47+
LLVM_LIBC_FUNCTION(int, pkey_mprotect,
48+
(void *addr, size_t len, int prot, int pkey)) {
49+
ErrorOr<int> ret =
50+
LIBC_NAMESPACE::internal::pkey_mprotect_impl(addr, len, prot, pkey);
51+
if (!ret.has_value()) {
52+
libc_errno = ret.error();
53+
return -1;
54+
}
55+
return ret.value();
56+
}
57+
4558
} // namespace LIBC_NAMESPACE_DECL

libc/src/sys/mman/linux/pkey_set.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
#include "src/sys/mman/pkey_set.h"
1010

11-
#include "hdr/errno_macros.h" // For ENOSYS
1211
#include "src/__support/common.h"
1312
#include "src/__support/error_or.h"
1413
#include "src/__support/libc_errno.h"

libc/src/sys/mman/linux/x86_64/pkey_common.h

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#ifndef LLVM_SYS_MMAN_LINUX_X86_64_PKEY_COMMON_H_
1010
#define LLVM_SYS_MMAN_LINUX_X86_64_PKEY_COMMON_H_
1111

12+
#include <immintrin.h>
13+
1214
#include "hdr/errno_macros.h" // For ENOSYS
1315
#include "hdr/stdint_proxy.h"
1416
#include "src/__support/common.h"
@@ -20,55 +22,35 @@
2022

2123
namespace LIBC_NAMESPACE_DECL {
2224
namespace pkey_common {
23-
namespace internal {
2425

25-
constexpr int MAX_KEY = 15;
26+
constexpr int KEY_COUNT = 16;
2627
constexpr int KEY_MASK = 0x3;
2728
constexpr int BITS_PER_KEY = 2;
2829

29-
// This will SIGILL on CPUs that don't support PKU / OSPKE,
30-
// but this case should never be reached as a prior pkey_alloc invocation
31-
// would have failed more gracefully.
32-
LIBC_INLINE uint32_t read_prku() {
33-
uint32_t pkru = 0;
34-
uint32_t edx = 0;
35-
asm volatile("rdpkru" : "=a"(pkru), "=d"(edx) : "c"(0));
36-
return pkru;
37-
}
38-
39-
// This will SIGILL on CPUs that don't support PKU / OSPKE,
40-
// but this case should never be reached as a prior pkey_alloc invocation
41-
// would have failed more gracefully.
42-
LIBC_INLINE void write_prku(uint32_t pkru) {
43-
asm volatile("wrpkru" : : "a"(pkru), "d"(0), "c"(0));
44-
}
45-
46-
} // namespace internal
47-
4830
// x86_64 implementation of pkey_get.
4931
// Returns the access rights for the given pkey on success, errno otherwise.
32+
[[gnu::target("pku")]]
5033
LIBC_INLINE ErrorOr<int> pkey_get(int pkey) {
51-
if (pkey < 0 || pkey > internal::MAX_KEY) {
34+
if (pkey < 0 || pkey >= KEY_COUNT) {
5235
return Error(EINVAL);
5336
}
5437

55-
uint32_t pkru = internal::read_prku();
56-
return (pkru >> (pkey * internal::BITS_PER_KEY)) & internal::KEY_MASK;
38+
uint32_t pkru = _rdpkru_u32();
39+
return (pkru >> (pkey * BITS_PER_KEY)) & KEY_MASK;
5740
}
5841

5942
// x86_64 implementation of pkey_set.
6043
// Returns 0 on success, errno otherwise.
44+
[[gnu::target("pku")]]
6145
LIBC_INLINE ErrorOr<int> pkey_set(int pkey, unsigned int access_rights) {
62-
if (pkey < 0 || pkey > internal::MAX_KEY ||
63-
access_rights > internal::KEY_MASK) {
46+
if (pkey < 0 || pkey >= KEY_COUNT || access_rights > KEY_MASK) {
6447
return Error(EINVAL);
6548
}
6649

67-
uint32_t pkru = internal::read_prku();
68-
pkru &= ~(internal::KEY_MASK << (pkey * internal::BITS_PER_KEY));
69-
pkru |=
70-
((access_rights & internal::KEY_MASK) << (pkey * internal::BITS_PER_KEY));
71-
internal::write_prku(pkru);
50+
uint32_t pkru = _rdpkru_u32();
51+
pkru &= ~(KEY_MASK << (pkey * BITS_PER_KEY));
52+
pkru |= ((access_rights & KEY_MASK) << (pkey * BITS_PER_KEY));
53+
_wrpkru(pkru);
7254

7355
return 0;
7456
}

0 commit comments

Comments
 (0)