~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/arm64/mte/check_user_mem.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 // Copyright (C) 2020 ARM Limited
  3 
  4 #define _GNU_SOURCE
  5 
  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 
 22 static size_t page_sz;
 23 
 24 #define TEST_NAME_MAX 100
 25 
 26 enum test_type {
 27         READ_TEST,
 28         WRITE_TEST,
 29         READV_TEST,
 30         WRITEV_TEST,
 31         LAST_TEST,
 32 };
 33 
 34 static 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 sync
115                                  * mode without fault but may not fail in async mode as per the
116                                  * 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 
134 usermem_acc_err:
135         err = KSFT_FAIL;
136 exit:
137         mte_free_memory((void *)ptr, len, mem_type, true);
138         close(fd);
139         return err;
140 }
141 
142 void 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 
194 int 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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php