Here's a minimal test that shows the different behavior, as of master head commit 0a58e39fe90c50b313a5148c095f8dbb6111a6d6.
signed_ptr_1 = 0x72ffff94022000 signed_ptr_2 = 0x59ffff94022000 auth_ptr = 0x20ffff94022000
Unmasked pointers DO NOT match
signed_ptr_1 = 0x72ffff94022000 signed_ptr_2 = 0x19ffff94022000 auth_ptr = 0xffff94022000
Unmasked pointers match
signed_ptr_1 = 0x50ffffbe314000 signed_ptr_2 = 0x4affffbe314000 auth_ptr = 0xffffbe314000
Unmasked pointers match
signed_ptr_1 = 0x50ffffbe314000 signed_ptr_2 = 0x4affffbe314000 auth_ptr = 0xffffbe314000
Unmasked pointers match
To compile: clang -g -O0 --target=aarch64-linux-gnu -march=armv8.5-a+memtag --sysroot=/usr/aarch64-linux-gnu/ -L/usr/lib/gcc/aarch64-linux-gnu/10.1.0/
#include <stdio.h>
#include <sys/mman.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <assert.h>
#define ADDRESS_BITS 48
#define ADDRESS_MASK ((uint64_t)(1ul << ADDRESS_BITS) - 1)
typedef enum {
RED = 1,
GREEN = 2
} MTE_Color;
uintptr_t sign_pointer(void* address, uint64_t modifier, bool use_mask) {
uintptr_t addr_to_use;
if(use_mask) {
addr_to_use = ((uintptr_t) address & ADDRESS_MASK);
} else {
addr_to_use = (uintptr_t)address;
}
uintptr_t result;
asm("pacda %[loc], %[mod]"
: "=r"(result)
: [loc] "r"(addr_to_use), [mod] "r"(modifier)
:
);
return result;
}
uintptr_t auth_pointer(void* address, uint64_t modifier) {
uintptr_t result;
asm("autda %[addr], %[mod]"
: "=r"(result)
: [addr] "r"(address), [mod] "r"(modifier)
:
);
return result;
}
int main(int argc, char** argv) {
uint8_t *region = (uint8_t*) mmap(NULL, 16, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
assert(region);
uint64_t modifier_1 = (1ul << 10) | RED;
uintptr_t signed_ptr_1 = sign_pointer(region, modifier_1, false);
uint64_t modifier_2 = (1ul << 10) | GREEN;
uintptr_t signed_ptr_2 = sign_pointer((void*)signed_ptr_1, modifier_2, false);
uintptr_t auth_ptr = auth_pointer((void*)signed_ptr_2, modifier_2);
printf("signed_ptr_1 = 0x%lx\tsigned_ptr_2 = 0x%lx\tauth_ptr = 0x%lx\n",
signed_ptr_1, signed_ptr_2, auth_ptr);
if(auth_ptr == (uintptr_t)region) {
printf("Unmasked pointers match\n");
} else {
printf("Unmasked pointers DO NOT match\n");
}
signed_ptr_1 = sign_pointer(region, modifier_1, true);
signed_ptr_2 = sign_pointer((void*)signed_ptr_1, modifier_2, true);
auth_ptr = auth_pointer((void*)signed_ptr_2, modifier_2);
printf("signed_ptr_1 = 0x%lx\tsigned_ptr_2 = 0x%lx\tauth_ptr = 0x%lx\n",
signed_ptr_1, signed_ptr_2, auth_ptr);
if(auth_ptr == (uintptr_t)region) {
printf("Unmasked pointers match\n");
} else {
printf("Unmasked pointers DO NOT match\n");
}
return 0;
}