1f3b2a26cSAmit Daniel Kachhap // SPDX-License-Identifier: GPL-2.0
2f3b2a26cSAmit Daniel Kachhap // Copyright (C) 2020 ARM Limited
3f3b2a26cSAmit Daniel Kachhap
4f3b2a26cSAmit Daniel Kachhap #define _GNU_SOURCE
5f3b2a26cSAmit Daniel Kachhap
6f3b2a26cSAmit Daniel Kachhap #include <errno.h>
7f3b2a26cSAmit Daniel Kachhap #include <signal.h>
8f3b2a26cSAmit Daniel Kachhap #include <stdio.h>
9f3b2a26cSAmit Daniel Kachhap #include <stdlib.h>
10f3b2a26cSAmit Daniel Kachhap #include <string.h>
11f3b2a26cSAmit Daniel Kachhap #include <ucontext.h>
12f3b2a26cSAmit Daniel Kachhap #include <sys/wait.h>
13f3b2a26cSAmit Daniel Kachhap
14f3b2a26cSAmit Daniel Kachhap #include "kselftest.h"
15f3b2a26cSAmit Daniel Kachhap #include "mte_common_util.h"
16f3b2a26cSAmit Daniel Kachhap #include "mte_def.h"
17f3b2a26cSAmit Daniel Kachhap
18f3b2a26cSAmit Daniel Kachhap #define BUFFER_SIZE (5 * MT_GRANULE_SIZE)
19f3b2a26cSAmit Daniel Kachhap #define RUNS (MT_TAG_COUNT * 2)
20f3b2a26cSAmit Daniel Kachhap #define MTE_LAST_TAG_MASK (0x7FFF)
21f3b2a26cSAmit Daniel Kachhap
verify_mte_pointer_validity(char * ptr,int mode)22f3b2a26cSAmit Daniel Kachhap static int verify_mte_pointer_validity(char *ptr, int mode)
23f3b2a26cSAmit Daniel Kachhap {
24f3b2a26cSAmit Daniel Kachhap mte_initialize_current_context(mode, (uintptr_t)ptr, BUFFER_SIZE);
25f3b2a26cSAmit Daniel Kachhap /* Check the validity of the tagged pointer */
26541235deSMark Brown memset(ptr, '1', BUFFER_SIZE);
27f3b2a26cSAmit Daniel Kachhap mte_wait_after_trig();
289a568171SMark Brown if (cur_mte_cxt.fault_valid) {
299a568171SMark Brown ksft_print_msg("Unexpected fault recorded for %p-%p in mode %x\n",
309a568171SMark Brown ptr, ptr + BUFFER_SIZE, mode);
31f3b2a26cSAmit Daniel Kachhap return KSFT_FAIL;
329a568171SMark Brown }
33f3b2a26cSAmit Daniel Kachhap /* Proceed further for nonzero tags */
34f3b2a26cSAmit Daniel Kachhap if (!MT_FETCH_TAG((uintptr_t)ptr))
35f3b2a26cSAmit Daniel Kachhap return KSFT_PASS;
36f3b2a26cSAmit Daniel Kachhap mte_initialize_current_context(mode, (uintptr_t)ptr, BUFFER_SIZE + 1);
37f3b2a26cSAmit Daniel Kachhap /* Check the validity outside the range */
38f3b2a26cSAmit Daniel Kachhap ptr[BUFFER_SIZE] = '2';
39f3b2a26cSAmit Daniel Kachhap mte_wait_after_trig();
409a568171SMark Brown if (!cur_mte_cxt.fault_valid) {
419a568171SMark Brown ksft_print_msg("No valid fault recorded for %p in mode %x\n",
429a568171SMark Brown ptr, mode);
43f3b2a26cSAmit Daniel Kachhap return KSFT_FAIL;
449a568171SMark Brown } else {
45f3b2a26cSAmit Daniel Kachhap return KSFT_PASS;
46f3b2a26cSAmit Daniel Kachhap }
479a568171SMark Brown }
48f3b2a26cSAmit Daniel Kachhap
check_single_included_tags(int mem_type,int mode)49f3b2a26cSAmit Daniel Kachhap static int check_single_included_tags(int mem_type, int mode)
50f3b2a26cSAmit Daniel Kachhap {
51f3b2a26cSAmit Daniel Kachhap char *ptr;
5272d6771cSMark Brown int tag, run, ret, result = KSFT_PASS;
53f3b2a26cSAmit Daniel Kachhap
54541235deSMark Brown ptr = mte_allocate_memory(BUFFER_SIZE + MT_GRANULE_SIZE, mem_type, 0, false);
55f3b2a26cSAmit Daniel Kachhap if (check_allocated_memory(ptr, BUFFER_SIZE + MT_GRANULE_SIZE,
56f3b2a26cSAmit Daniel Kachhap mem_type, false) != KSFT_PASS)
57f3b2a26cSAmit Daniel Kachhap return KSFT_FAIL;
58f3b2a26cSAmit Daniel Kachhap
59f3b2a26cSAmit Daniel Kachhap for (tag = 0; (tag < MT_TAG_COUNT) && (result == KSFT_PASS); tag++) {
6072d6771cSMark Brown ret = mte_switch_mode(mode, MT_INCLUDE_VALID_TAG(tag));
6172d6771cSMark Brown if (ret != 0)
6272d6771cSMark Brown result = KSFT_FAIL;
63f3b2a26cSAmit Daniel Kachhap /* Try to catch a excluded tag by a number of tries. */
64f3b2a26cSAmit Daniel Kachhap for (run = 0; (run < RUNS) && (result == KSFT_PASS); run++) {
65541235deSMark Brown ptr = mte_insert_tags(ptr, BUFFER_SIZE);
66f3b2a26cSAmit Daniel Kachhap /* Check tag value */
67f3b2a26cSAmit Daniel Kachhap if (MT_FETCH_TAG((uintptr_t)ptr) == tag) {
68f3b2a26cSAmit Daniel Kachhap ksft_print_msg("FAIL: wrong tag = 0x%x with include mask=0x%x\n",
69f3b2a26cSAmit Daniel Kachhap MT_FETCH_TAG((uintptr_t)ptr),
70f3b2a26cSAmit Daniel Kachhap MT_INCLUDE_VALID_TAG(tag));
71f3b2a26cSAmit Daniel Kachhap result = KSFT_FAIL;
72f3b2a26cSAmit Daniel Kachhap break;
73f3b2a26cSAmit Daniel Kachhap }
74f3b2a26cSAmit Daniel Kachhap result = verify_mte_pointer_validity(ptr, mode);
75f3b2a26cSAmit Daniel Kachhap }
76f3b2a26cSAmit Daniel Kachhap }
77541235deSMark Brown mte_free_memory_tag_range(ptr, BUFFER_SIZE, mem_type, 0, MT_GRANULE_SIZE);
78f3b2a26cSAmit Daniel Kachhap return result;
79f3b2a26cSAmit Daniel Kachhap }
80f3b2a26cSAmit Daniel Kachhap
check_multiple_included_tags(int mem_type,int mode)81f3b2a26cSAmit Daniel Kachhap static int check_multiple_included_tags(int mem_type, int mode)
82f3b2a26cSAmit Daniel Kachhap {
83f3b2a26cSAmit Daniel Kachhap char *ptr;
84f3b2a26cSAmit Daniel Kachhap int tag, run, result = KSFT_PASS;
85f3b2a26cSAmit Daniel Kachhap unsigned long excl_mask = 0;
86f3b2a26cSAmit Daniel Kachhap
87541235deSMark Brown ptr = mte_allocate_memory(BUFFER_SIZE + MT_GRANULE_SIZE, mem_type, 0, false);
88f3b2a26cSAmit Daniel Kachhap if (check_allocated_memory(ptr, BUFFER_SIZE + MT_GRANULE_SIZE,
89f3b2a26cSAmit Daniel Kachhap mem_type, false) != KSFT_PASS)
90f3b2a26cSAmit Daniel Kachhap return KSFT_FAIL;
91f3b2a26cSAmit Daniel Kachhap
92f3b2a26cSAmit Daniel Kachhap for (tag = 0; (tag < MT_TAG_COUNT - 1) && (result == KSFT_PASS); tag++) {
93f3b2a26cSAmit Daniel Kachhap excl_mask |= 1 << tag;
94f3b2a26cSAmit Daniel Kachhap mte_switch_mode(mode, MT_INCLUDE_VALID_TAGS(excl_mask));
95f3b2a26cSAmit Daniel Kachhap /* Try to catch a excluded tag by a number of tries. */
96f3b2a26cSAmit Daniel Kachhap for (run = 0; (run < RUNS) && (result == KSFT_PASS); run++) {
97541235deSMark Brown ptr = mte_insert_tags(ptr, BUFFER_SIZE);
98f3b2a26cSAmit Daniel Kachhap /* Check tag value */
99f3b2a26cSAmit Daniel Kachhap if (MT_FETCH_TAG((uintptr_t)ptr) < tag) {
100f3b2a26cSAmit Daniel Kachhap ksft_print_msg("FAIL: wrong tag = 0x%x with include mask=0x%x\n",
101f3b2a26cSAmit Daniel Kachhap MT_FETCH_TAG((uintptr_t)ptr),
102f3b2a26cSAmit Daniel Kachhap MT_INCLUDE_VALID_TAGS(excl_mask));
103f3b2a26cSAmit Daniel Kachhap result = KSFT_FAIL;
104f3b2a26cSAmit Daniel Kachhap break;
105f3b2a26cSAmit Daniel Kachhap }
106f3b2a26cSAmit Daniel Kachhap result = verify_mte_pointer_validity(ptr, mode);
107f3b2a26cSAmit Daniel Kachhap }
108f3b2a26cSAmit Daniel Kachhap }
109541235deSMark Brown mte_free_memory_tag_range(ptr, BUFFER_SIZE, mem_type, 0, MT_GRANULE_SIZE);
110f3b2a26cSAmit Daniel Kachhap return result;
111f3b2a26cSAmit Daniel Kachhap }
112f3b2a26cSAmit Daniel Kachhap
check_all_included_tags(int mem_type,int mode)113f3b2a26cSAmit Daniel Kachhap static int check_all_included_tags(int mem_type, int mode)
114f3b2a26cSAmit Daniel Kachhap {
115f3b2a26cSAmit Daniel Kachhap char *ptr;
11672d6771cSMark Brown int run, ret, result = KSFT_PASS;
117f3b2a26cSAmit Daniel Kachhap
118541235deSMark Brown ptr = mte_allocate_memory(BUFFER_SIZE + MT_GRANULE_SIZE, mem_type, 0, false);
119f3b2a26cSAmit Daniel Kachhap if (check_allocated_memory(ptr, BUFFER_SIZE + MT_GRANULE_SIZE,
120f3b2a26cSAmit Daniel Kachhap mem_type, false) != KSFT_PASS)
121f3b2a26cSAmit Daniel Kachhap return KSFT_FAIL;
122f3b2a26cSAmit Daniel Kachhap
12372d6771cSMark Brown ret = mte_switch_mode(mode, MT_INCLUDE_TAG_MASK);
12472d6771cSMark Brown if (ret != 0)
12572d6771cSMark Brown return KSFT_FAIL;
126f3b2a26cSAmit Daniel Kachhap /* Try to catch a excluded tag by a number of tries. */
127f3b2a26cSAmit Daniel Kachhap for (run = 0; (run < RUNS) && (result == KSFT_PASS); run++) {
128f3b2a26cSAmit Daniel Kachhap ptr = (char *)mte_insert_tags(ptr, BUFFER_SIZE);
129f3b2a26cSAmit Daniel Kachhap /*
130f3b2a26cSAmit Daniel Kachhap * Here tag byte can be between 0x0 to 0xF (full allowed range)
131f3b2a26cSAmit Daniel Kachhap * so no need to match so just verify if it is writable.
132f3b2a26cSAmit Daniel Kachhap */
133f3b2a26cSAmit Daniel Kachhap result = verify_mte_pointer_validity(ptr, mode);
134f3b2a26cSAmit Daniel Kachhap }
135541235deSMark Brown mte_free_memory_tag_range(ptr, BUFFER_SIZE, mem_type, 0, MT_GRANULE_SIZE);
136f3b2a26cSAmit Daniel Kachhap return result;
137f3b2a26cSAmit Daniel Kachhap }
138f3b2a26cSAmit Daniel Kachhap
check_none_included_tags(int mem_type,int mode)139f3b2a26cSAmit Daniel Kachhap static int check_none_included_tags(int mem_type, int mode)
140f3b2a26cSAmit Daniel Kachhap {
141f3b2a26cSAmit Daniel Kachhap char *ptr;
14272d6771cSMark Brown int run, ret;
143f3b2a26cSAmit Daniel Kachhap
144541235deSMark Brown ptr = mte_allocate_memory(BUFFER_SIZE, mem_type, 0, false);
145f3b2a26cSAmit Daniel Kachhap if (check_allocated_memory(ptr, BUFFER_SIZE, mem_type, false) != KSFT_PASS)
146f3b2a26cSAmit Daniel Kachhap return KSFT_FAIL;
147f3b2a26cSAmit Daniel Kachhap
14872d6771cSMark Brown ret = mte_switch_mode(mode, MT_EXCLUDE_TAG_MASK);
14972d6771cSMark Brown if (ret != 0)
15072d6771cSMark Brown return KSFT_FAIL;
151f3b2a26cSAmit Daniel Kachhap /* Try to catch a excluded tag by a number of tries. */
152f3b2a26cSAmit Daniel Kachhap for (run = 0; run < RUNS; run++) {
153f3b2a26cSAmit Daniel Kachhap ptr = (char *)mte_insert_tags(ptr, BUFFER_SIZE);
154f3b2a26cSAmit Daniel Kachhap /* Here all tags exluded so tag value generated should be 0 */
155f3b2a26cSAmit Daniel Kachhap if (MT_FETCH_TAG((uintptr_t)ptr)) {
156f3b2a26cSAmit Daniel Kachhap ksft_print_msg("FAIL: included tag value found\n");
157f3b2a26cSAmit Daniel Kachhap mte_free_memory((void *)ptr, BUFFER_SIZE, mem_type, true);
158f3b2a26cSAmit Daniel Kachhap return KSFT_FAIL;
159f3b2a26cSAmit Daniel Kachhap }
160f3b2a26cSAmit Daniel Kachhap mte_initialize_current_context(mode, (uintptr_t)ptr, BUFFER_SIZE);
161f3b2a26cSAmit Daniel Kachhap /* Check the write validity of the untagged pointer */
162541235deSMark Brown memset(ptr, '1', BUFFER_SIZE);
163f3b2a26cSAmit Daniel Kachhap mte_wait_after_trig();
164f3b2a26cSAmit Daniel Kachhap if (cur_mte_cxt.fault_valid)
165f3b2a26cSAmit Daniel Kachhap break;
166f3b2a26cSAmit Daniel Kachhap }
167541235deSMark Brown mte_free_memory(ptr, BUFFER_SIZE, mem_type, false);
168f3b2a26cSAmit Daniel Kachhap if (cur_mte_cxt.fault_valid)
169f3b2a26cSAmit Daniel Kachhap return KSFT_FAIL;
170f3b2a26cSAmit Daniel Kachhap else
171f3b2a26cSAmit Daniel Kachhap return KSFT_PASS;
172f3b2a26cSAmit Daniel Kachhap }
173f3b2a26cSAmit Daniel Kachhap
main(int argc,char * argv[])174f3b2a26cSAmit Daniel Kachhap int main(int argc, char *argv[])
175f3b2a26cSAmit Daniel Kachhap {
176f3b2a26cSAmit Daniel Kachhap int err;
177f3b2a26cSAmit Daniel Kachhap
178f3b2a26cSAmit Daniel Kachhap err = mte_default_setup();
179f3b2a26cSAmit Daniel Kachhap if (err)
180f3b2a26cSAmit Daniel Kachhap return err;
181f3b2a26cSAmit Daniel Kachhap
182f3b2a26cSAmit Daniel Kachhap /* Register SIGSEGV handler */
183f3b2a26cSAmit Daniel Kachhap mte_register_signal(SIGSEGV, mte_default_handler);
184f3b2a26cSAmit Daniel Kachhap
185041fa41fSVincenzo Frascino /* Set test plan */
186041fa41fSVincenzo Frascino ksft_set_plan(4);
187041fa41fSVincenzo Frascino
188f3b2a26cSAmit Daniel Kachhap evaluate_test(check_single_included_tags(USE_MMAP, MTE_SYNC_ERR),
189f3b2a26cSAmit Daniel Kachhap "Check an included tag value with sync mode\n");
190f3b2a26cSAmit Daniel Kachhap evaluate_test(check_multiple_included_tags(USE_MMAP, MTE_SYNC_ERR),
191f3b2a26cSAmit Daniel Kachhap "Check different included tags value with sync mode\n");
192f3b2a26cSAmit Daniel Kachhap evaluate_test(check_none_included_tags(USE_MMAP, MTE_SYNC_ERR),
193f3b2a26cSAmit Daniel Kachhap "Check none included tags value with sync mode\n");
194f3b2a26cSAmit Daniel Kachhap evaluate_test(check_all_included_tags(USE_MMAP, MTE_SYNC_ERR),
195f3b2a26cSAmit Daniel Kachhap "Check all included tags value with sync mode\n");
196f3b2a26cSAmit Daniel Kachhap
197f3b2a26cSAmit Daniel Kachhap mte_restore_setup();
198f3b2a26cSAmit Daniel Kachhap ksft_print_cnts();
199f3b2a26cSAmit Daniel Kachhap return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
200f3b2a26cSAmit Daniel Kachhap }
201