Hi Amit,
On Fri, Mar 03, 2023 at 06:34:41PM +0530, Amit Daniel Kachhap wrote:
Some of the Gcc compiled clone tests in restricted mode face stack corruption. This occurs as the dynamic relocations by Gcc do not get input from compiler about clearing the executive mode in function pointers. On the other hand, Clang provides input about this permission in the structure cap_reloc (may be with hint from instruction blrr) to the capability relocation code.
So I must admit I've been struggling a bit to connect the dots here. I'm not entirely sure how relocations would deal with executive vs restricted: two entries for the same symbol with different permissions ? Furthermore, the symbol at hand, in the case of clang is not actually being relocated. The branch capability is being build based on PCC, which for restricted renders proper capability permissions (as PCC will already have the executive bit cleared). Now with GCC, the symbol is relocated with executive permission which means the branch instruction will switch from restrictive back to executive which is were the problem comes from: that switch will also switch the SP (from RCSP to CSP) and as that one is not the one expected, it will result in number of issues. Note that the CSP will point to the stack from before switching to restricted. And that is the main problem here. Your change, even though it is actually fixing the mess we end up with GCC, it brings more generic question on how to actually handle restricted. Note that any branch to relocated symbol, without proper handling of related registers or permissions will blow up. I guess though, that's the best we can do at this point.
--- BR B.
As a workaround, clear this permission bit explicitly if required before branching to this function pointer. Also, keep any other function called from this function as inline.
Signed-off-by: Amit Daniel Kachhap amit.kachhap@arm.com
tools/testing/selftests/arm64/morello/clone.c | 3 ++- .../arm64/morello/freestanding_start.S | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/arm64/morello/clone.c b/tools/testing/selftests/arm64/morello/clone.c index 69189287144a..67468cb524bc 100644 --- a/tools/testing/selftests/arm64/morello/clone.c +++ b/tools/testing/selftests/arm64/morello/clone.c @@ -44,7 +44,8 @@ struct test_fixture { #define PROBE_INTERVAL (1 << 12) -static void probe_addr_range(uintcap_t start_addr, size_t size, int interval) +static inline __attribute__((always_inline)) +void probe_addr_range(uintcap_t start_addr, size_t size, int interval) { size_t i; diff --git a/tools/testing/selftests/arm64/morello/freestanding_start.S b/tools/testing/selftests/arm64/morello/freestanding_start.S index 92260fdc384d..365a8d16606a 100644 --- a/tools/testing/selftests/arm64/morello/freestanding_start.S +++ b/tools/testing/selftests/arm64/morello/freestanding_start.S @@ -199,6 +199,24 @@ FUNCTION_START(__clone) 1: mov c0, c10 mov c1, c9
- /*
* Function pointers executed in restrictive mode have the executive
* mode permission cleared off by the Clang capability relocation code.
* However, dynamic relocations by GCC do not manage this, so clear this
* permission bit explicitly if required.
*/
- adr c2, #0
- gcperm x3, c2
- tbnz x3, #__ARM_CAP_PERMISSION_EXECUTIVE__, 2f
- mov x4, #__ARM_CAP_PERMISSION_EXECUTIVE__
- clrperm c1, c1, x4
- /*
* Function pointers are sealed so clrperm untagged c1 - rebuild a valid
* capability from PCC
*/
- build c1, c1, c2
+2: blr c1 mov x8, #__NR_exit svc #0 -- 2.25.1