244 lines · c
1// SPDX-License-Identifier: GPL-2.02// Copyright (C) 2020 ARM Limited3 4#define _GNU_SOURCE5 6#include <assert.h>7#include <errno.h>8#include <fcntl.h>9#include <signal.h>10#include <stdlib.h>11#include <stdio.h>12#include <string.h>13#include <ucontext.h>14#include <unistd.h>15#include <sys/uio.h>16#include <sys/mman.h>17 18#include "kselftest.h"19#include "mte_common_util.h"20#include "mte_def.h"21 22static size_t page_sz;23 24#define TEST_NAME_MAX 10025 26enum test_type {27 READ_TEST,28 WRITE_TEST,29 READV_TEST,30 WRITEV_TEST,31 LAST_TEST,32};33 34static int check_usermem_access_fault(int mem_type, int mode, int mapping,35 int tag_offset, int tag_len,36 enum test_type test_type)37{38 int fd, i, err;39 char val = 'A';40 ssize_t len, syscall_len;41 void *ptr, *ptr_next;42 int fileoff, ptroff, size;43 int sizes[] = {1, 2, 3, 8, 16, 32, 4096, page_sz};44 45 err = KSFT_PASS;46 len = 2 * page_sz;47 mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);48 fd = create_temp_file();49 if (fd == -1)50 return KSFT_FAIL;51 for (i = 0; i < len; i++)52 if (write(fd, &val, sizeof(val)) != sizeof(val))53 return KSFT_FAIL;54 lseek(fd, 0, 0);55 ptr = mte_allocate_memory(len, mem_type, mapping, true);56 if (check_allocated_memory(ptr, len, mem_type, true) != KSFT_PASS) {57 close(fd);58 return KSFT_FAIL;59 }60 mte_initialize_current_context(mode, (uintptr_t)ptr, len);61 /* Copy from file into buffer with valid tag */62 syscall_len = read(fd, ptr, len);63 mte_wait_after_trig();64 if (cur_mte_cxt.fault_valid || syscall_len < len)65 goto usermem_acc_err;66 /* Verify same pattern is read */67 for (i = 0; i < len; i++)68 if (*(char *)(ptr + i) != val)69 break;70 if (i < len)71 goto usermem_acc_err;72 73 if (!tag_len)74 tag_len = len - tag_offset;75 /* Tag a part of memory with different value */76 ptr_next = (void *)((unsigned long)ptr + tag_offset);77 ptr_next = mte_insert_new_tag(ptr_next);78 mte_set_tag_address_range(ptr_next, tag_len);79 80 for (fileoff = 0; fileoff < 16; fileoff++) {81 for (ptroff = 0; ptroff < 16; ptroff++) {82 for (i = 0; i < ARRAY_SIZE(sizes); i++) {83 size = sizes[i];84 lseek(fd, 0, 0);85 86 /* perform file operation on buffer with invalid tag */87 switch (test_type) {88 case READ_TEST:89 syscall_len = read(fd, ptr + ptroff, size);90 break;91 case WRITE_TEST:92 syscall_len = write(fd, ptr + ptroff, size);93 break;94 case READV_TEST: {95 struct iovec iov[1];96 iov[0].iov_base = ptr + ptroff;97 iov[0].iov_len = size;98 syscall_len = readv(fd, iov, 1);99 break;100 }101 case WRITEV_TEST: {102 struct iovec iov[1];103 iov[0].iov_base = ptr + ptroff;104 iov[0].iov_len = size;105 syscall_len = writev(fd, iov, 1);106 break;107 }108 case LAST_TEST:109 goto usermem_acc_err;110 }111 112 mte_wait_after_trig();113 /*114 * Accessing user memory in kernel with invalid tag should fail in sync115 * mode without fault but may not fail in async mode as per the116 * implemented MTE userspace support in Arm64 kernel.117 */118 if (cur_mte_cxt.fault_valid) {119 goto usermem_acc_err;120 }121 if (mode == MTE_SYNC_ERR && syscall_len < len) {122 /* test passed */123 } else if (mode == MTE_ASYNC_ERR && syscall_len == size) {124 /* test passed */125 } else {126 goto usermem_acc_err;127 }128 }129 }130 }131 132 goto exit;133 134usermem_acc_err:135 err = KSFT_FAIL;136exit:137 mte_free_memory((void *)ptr, len, mem_type, true);138 close(fd);139 return err;140}141 142void format_test_name(char* name, int name_len, int type, int sync, int map, int len, int offset) {143 const char* test_type;144 const char* mte_type;145 const char* map_type;146 147 switch (type) {148 case READ_TEST:149 test_type = "read";150 break;151 case WRITE_TEST:152 test_type = "write";153 break;154 case READV_TEST:155 test_type = "readv";156 break;157 case WRITEV_TEST:158 test_type = "writev";159 break;160 default:161 assert(0);162 break;163 }164 165 switch (sync) {166 case MTE_SYNC_ERR:167 mte_type = "MTE_SYNC_ERR";168 break;169 case MTE_ASYNC_ERR:170 mte_type = "MTE_ASYNC_ERR";171 break;172 default:173 assert(0);174 break;175 }176 177 switch (map) {178 case MAP_SHARED:179 map_type = "MAP_SHARED";180 break;181 case MAP_PRIVATE:182 map_type = "MAP_PRIVATE";183 break;184 default:185 assert(0);186 break;187 }188 189 snprintf(name, name_len,190 "test type: %s, %s, %s, tag len: %d, tag offset: %d\n",191 test_type, mte_type, map_type, len, offset);192}193 194int main(int argc, char *argv[])195{196 int err;197 int t, s, m, l, o;198 int mte_sync[] = {MTE_SYNC_ERR, MTE_ASYNC_ERR};199 int maps[] = {MAP_SHARED, MAP_PRIVATE};200 int tag_lens[] = {0, MT_GRANULE_SIZE};201 int tag_offsets[] = {page_sz, MT_GRANULE_SIZE};202 char test_name[TEST_NAME_MAX];203 204 page_sz = getpagesize();205 if (!page_sz) {206 ksft_print_msg("ERR: Unable to get page size\n");207 return KSFT_FAIL;208 }209 err = mte_default_setup();210 if (err)211 return err;212 213 /* Register signal handlers */214 mte_register_signal(SIGSEGV, mte_default_handler);215 216 /* Set test plan */217 ksft_set_plan(64);218 219 for (t = 0; t < LAST_TEST; t++) {220 for (s = 0; s < ARRAY_SIZE(mte_sync); s++) {221 for (m = 0; m < ARRAY_SIZE(maps); m++) {222 for (l = 0; l < ARRAY_SIZE(tag_lens); l++) {223 for (o = 0; o < ARRAY_SIZE(tag_offsets); o++) {224 int sync = mte_sync[s];225 int map = maps[m];226 int offset = tag_offsets[o];227 int tag_len = tag_lens[l];228 int res = check_usermem_access_fault(USE_MMAP, sync,229 map, offset,230 tag_len, t);231 format_test_name(test_name, TEST_NAME_MAX,232 t, sync, map, tag_len, offset);233 evaluate_test(res, test_name);234 }235 }236 }237 }238 }239 240 mte_restore_setup();241 ksft_print_cnts();242 return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;243}244