aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tools/testing/selftests/arm64/mte/check_tags_inclusion.c
blob: 94d245a0ed560fc8ec95dc9bfad4dc32f55e7aac (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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;
}