Hi,
These 2 patch fixes the failure in clone test with Gcc toolchain. They need the recent v4 version of Gcc support patches posted earlier [1]. The full patch series can be found here [2].
Changes in v2: * Patch 1 is modified to calculate function pointer branch address from PCC. * Commit log updated.
[1]: git@git.morello-project.org:amitdaniel/linux.git gcc_kselftests_support_v4 [2]: git@git.morello-project.org:amitdaniel/linux.git gcc_kselftests_clone_fixes_v2
Thanks, Amit Daniel
Amit Daniel Kachhap (2): kselftests/arm64: morello: Fix restricted mode tests with Gcc kselftests/arm64: morello: clone: Remove loop check
tools/testing/selftests/arm64/morello/clone.c | 30 +++++++++++-------- .../selftests/arm64/morello/freestanding.h | 8 +++++ 2 files changed, 26 insertions(+), 12 deletions(-)
Some of the Gcc compiled clone tests in restricted mode face stack corruption. This occurs as the run-time permission settings (executive or restricted mode) in the PCC may be lost if function pointers are materialised from the GOT entries. This further leads to selecting an incorrect stack pointer(CSP instead of RCSP) and hence the crash.
As a workaround, materialise the function pointer clone_base_fn explicitly by building branch address from the PCC. Here it is assumed that the bounds and permissions of clone_base_fn are same as the PCC , which is not an issue in practice (being in the same translation unit).
Signed-off-by: Amit Daniel Kachhap amit.kachhap@arm.com --- tools/testing/selftests/arm64/morello/clone.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/arm64/morello/clone.c b/tools/testing/selftests/arm64/morello/clone.c index 69189287144a..730811f9b7c2 100644 --- a/tools/testing/selftests/arm64/morello/clone.c +++ b/tools/testing/selftests/arm64/morello/clone.c @@ -98,6 +98,7 @@ void clone_single(struct test_fixture *data) { int ppid = 0, cpid = 0; int result = -EINVAL; + void *ptr = clone_base_fn;
void *new_stack = mmap_verified(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0, STACK_REQ_PERMS); @@ -119,7 +120,18 @@ void clone_single(struct test_fixture *data)
EXPECT_TRUE(!(data->flags & CLONE_TH_RESTRICTED) || in_restricted());
- result = __clone(clone_base_fn, (uintcap_t)new_stack + STACK_SIZE, + /* + * Function pointers are materialised by the compiler by either + * computing from the PCC (ADRP + ADD + SEAL) or loading from GOT. The + * run-time permission settings (executive or restrictive) in PCC may + * not match with the GOT entries. Hence, materialise the function + * pointers explicitly to avoid this mismatch issue. + */ + if (in_restricted()) { + ptr = cheri_address_set(cheri_pcc_get(), (ptraddr_t)ptr); + ptr = cheri_sentry_create(ptr); + } + result = __clone(ptr, (uintcap_t)new_stack + STACK_SIZE, clone_flags, data, &ppid, tls, &cpid);
EXPECT_GT(result, 0) {
On 16/03/2023 10:43, Amit Daniel Kachhap wrote:
Some of the Gcc compiled clone tests in restricted mode face stack corruption. This occurs as the run-time permission settings (executive or restricted mode) in the PCC may be lost if function pointers are materialised from the GOT entries. This further leads to selecting an incorrect stack pointer(CSP instead of RCSP) and hence the crash.
As a workaround, materialise the function pointer clone_base_fn explicitly by building branch address from the PCC. Here it is assumed that the bounds and permissions of clone_base_fn are same as the PCC , which is not an issue in practice (being in the same translation unit).
Signed-off-by: Amit Daniel Kachhap amit.kachhap@arm.com
tools/testing/selftests/arm64/morello/clone.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/arm64/morello/clone.c b/tools/testing/selftests/arm64/morello/clone.c index 69189287144a..730811f9b7c2 100644 --- a/tools/testing/selftests/arm64/morello/clone.c +++ b/tools/testing/selftests/arm64/morello/clone.c @@ -98,6 +98,7 @@ void clone_single(struct test_fixture *data) { int ppid = 0, cpid = 0; int result = -EINVAL;
- void *ptr = clone_base_fn;
A more descriptive name would be good, maybe clone_fn? Also I think that using the real type should work: int (*clone_fn)(void *) = ...
Another minor improvement, this could be moved after clone_flags, and move the if block just after the declaration, to have it all in one place.
Kevin
void *new_stack = mmap_verified(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0, STACK_REQ_PERMS); @@ -119,7 +120,18 @@ void clone_single(struct test_fixture *data) EXPECT_TRUE(!(data->flags & CLONE_TH_RESTRICTED) || in_restricted());
- result = __clone(clone_base_fn, (uintcap_t)new_stack + STACK_SIZE,
- /*
* Function pointers are materialised by the compiler by either
* computing from the PCC (ADRP + ADD + SEAL) or loading from GOT. The
* run-time permission settings (executive or restrictive) in PCC may
* not match with the GOT entries. Hence, materialise the function
* pointers explicitly to avoid this mismatch issue.
*/
- if (in_restricted()) {
ptr = cheri_address_set(cheri_pcc_get(), (ptraddr_t)ptr);
ptr = cheri_sentry_create(ptr);
- }
- result = __clone(ptr, (uintcap_t)new_stack + STACK_SIZE, clone_flags, data, &ppid, tls, &cpid);
EXPECT_GT(result, 0) {
Some of the clone tests use loop check on status flag to determine if the child exited normally. However, this may cause infinite looping if the data handshake does not happen properly due to compiler optimization as observed with Morello Gcc.
Replace the busy loop with the lightweight waitpid() syscall (Instead of existing waitid()) to wait for the child to exit normally.
Signed-off-by: Amit Daniel Kachhap amit.kachhap@arm.com --- tools/testing/selftests/arm64/morello/clone.c | 16 +++++----------- .../selftests/arm64/morello/freestanding.h | 8 ++++++++ 2 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/tools/testing/selftests/arm64/morello/clone.c b/tools/testing/selftests/arm64/morello/clone.c index 730811f9b7c2..7146ff9889f6 100644 --- a/tools/testing/selftests/arm64/morello/clone.c +++ b/tools/testing/selftests/arm64/morello/clone.c @@ -18,9 +18,6 @@ #define in_restricted() \ (!(cheri_perms_get(cheri_pcc_get()) & ARM_CAP_PERMISSION_EXECUTIVE))
- -#define MAGIC_NR 0x3562 /* whatever really ..... */ - #ifndef MAX_PID_NS_LEVEL #define MAX_PID_NS_LEVEL 32 #endif @@ -36,7 +33,6 @@ #define CLONE_TH_RUSAGE BIT(3)
struct test_fixture { - int status; int flags; void *sp; int result; @@ -89,14 +85,13 @@ static int clone_base_fn(void *data) !!(__data->flags & CLONE_TH_RESTRICTED) != in_restricted() ? CTR_FAILED : CTR_SUCCESS; done: - __data->status = MAGIC_NR; return 0; }
static inline __attribute__((always_inline)) void clone_single(struct test_fixture *data) { - int ppid = 0, cpid = 0; + int ppid = 0, cpid = 0, wstatus; int result = -EINVAL; void *ptr = clone_base_fn;
@@ -108,7 +103,7 @@ void clone_single(struct test_fixture *data) CAP_LOAD_PERMS | CAP_STORE_PERMS) : NULL;
- int clone_flags = CLONE_VM | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID; + int clone_flags = CLONE_VM | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | SIGCHLD;
ASSERT_NE(new_stack, NULL); /* For stack probing .... */ @@ -139,10 +134,9 @@ void clone_single(struct test_fixture *data) goto leave; }
- /* Wait substitute ... */ - while (data->status != MAGIC_NR) { - asm(""); - } + /* Wait for the child */ + waitpid(cpid, &wstatus, 0); + ASSERT_TRUE(WIFEXITED(wstatus)); /* * CLONE_CHILD_SETTID sets child's thread ID to provided child's * memory but as VM is being shared, it's all good at this point. diff --git a/tools/testing/selftests/arm64/morello/freestanding.h b/tools/testing/selftests/arm64/morello/freestanding.h index 19611b315de9..135150701b0d 100644 --- a/tools/testing/selftests/arm64/morello/freestanding.h +++ b/tools/testing/selftests/arm64/morello/freestanding.h @@ -31,6 +31,10 @@ typedef __uintcap_t uintcap_t;
#define EXIT_SUCCESS 0
+#ifndef WIFEXITED +#define WIFEXITED(status) (((status) & 0x7f) == 0) +#endif + struct __test_meta { int message; }; @@ -213,4 +217,8 @@ static inline int waitid(int id_type, pid_t id, siginfo_t *info, int options, st return syscall(__NR_waitid, id_type, id, info, options, ru); }
+static inline int waitpid(pid_t pid, int *wstatus, int options) +{ + return syscall(__NR_wait4, pid, wstatus, options, 0); +} #endif
linux-morello@op-lists.linaro.org