Skip to content

Commit 4dafc08

Browse files
amitdanielkachhapwilldeacon
authored andcommitted
kselftest/arm64: Check mte tagged user address in kernel
Add a testcase to check that user address with valid/invalid mte tag works in kernel mode. This test verifies that the kernel API's __arch_copy_from_user/__arch_copy_to_user works by considering if the user pointer has valid/invalid allocation tags. In MTE sync mode, file memory read/write and other similar interfaces fails if a user memory with invalid tag is accessed in kernel. In async mode no such failure occurs. Signed-off-by: Amit Daniel Kachhap <amit.kachhap@arm.com> Tested-by: Catalin Marinas <catalin.marinas@arm.com> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Cc: Shuah Khan <shuah@kernel.org> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Will Deacon <will@kernel.org> Link: https://lore.kernel.org/r/20201002115630.24683-7-amit.kachhap@arm.com Signed-off-by: Will Deacon <will@kernel.org>
1 parent f981d8f commit 4dafc08

4 files changed

Lines changed: 127 additions & 0 deletions

File tree

tools/testing/selftests/arm64/mte/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ check_tags_inclusion
33
check_child_memory
44
check_mmap_options
55
check_ksm_options
6+
check_user_mem
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
// Copyright (C) 2020 ARM Limited
3+
4+
#define _GNU_SOURCE
5+
6+
#include <errno.h>
7+
#include <fcntl.h>
8+
#include <signal.h>
9+
#include <stdlib.h>
10+
#include <stdio.h>
11+
#include <string.h>
12+
#include <ucontext.h>
13+
#include <unistd.h>
14+
#include <sys/mman.h>
15+
16+
#include "kselftest.h"
17+
#include "mte_common_util.h"
18+
#include "mte_def.h"
19+
20+
static size_t page_sz;
21+
22+
static int check_usermem_access_fault(int mem_type, int mode, int mapping)
23+
{
24+
int fd, i, err;
25+
char val = 'A';
26+
size_t len, read_len;
27+
void *ptr, *ptr_next;
28+
29+
err = KSFT_FAIL;
30+
len = 2 * page_sz;
31+
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
32+
fd = create_temp_file();
33+
if (fd == -1)
34+
return KSFT_FAIL;
35+
for (i = 0; i < len; i++)
36+
write(fd, &val, sizeof(val));
37+
lseek(fd, 0, 0);
38+
ptr = mte_allocate_memory(len, mem_type, mapping, true);
39+
if (check_allocated_memory(ptr, len, mem_type, true) != KSFT_PASS) {
40+
close(fd);
41+
return KSFT_FAIL;
42+
}
43+
mte_initialize_current_context(mode, (uintptr_t)ptr, len);
44+
/* Copy from file into buffer with valid tag */
45+
read_len = read(fd, ptr, len);
46+
mte_wait_after_trig();
47+
if (cur_mte_cxt.fault_valid || read_len < len)
48+
goto usermem_acc_err;
49+
/* Verify same pattern is read */
50+
for (i = 0; i < len; i++)
51+
if (*(char *)(ptr + i) != val)
52+
break;
53+
if (i < len)
54+
goto usermem_acc_err;
55+
56+
/* Tag the next half of memory with different value */
57+
ptr_next = (void *)((unsigned long)ptr + page_sz);
58+
ptr_next = mte_insert_new_tag(ptr_next);
59+
mte_set_tag_address_range(ptr_next, page_sz);
60+
61+
lseek(fd, 0, 0);
62+
/* Copy from file into buffer with invalid tag */
63+
read_len = read(fd, ptr, len);
64+
mte_wait_after_trig();
65+
/*
66+
* Accessing user memory in kernel with invalid tag should fail in sync
67+
* mode without fault but may not fail in async mode as per the
68+
* implemented MTE userspace support in Arm64 kernel.
69+
*/
70+
if (mode == MTE_SYNC_ERR &&
71+
!cur_mte_cxt.fault_valid && read_len < len) {
72+
err = KSFT_PASS;
73+
} else if (mode == MTE_ASYNC_ERR &&
74+
!cur_mte_cxt.fault_valid && read_len == len) {
75+
err = KSFT_PASS;
76+
}
77+
usermem_acc_err:
78+
mte_free_memory((void *)ptr, len, mem_type, true);
79+
close(fd);
80+
return err;
81+
}
82+
83+
int main(int argc, char *argv[])
84+
{
85+
int err;
86+
87+
page_sz = getpagesize();
88+
if (!page_sz) {
89+
ksft_print_msg("ERR: Unable to get page size\n");
90+
return KSFT_FAIL;
91+
}
92+
err = mte_default_setup();
93+
if (err)
94+
return err;
95+
/* Register signal handlers */
96+
mte_register_signal(SIGSEGV, mte_default_handler);
97+
98+
evaluate_test(check_usermem_access_fault(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),
99+
"Check memory access from kernel in sync mode, private mapping and mmap memory\n");
100+
evaluate_test(check_usermem_access_fault(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED),
101+
"Check memory access from kernel in sync mode, shared mapping and mmap memory\n");
102+
103+
evaluate_test(check_usermem_access_fault(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE),
104+
"Check memory access from kernel in async mode, private mapping and mmap memory\n");
105+
evaluate_test(check_usermem_access_fault(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED),
106+
"Check memory access from kernel in async mode, shared mapping and mmap memory\n");
107+
108+
mte_restore_setup();
109+
ksft_print_cnts();
110+
return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
111+
}

tools/testing/selftests/arm64/mte/mte_common_util.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ int create_temp_file(void);
6464

6565
/* Assembly MTE utility functions */
6666
void *mte_insert_random_tag(void *ptr);
67+
void *mte_insert_new_tag(void *ptr);
6768
void *mte_get_tag_address(void *ptr);
6869
void mte_set_tag_address_range(void *ptr, int range);
6970
void mte_clear_tag_address_range(void *ptr, int range);

tools/testing/selftests/arm64/mte/mte_helper.S

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,20 @@ ENTRY(mte_insert_random_tag)
2626
ret
2727
ENDPROC(mte_insert_random_tag)
2828

29+
/*
30+
* mte_insert_new_tag: Insert new tag and different from the source tag if
31+
* source pointer has it.
32+
* Input:
33+
* x0 - source pointer with a tag/no-tag
34+
* Return:
35+
* x0 - pointer with random tag
36+
*/
37+
ENTRY(mte_insert_new_tag)
38+
gmi x1, x0, xzr
39+
irg x0, x0, x1
40+
ret
41+
ENDPROC(mte_insert_new_tag)
42+
2943
/*
3044
* mte_get_tag_address: Get the tag from given address.
3145
* Input:

0 commit comments

Comments
 (0)