kselftest/arm64: Verify mte tag inclusion via prctl
This testcase verifies that the tag generated with "irg" instruction contains only included tags. This is done via prtcl call. This test covers 4 scenarios, * At least one included tag. * More than one included tags. * All included. * None included. Co-developed-by: Gabor Kertesz <gabor.kertesz@arm.com> Signed-off-by: Gabor Kertesz <gabor.kertesz@arm.com> Signed-off-by: Amit Daniel Kachhap <amit.kachhap@arm.com> Tested-by: Catalin Marinas <catalin.marinas@arm.com> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Cc: Shuah Khan <shuah@kernel.org> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Will Deacon <will@kernel.org> Link: https://lore.kernel.org/r/20201002115630.24683-3-amit.kachhap@arm.com Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
e9b60476be
commit
f3b2a26ca7
|
@ -1 +1,2 @@
|
|||
check_buffer_fill
|
||||
check_tags_inclusion
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2020 ARM Limited
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ucontext.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "kselftest.h"
|
||||
#include "mte_common_util.h"
|
||||
#include "mte_def.h"
|
||||
|
||||
#define BUFFER_SIZE (5 * MT_GRANULE_SIZE)
|
||||
#define RUNS (MT_TAG_COUNT * 2)
|
||||
#define MTE_LAST_TAG_MASK (0x7FFF)
|
||||
|
||||
static int verify_mte_pointer_validity(char *ptr, int mode)
|
||||
{
|
||||
mte_initialize_current_context(mode, (uintptr_t)ptr, BUFFER_SIZE);
|
||||
/* Check the validity of the tagged pointer */
|
||||
memset((void *)ptr, '1', BUFFER_SIZE);
|
||||
mte_wait_after_trig();
|
||||
if (cur_mte_cxt.fault_valid)
|
||||
return KSFT_FAIL;
|
||||
/* Proceed further for nonzero tags */
|
||||
if (!MT_FETCH_TAG((uintptr_t)ptr))
|
||||
return KSFT_PASS;
|
||||
mte_initialize_current_context(mode, (uintptr_t)ptr, BUFFER_SIZE + 1);
|
||||
/* Check the validity outside the range */
|
||||
ptr[BUFFER_SIZE] = '2';
|
||||
mte_wait_after_trig();
|
||||
if (!cur_mte_cxt.fault_valid)
|
||||
return KSFT_FAIL;
|
||||
else
|
||||
return KSFT_PASS;
|
||||
}
|
||||
|
||||
static int check_single_included_tags(int mem_type, int mode)
|
||||
{
|
||||
char *ptr;
|
||||
int tag, run, result = KSFT_PASS;
|
||||
|
||||
ptr = (char *)mte_allocate_memory(BUFFER_SIZE + MT_GRANULE_SIZE, mem_type, 0, false);
|
||||
if (check_allocated_memory(ptr, BUFFER_SIZE + MT_GRANULE_SIZE,
|
||||
mem_type, false) != KSFT_PASS)
|
||||
return KSFT_FAIL;
|
||||
|
||||
for (tag = 0; (tag < MT_TAG_COUNT) && (result == KSFT_PASS); tag++) {
|
||||
mte_switch_mode(mode, MT_INCLUDE_VALID_TAG(tag));
|
||||
/* Try to catch a excluded tag by a number of tries. */
|
||||
for (run = 0; (run < RUNS) && (result == KSFT_PASS); run++) {
|
||||
ptr = (char *)mte_insert_tags(ptr, BUFFER_SIZE);
|
||||
/* Check tag value */
|
||||
if (MT_FETCH_TAG((uintptr_t)ptr) == tag) {
|
||||
ksft_print_msg("FAIL: wrong tag = 0x%x with include mask=0x%x\n",
|
||||
MT_FETCH_TAG((uintptr_t)ptr),
|
||||
MT_INCLUDE_VALID_TAG(tag));
|
||||
result = KSFT_FAIL;
|
||||
break;
|
||||
}
|
||||
result = verify_mte_pointer_validity(ptr, mode);
|
||||
}
|
||||
}
|
||||
mte_free_memory_tag_range((void *)ptr, BUFFER_SIZE, mem_type, 0, MT_GRANULE_SIZE);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int check_multiple_included_tags(int mem_type, int mode)
|
||||
{
|
||||
char *ptr;
|
||||
int tag, run, result = KSFT_PASS;
|
||||
unsigned long excl_mask = 0;
|
||||
|
||||
ptr = (char *)mte_allocate_memory(BUFFER_SIZE + MT_GRANULE_SIZE, mem_type, 0, false);
|
||||
if (check_allocated_memory(ptr, BUFFER_SIZE + MT_GRANULE_SIZE,
|
||||
mem_type, false) != KSFT_PASS)
|
||||
return KSFT_FAIL;
|
||||
|
||||
for (tag = 0; (tag < MT_TAG_COUNT - 1) && (result == KSFT_PASS); tag++) {
|
||||
excl_mask |= 1 << tag;
|
||||
mte_switch_mode(mode, MT_INCLUDE_VALID_TAGS(excl_mask));
|
||||
/* Try to catch a excluded tag by a number of tries. */
|
||||
for (run = 0; (run < RUNS) && (result == KSFT_PASS); run++) {
|
||||
ptr = (char *)mte_insert_tags(ptr, BUFFER_SIZE);
|
||||
/* Check tag value */
|
||||
if (MT_FETCH_TAG((uintptr_t)ptr) < tag) {
|
||||
ksft_print_msg("FAIL: wrong tag = 0x%x with include mask=0x%x\n",
|
||||
MT_FETCH_TAG((uintptr_t)ptr),
|
||||
MT_INCLUDE_VALID_TAGS(excl_mask));
|
||||
result = KSFT_FAIL;
|
||||
break;
|
||||
}
|
||||
result = verify_mte_pointer_validity(ptr, mode);
|
||||
}
|
||||
}
|
||||
mte_free_memory_tag_range((void *)ptr, BUFFER_SIZE, mem_type, 0, MT_GRANULE_SIZE);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int check_all_included_tags(int mem_type, int mode)
|
||||
{
|
||||
char *ptr;
|
||||
int run, result = KSFT_PASS;
|
||||
|
||||
ptr = (char *)mte_allocate_memory(BUFFER_SIZE + MT_GRANULE_SIZE, mem_type, 0, false);
|
||||
if (check_allocated_memory(ptr, BUFFER_SIZE + MT_GRANULE_SIZE,
|
||||
mem_type, false) != KSFT_PASS)
|
||||
return KSFT_FAIL;
|
||||
|
||||
mte_switch_mode(mode, MT_INCLUDE_TAG_MASK);
|
||||
/* Try to catch a excluded tag by a number of tries. */
|
||||
for (run = 0; (run < RUNS) && (result == KSFT_PASS); run++) {
|
||||
ptr = (char *)mte_insert_tags(ptr, BUFFER_SIZE);
|
||||
/*
|
||||
* Here tag byte can be between 0x0 to 0xF (full allowed range)
|
||||
* so no need to match so just verify if it is writable.
|
||||
*/
|
||||
result = verify_mte_pointer_validity(ptr, mode);
|
||||
}
|
||||
mte_free_memory_tag_range((void *)ptr, BUFFER_SIZE, mem_type, 0, MT_GRANULE_SIZE);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int check_none_included_tags(int mem_type, int mode)
|
||||
{
|
||||
char *ptr;
|
||||
int run;
|
||||
|
||||
ptr = (char *)mte_allocate_memory(BUFFER_SIZE, mem_type, 0, false);
|
||||
if (check_allocated_memory(ptr, BUFFER_SIZE, mem_type, false) != KSFT_PASS)
|
||||
return KSFT_FAIL;
|
||||
|
||||
mte_switch_mode(mode, MT_EXCLUDE_TAG_MASK);
|
||||
/* Try to catch a excluded tag by a number of tries. */
|
||||
for (run = 0; run < RUNS; run++) {
|
||||
ptr = (char *)mte_insert_tags(ptr, BUFFER_SIZE);
|
||||
/* Here all tags exluded so tag value generated should be 0 */
|
||||
if (MT_FETCH_TAG((uintptr_t)ptr)) {
|
||||
ksft_print_msg("FAIL: included tag value found\n");
|
||||
mte_free_memory((void *)ptr, BUFFER_SIZE, mem_type, true);
|
||||
return KSFT_FAIL;
|
||||
}
|
||||
mte_initialize_current_context(mode, (uintptr_t)ptr, BUFFER_SIZE);
|
||||
/* Check the write validity of the untagged pointer */
|
||||
memset((void *)ptr, '1', BUFFER_SIZE);
|
||||
mte_wait_after_trig();
|
||||
if (cur_mte_cxt.fault_valid)
|
||||
break;
|
||||
}
|
||||
mte_free_memory((void *)ptr, BUFFER_SIZE, mem_type, false);
|
||||
if (cur_mte_cxt.fault_valid)
|
||||
return KSFT_FAIL;
|
||||
else
|
||||
return KSFT_PASS;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int err;
|
||||
|
||||
err = mte_default_setup();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Register SIGSEGV handler */
|
||||
mte_register_signal(SIGSEGV, mte_default_handler);
|
||||
|
||||
evaluate_test(check_single_included_tags(USE_MMAP, MTE_SYNC_ERR),
|
||||
"Check an included tag value with sync mode\n");
|
||||
evaluate_test(check_multiple_included_tags(USE_MMAP, MTE_SYNC_ERR),
|
||||
"Check different included tags value with sync mode\n");
|
||||
evaluate_test(check_none_included_tags(USE_MMAP, MTE_SYNC_ERR),
|
||||
"Check none included tags value with sync mode\n");
|
||||
evaluate_test(check_all_included_tags(USE_MMAP, MTE_SYNC_ERR),
|
||||
"Check all included tags value with sync mode\n");
|
||||
|
||||
mte_restore_setup();
|
||||
ksft_print_cnts();
|
||||
return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
|
||||
}
|
Loading…
Reference in New Issue