On Tue, Sep 01, 2020 at 02:57:19PM +0530, Amit Daniel Kachhap wrote: > Add a testcase to check that user address with valid/invalid > mte tag works in kernel mode. This test verifies 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 a SIGSEV fault is generated if a user memory > with invalid tag is accessed in kernel. In async mode no such > fault occurs. We don't generate a SIGSEGV for faults in the uaccess routines. The kernel simply returns less copied bytes than what was requested or -1 and setting errno. BTW, Qemu has a bug and it reports the wrong exception class (lower DABT) for a tag check fault while in the uaccess routines, leading to kernel panic (bad mode in synchronous abort handler). > +static int check_usermem_access_fault(int mem_type, int mode, int mapping) > +{ > + int fd, ret, i, err; > + char val = 'A'; > + size_t len, read_len; > + void *ptr, *ptr_next; > + bool fault; > + > + len = 2 * page_sz; > + err = KSFT_FAIL; > + /* > + * Accessing user memory in kernel with invalid tag should fault in sync > + * mode but may not fault in async mode as per the implemented MTE > + * support in Arm64 kernel. > + */ > + if (mode == MTE_ASYNC_ERR) > + fault = false; > + else > + fault = true; > + mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG); > + fd = create_temp_file(); > + if (fd == -1) > + return KSFT_FAIL; > + for (i = 0; i < len; i++) > + write(fd, &val, sizeof(val)); > + lseek(fd, 0, 0); > + ptr = mte_allocate_memory(len, mem_type, mapping, true); > + if (check_allocated_memory(ptr, len, mem_type, true) != KSFT_PASS) { > + close(fd); > + return KSFT_FAIL; > + } > + mte_initialize_current_context(mode, (uintptr_t)ptr, len); > + /* Copy from file into buffer with valid tag */ > + read_len = read(fd, ptr, len); > + ret = errno; My reading of the man page is that errno is set only if read() returns -1. > + mte_wait_after_trig(); > + if ((cur_mte_cxt.fault_valid == true) || ret == EFAULT || read_len < len) > + goto usermem_acc_err; > + /* Verify same pattern is read */ > + for (i = 0; i < len; i++) > + if (*(char *)(ptr + i) != val) > + break; > + if (i < len) > + goto usermem_acc_err; > + > + /* Tag the next half of memory with different value */ > + ptr_next = (void *)((unsigned long)ptr + page_sz); > + ptr_next = mte_insert_tags(ptr_next, page_sz); > + if (!ptr_next) > + goto usermem_acc_err; > + lseek(fd, 0, 0); > + /* Copy from file into buffer with invalid tag */ > + read_len = read(fd, ptr, len); > + ret = errno; > + mte_wait_after_trig(); > + if ((fault == true) && Nitpick: just use "if (fault &&), it's a bool already. > + (cur_mte_cxt.fault_valid == true || ret == EFAULT || read_len < len)) { > + err = KSFT_PASS; > + } else if ((fault == false) && > + (cur_mte_cxt.fault_valid == false && read_len == len)) { Same here, !fault, !cur_mte_cxt.fault_valid. -- Catalin