Skip to content

Commit

Permalink
libdrgn: aarch64: Apply TBI to virtual addresses
Browse files Browse the repository at this point in the history
In tag-based KASAN modes, TCR_EL1.TBI1 is enabled, which causes the
top 8 bits of virtual addresses to be ignored for address translation
purposes. Do the same when reading from memory. There is no harm in doing
so unconditionally, as the architecture does not support >56 bit VA sizes.

Signed-off-by: Peter Collingbourne <[email protected]>
  • Loading branch information
pcc committed Dec 5, 2023
1 parent a4f5976 commit 7a82697
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 6 deletions.
7 changes: 7 additions & 0 deletions libdrgn/arch_aarch64.c
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,12 @@ linux_kernel_pgtable_iterator_next_aarch64(struct drgn_program *prog,
}
}

static uint64_t untagged_addr_aarch64(uint64_t addr)
{
/* Apply TBI by sign extending bit 55 into bits 56-63. */
return (((int64_t)addr) << 8) >> 8;
}

const struct drgn_architecture_info arch_info_aarch64 = {
.name = "AArch64",
.arch = DRGN_ARCH_AARCH64,
Expand All @@ -475,4 +481,5 @@ const struct drgn_architecture_info arch_info_aarch64 = {
linux_kernel_pgtable_iterator_init_aarch64,
.linux_kernel_pgtable_iterator_next =
linux_kernel_pgtable_iterator_next_aarch64,
.untagged_addr = untagged_addr_aarch64,
};
6 changes: 6 additions & 0 deletions libdrgn/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,12 @@ struct drgn_architecture_info {
* @see pgtable_iterator_next_fn
*/
pgtable_iterator_next_fn *linux_kernel_pgtable_iterator_next;
/**
* Return the canonical form of a virtual address, i.e. apply any
* transformations that the CPU applies to the address before page
* table walking.
*/
uint64_t (*untagged_addr)(uint64_t addr);
};

/**
Expand Down
12 changes: 6 additions & 6 deletions libdrgn/program.c
Original file line number Diff line number Diff line change
Expand Up @@ -1639,10 +1639,12 @@ drgn_program_read_memory(struct drgn_program *prog, void *buf, uint64_t address,
{
uint64_t address_mask;
struct drgn_error *err = drgn_program_address_mask(prog, &address_mask);
if (err)
return err;
err = drgn_program_untagged_addr(prog, &address);
if (err)
return err;
char *p = buf;
address &= address_mask;
while (count > 0) {
size_t n = min((uint64_t)(count - 1), address_mask - address) + 1;
err = drgn_memory_reader_read(&prog->reader, p, address, n,
Expand All @@ -1662,13 +1664,11 @@ LIBDRGN_PUBLIC struct drgn_error *
drgn_program_read_c_string(struct drgn_program *prog, uint64_t address,
bool physical, size_t max_size, char **ret)
{
uint64_t address_mask;
struct drgn_error *err = drgn_program_address_mask(prog, &address_mask);
if (err)
return err;
_cleanup_(char_vector_deinit) struct char_vector str = VECTOR_INIT;
for (;;) {
address &= address_mask;
struct drgn_error *err = drgn_program_untagged_addr(prog, &address);
if (err)
return err;
char *c = char_vector_append_entry(&str);
if (!c)
return &drgn_enomem;
Expand Down
13 changes: 13 additions & 0 deletions libdrgn/program.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,19 @@ drgn_program_address_mask(const struct drgn_program *prog, uint64_t *ret)
return NULL;
}

static inline struct drgn_error *
drgn_program_untagged_addr(const struct drgn_program *prog, uint64_t *address)
{
if (!prog->has_platform) {
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
"program address size is not known");
}
*address &= drgn_platform_address_mask(&prog->platform);
if (prog->platform.arch->untagged_addr)
*address = prog->platform.arch->untagged_addr(*address);
return NULL;
}

struct drgn_error *drgn_thread_dup_internal(const struct drgn_thread *thread,
struct drgn_thread *ret);

Expand Down

0 comments on commit 7a82697

Please sign in to comment.