| // 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); |
| |
| /* Set test plan */ |
| ksft_set_plan(4); |
| |
| 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; |
| } |