Hi All,
This patch series introduces the mm reservation interface to manage
the owning capability of the allocated addresses. This series adds reservation
details in the VMA structure and different capability/reservation constraint checks.
Looking for feedback regarding API names, directory structure etc.
Details about several rules implemented can be found in PCuABI spec here [1].
This series is based on tree [2].
Changes in this v2 as compared with v1(Based on suggestions from Kevin):
1) Separated the user pointer related helpers from reservation helpers
and added them in lib/user_ptr.c.
2) Added new helpers user_ptr_is_valid() and user_ptr_set_addr()
to reduce CONFIG_CHERI_PURECAP_UABI ifdefs.
3) Fixed max gap issues in unmapped_area_topdown().
4) Dropped patch "mm,fs: Use address as user_uintptr_t in generic get_unmapped_area()".
However, due to this get_unmapped_area() cannot be called for
MAP_FIXED type valid capabilities. A special sanity check function is created
vm_area_range_within_limit() and is to be used for sanity checks in
those cases.
5) Some fixes regarding adding reservation details in VMA merging/expansions.
6) A new patch "fs/binfmt_elf: Add PCuABI reservation constraints" is
added in this series to demostrate the use of API
reserv_range_set_reserv() and kernel mapping functions vm_mmap() and vm_munmap().
7) Some code fixes and cleanups as suggested by Kevin.
Future works:
1) Users of vm_mmap/vm_munmap() i.e. filesystems, vdso, exec stack to be
modified to preserve capability addresses.
2) Cover remaining memory addressing syscalls.
Testing:
1) All tests by Chaitanya in v3 selftests [3] passes.
2) Purecap/Compat Busybox boot passes after adding [WIP] patches present in [4].
The whole series can be found here [4].
[1]: https://git.morello-project.org/morello/kernel/linux/-/wikis/Morello-pure-c…
[2]: https://git.morello-project.org/morello/kernel/linux morello/next
[3]: https://git.morello-project.org/chaitanya_prakash/linux.git review/purecap_mmap_testcases_v8
[4]: https://git.morello-project.org/amitdaniel/linux.git review/purecap_mm_reservation_v2
Thanks,
Amit Daniel
Amit Daniel Kachhap (22):
uapi: errno.h: Introduce PCuABI memory reservation error
linux/sched/coredump.h: Add MMF_PCUABI_RESERV mm flag
mm/cap_addr_mgmt: Add capability reservation interfaces in VMA
linux/user_ptr.h: Add two helpers to operate on user pointers
lib/user_ptr: Add helpers to be used by mm syscalls
mm/(mmap,mremap): Modify unmapped address space management code
mm: Add and use PCuABI reservation during VMA operation
mm/mmap: Add reservation constraints in mmap/munmap parameters
mm/mremap: Add reservation constraints in mremap syscall
mm/mprotect: Add the PCuABI reservation constraints
mm/madvise: Add the PCuABI reservation constraints
mm/mlock: Add the PCuABI reservation constraints
mm/msync: Add the PCuABI reservation constraints
mm/mmap: Disable MAP_GROWSDOWN mapping flag for PCuABI
uapi: mman-common.h: Macros for maximum capability permissions
lib/user_ptr: Add user pointer permission helpers for PCuABI
arm64: user_ptr: Implement morello capability permission helpers
mm/mmap: Add capability permission constraints for PCuABI
mm/mremap: Add capability permission constraints for PCuABI
mm/mprotect: Add capability permission constraints for PCuABI
mm/mincore: Add PCuABI reservation/capability constraints
fs/binfmt_elf: Add PCuABI reservation constraints
Documentation/core-api/user_ptr.rst | 28 ++++
arch/Kconfig | 3 +
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/user_ptr.h | 33 ++++
fs/binfmt_elf.c | 100 ++++++++----
include/linux/cap_addr_mgmt.h | 217 +++++++++++++++++++++++++
include/linux/mm.h | 19 ++-
include/linux/mm_types.h | 9 +
include/linux/sched/coredump.h | 2 +
include/linux/user_ptr.h | 101 ++++++++++++
include/uapi/asm-generic/errno.h | 2 +
include/uapi/asm-generic/mman-common.h | 6 +
io_uring/advise.c | 2 +-
kernel/fork.c | 3 +
lib/user_ptr.c | 93 +++++++++++
mm/Makefile | 2 +-
mm/cap_addr_mgmt.c | 152 +++++++++++++++++
mm/damon/vaddr.c | 2 +-
mm/madvise.c | 26 ++-
mm/mincore.c | 46 +++++-
mm/mlock.c | 36 +++-
mm/mmap.c | 207 +++++++++++++++++++----
mm/mprotect.c | 26 ++-
mm/mremap.c | 122 +++++++++++---
mm/msync.c | 13 +-
mm/util.c | 16 +-
26 files changed, 1137 insertions(+), 130 deletions(-)
create mode 100644 arch/arm64/include/asm/user_ptr.h
create mode 100644 include/linux/cap_addr_mgmt.h
create mode 100644 mm/cap_addr_mgmt.c
--
2.25.1
Syscalls operating on memory mappings manage their address space via
owning capabilities. They must adhere to a certain set of rules[1] in
order to ensure memory safety. Address space management syscalls are
only allowed to manipulate mappings that are within the range of the
owning capability and have appropriate permissions.
Tests to validate the capability's tag, bounds, range as well as
permissions have been added. As certain flags and syscalls
conflict with the reservation model or lack implementation, a check
to verify appropriate handling of the same has also been added. Lastly,
testcases to verify mmap/unmap of CHERI unreprentable address/length
have been added.
Review branch:
https://git.morello-project.org/chaitanya_prakash/linux/-/tree/review/morel…
This patch series has been tested on:
https://git.morello-project.org/amitdaniel/linux/-/tree/review/purecap_mm_r…
[1]https://git.morello-project.org/morello/kernel/linux/-/wikis/Morello-pure…
Changes in V7:
- Modified the do-while loop used to generate unrepresentable address/length
- Added tag validity check for test_cheri_representability()
- Corrected representable_base such that the value is computed using
address rather than the base
- Updated commit messages
Changes in V6:
https://op-lists.linaro.org/archives/list/linux-morello@op-lists.linaro.org…
- Updated commit messages and in code comments as required.
- Moved struct initial_data back to bootstrap.c
- Defined __maybe_unused in freestanding.h
- Defined a fixed address to be shared among the tests.
- Modified negative madvise() test to make use of the common private
mapping.
- Renamed test_mmap_bounds_check and test_mremap_bounds_check testcases
to test_check_mmap_reservation and test_check_mremap_reservation
respectively.
- Modified the do-while loop used to generate unrepresentable
length/address.
- Added checks to validate that the bounds and length of ptr1 and ptr2
are of cheri representable length and their base is aligned according
to the alignment mask.
- Added a test to ensure mmap(owning_cap,..., MAP_FIXED fails if the
underlying reservation has been destroyed.
Changes in V5:
https://op-lists.linaro.org/archives/list/linux-morello@op-lists.linaro.org…
- Added representability testcase.
- Removed global struct reg_data and called get_pagesize() with auxv
passed in main().
- Removed VERIFY_ERRNO macro and made use of extended EXPECT_EQ
- As helper functions have been removed, the inline attribute line is of
no use and has been deleted.
- Used a common mapping to avoid creating and destroying mappings
repeatedly.
- Removed positive testcases as they are not unique to PCuABI
- Corrected the error code to reflect -ENOMEM instead of -ERESERVATION
when mremap() tries to move a mapping without MREMAP_MAYMOVE flag
- Reworded commit messages and restructured code.
Changes in V4:
https://op-lists.linaro.org/archives/list/linux-morello@op-lists.linaro.org…
-Corrected subject of cover letter
Changes in V3:
https://op-lists.linaro.org/archives/list/linux-morello@op-lists.linaro.org…
- Added get_pagesize() function and VERRIFY_ERRNO() macro
- Added LoadCap and StoreCap permissions testcase
- Added validity_tag_check testcases
- Added reservation tests
- Renamed variable "addr" to "ptr" to avoid confusion when manipulating
both addresses and capabilities
- Cleaned up syscall_mmap and syscall_mmap2 testcases
- Restructured code into testcases that check tags, range, bounds
and permissions
- Improved range_check testcases
- Improved commit messages
- Removed helper functions, tests directly written in testcase functions
- Removed signal handling and ddc register testcases
Changes in V2:
https://op-lists.linaro.org/archives/list/linux-morello@op-lists.linaro.org…
- Added link to the review branch
- Removed unnecessary whitespace
Changes in V1:
https://op-lists.linaro.org/archives/list/linux-morello@op-lists.linaro.org…
Amit Daniel Kachhap (1):
kselftests/arm64: morello: mmap: Test unrepresentable addresses
Chaitanya S Prakash (10):
kselftests/arm64: morello: Create wrapper functions for frequently
invoked syscalls
kselftests/arm64: morello: Add get_pagesize() function
kselftests/arm64: morello: mmap: Clean up existing testcases
kselftests/arm64: morello: mmap: Add MAP_GROWSDOWN testcase
kselftests/arm64: morello: mmap: Add validity tag check testcases
kselftests/arm64: morello: mmap: Add capability range testcases
kselftests/arm64: morello: mmap: Add mmap() reservation testcases
kselftests/arm64: morello: mmap: Add mremap() reservation check
testcases
kselftests/arm64: morello: mmap: Add permission check testcases
kselftests/arm64: morello: mmap: Add brk() testcase
.../selftests/arm64/morello/bootstrap.c | 6 -
.../selftests/arm64/morello/freestanding.c | 15 +
.../selftests/arm64/morello/freestanding.h | 68 ++-
tools/testing/selftests/arm64/morello/mmap.c | 552 +++++++++++++++++-
4 files changed, 603 insertions(+), 38 deletions(-)
--
2.34.1
A few tests currently create temporary files in / to obtain an fd
for testing further syscalls. This is suboptimal as these files may
be used for other purposes, they are not deleted after the tests are
run, and we should generally avoid creating files at the root.
We could create files in /tmp instead, with some naming pattern à la
mkstemp(), but it turns out there is an even simpler solution.
open() can be passed O_TMPFILE to create an unnamed file under a
given directory. The file disappears once the fd is closed, so there
can be no leftover. This approach is used to implement tmpfile() in
glibc, if available.
On the model of tmpfile(), add a new helper tmpfd() in
freestanding.h and make use of it in the tests that need a temporary
fd, replacing the hardcoded files.
Signed-off-by: Kevin Brodsky <kevin.brodsky(a)arm.com>
---
This will also help for Akram's uaccess kselftests.
Review branch:
https://git.morello-project.org/kbrodsky-arm/linux/-/commits/morello/kselft…
.../selftests/arm64/morello/freestanding.h | 15 +++++++++++++++
tools/testing/selftests/arm64/morello/mmap.c | 4 +---
.../testing/selftests/arm64/morello/read_write.c | 7 ++-----
3 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/tools/testing/selftests/arm64/morello/freestanding.h b/tools/testing/selftests/arm64/morello/freestanding.h
index 8dab905d2b54..5ab02dee1270 100644
--- a/tools/testing/selftests/arm64/morello/freestanding.h
+++ b/tools/testing/selftests/arm64/morello/freestanding.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <stddef.h>
#include <asm/unistd.h>
+#include <linux/fcntl.h>
#include <linux/posix_types.h>
#include <linux/resource.h>
#include <linux/signal.h>
@@ -229,4 +230,18 @@ static inline int waitpid(pid_t pid, int *wstatus, int options)
return syscall(__NR_wait4, pid, wstatus, options, 0);
}
+/*
+ * Creates a new temporary file and returns an fd to it. The file has no name
+ * (see open(2) regarding O_TMPFILE) and is deleted when the fd is closed.
+ */
+static inline int tmpfd(void)
+{
+ int fd;
+
+ fd = syscall(__NR_openat, 0, "/", O_TMPFILE | O_RDWR, 0666);
+ ASSERT_GE(fd, 0);
+
+ return fd;
+}
+
#endif
diff --git a/tools/testing/selftests/arm64/morello/mmap.c b/tools/testing/selftests/arm64/morello/mmap.c
index 62fc14d14d46..618eb221d0ae 100644
--- a/tools/testing/selftests/arm64/morello/mmap.c
+++ b/tools/testing/selftests/arm64/morello/mmap.c
@@ -7,7 +7,6 @@
#include <linux/mman.h>
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/fcntl.h>
#include <cheriintrin.h>
#include "freestanding.h"
@@ -65,13 +64,12 @@ void syscall_mmap2(void)
{
const char msg[] = "foo";
unsigned int msg_len = sizeof(msg); /* No need for the terminator */
- const char *sample_file = "/limbo.dat";
void *addr;
int fd;
int retval;
/* create a sample file to map onto with mmap */
- fd = syscall(__NR_openat, 0, sample_file, O_RDWR | O_CREAT, FILE_PERM);
+ fd = tmpfd();
ASSERT_GE(fd, 0);
diff --git a/tools/testing/selftests/arm64/morello/read_write.c b/tools/testing/selftests/arm64/morello/read_write.c
index a68b5efeb5ab..6425c8449baa 100644
--- a/tools/testing/selftests/arm64/morello/read_write.c
+++ b/tools/testing/selftests/arm64/morello/read_write.c
@@ -7,7 +7,6 @@
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/uio.h>
-#include <asm/fcntl.h>
#include <asm/unistd.h>
#include "freestanding.h"
@@ -26,8 +25,6 @@ static const char w_vec_msg2[VEC_MSG_LEN] = " is vector\n";
static char r_vec_msg1[VEC_MSG_LEN];
static char r_vec_msg2[VEC_MSG_LEN];
-static const char file[] = "/check_cap.txt";
-
static const struct iovec w_iovec[VEC_MSG_NUM] = {
{.iov_base = (char *) w_vec_msg1, .iov_len = VEC_MSG_LEN},
{.iov_base = (char *) w_vec_msg2, .iov_len = VEC_MSG_LEN},
@@ -58,8 +55,8 @@ TEST(test_writev)
TEST(test_open)
{
- fd = syscall(__NR_openat, 0, file, O_RDWR | O_CREAT, 0666);
- ASSERT_LE(1, fd) TH_LOG("open failed");
+ /* tmpfd() asserts that the openat syscall succeeds */
+ fd = tmpfd();
}
TEST(test_read)
--
2.42.1