pwndbg/pwndbg

AArch64 MTE support, broken telescope and others commands..

Open

#3,270 opened on Aug 26, 2025

View on GitHub
 (4 comments) (0 reactions) (0 assignees)Python (776 forks)batch import
bughelp wanted

Repository metrics

Stars
 (5,820 stars)
PR merge metrics
 (Avg merge 3d 12h) (32 merged PRs in 30d)

Description

Blog for reading: https://www.linaro.org/blog/adding-support-for-mte-debugging-to-qemu/

Telescope: ^ should display good values for tagged addresses

vmmap:

Example program:

//  zig cc -target aarch64-linux-musl -march=neoverse_n2+mte -O0 -g arm64-mte.c -o mte_demo

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/auxv.h>
#include <asm/hwcap.h>
#include <sys/prctl.h>
#include <signal.h>
#include <unistd.h>
#include <stdint.h>
#include <arm_acle.h>

#define PAGE_SIZE 4096

/*
 * Insert a random logical tag into the given pointer.
 * IRG instruction.
 */
#define insert_random_tag(ptr) ({                       \
        uint64_t __val;                                 \
        asm("irg %0, %1" : "=r" (__val) : "r" (ptr));   \
        __val;                                          \
})

/*
 * Set the allocation tag on the destination address.
 * STG instruction.
 */
#define set_tag(tagged_addr) do {                                      \
        asm volatile("stg %0, [%0]" : : "r" (tagged_addr) : "memory"); \
} while (0)

static void segv_handler(int sig, siginfo_t *si, void *unused) {
    printf("Caught SIGSEGV at address %p (MTE violation)\n", si->si_addr);
    _exit(1);
}

#define PR_MTE_TAG_SHIFT	3

int main() {
    unsigned long hwcap2 = getauxval(AT_HWCAP2);
    if (!(hwcap2 & HWCAP2_MTE)) {
        printf("MTE not supported on this CPU\n");
        return 0;
    }
    printf("MTE supported!\n");

    prctl(PR_SET_TAGGED_ADDR_CTRL,
          PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC | (0xfffe << PR_MTE_TAG_SHIFT), 0, 0, 0);

    // zainstaluj handler SIGSEGV
    struct sigaction sa = {0};
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = segv_handler;
    sigaction(SIGSEGV, &sa, NULL);

    // alokacja pamięci z PROT_MTE
    unsigned char *ptr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE|PROT_MTE,
                   MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

    /*
     * Print the pointer value with the default tag (expecting 0)
     */
    printf("pointer is %p\n", ptr);

    /*
     * Write the first 2 bytes of the memory with the default tag
     */
    ptr[0] = 0x41;
    ptr[1] = 0x42;

    /*
     * Read back to confirm the writes
     */
    printf("ptr[0] = 0x%hhx ptr[1] = 0x%hhx\n", ptr[0], ptr[1]);

    /*
     * Generate a random tag and store it for the address (IRG instruction)
     */
    ptr = (unsigned char *) insert_random_tag(ptr);

    /*
     * Set the key on the pointer to match the lock on the memory  (STG instruction)
     */
    set_tag(ptr);

    /*
     * Print the pointer value with the new tag
     */
    printf("pointer is now %p\n", ptr);

    /*
     * Write the first 2 bytes of the memory again, with the new tag
     */
    ptr[0] = 0x43;
    ptr[1] = 0x44;

    /*
     * Read back to confirm the writes
     */
    printf("ptr[0] = 0x%hhx ptr[1] = 0x%hhx\n", ptr[0], ptr[1]);
    while(1) {}

    /*
     * Write to memory beyond the 16 byte granule (offsest 0x10)
     * MTE should generate an exception
     * If the offset is less than 0x10 no SIGSEGV will occur.
     */
    printf("Expecting SIGSEGV...\n");
    ptr[0x10] = 0x55;
    return 0;
}

Contributor guide