Path: blob/master/tools/testing/selftests/arm64/mte/check_buffer_fill.c
26296 views
// SPDX-License-Identifier: GPL-2.01// Copyright (C) 2020 ARM Limited23#define _GNU_SOURCE45#include <stddef.h>6#include <stdio.h>7#include <string.h>89#include "kselftest.h"10#include "mte_common_util.h"11#include "mte_def.h"1213#define OVERFLOW_RANGE MT_GRANULE_SIZE1415static int sizes[] = {161, 555, 1033, MT_GRANULE_SIZE - 1, MT_GRANULE_SIZE,17/* page size - 1*/ 0, /* page_size */ 0, /* page size + 1 */ 018};1920enum mte_block_test_alloc {21UNTAGGED_TAGGED,22TAGGED_UNTAGGED,23TAGGED_TAGGED,24BLOCK_ALLOC_MAX,25};2627static int check_buffer_by_byte(int mem_type, int mode)28{29char *ptr;30int i, j, item;31bool err;3233mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);34item = ARRAY_SIZE(sizes);3536for (i = 0; i < item; i++) {37ptr = (char *)mte_allocate_memory(sizes[i], mem_type, 0, true);38if (check_allocated_memory(ptr, sizes[i], mem_type, true) != KSFT_PASS)39return KSFT_FAIL;40mte_initialize_current_context(mode, (uintptr_t)ptr, sizes[i]);41/* Set some value in tagged memory */42for (j = 0; j < sizes[i]; j++)43ptr[j] = '1';44mte_wait_after_trig();45err = cur_mte_cxt.fault_valid;46/* Check the buffer whether it is filled. */47for (j = 0; j < sizes[i] && !err; j++) {48if (ptr[j] != '1')49err = true;50}51mte_free_memory((void *)ptr, sizes[i], mem_type, true);5253if (err)54break;55}56if (!err)57return KSFT_PASS;58else59return KSFT_FAIL;60}6162static int check_buffer_underflow_by_byte(int mem_type, int mode,63int underflow_range)64{65char *ptr;66int i, j, item, last_index;67bool err;68char *und_ptr = NULL;6970mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);71item = ARRAY_SIZE(sizes);72for (i = 0; i < item; i++) {73ptr = (char *)mte_allocate_memory_tag_range(sizes[i], mem_type, 0,74underflow_range, 0);75if (check_allocated_memory_range(ptr, sizes[i], mem_type,76underflow_range, 0) != KSFT_PASS)77return KSFT_FAIL;7879mte_initialize_current_context(mode, (uintptr_t)ptr, -underflow_range);80last_index = 0;81/* Set some value in tagged memory and make the buffer underflow */82for (j = sizes[i] - 1; (j >= -underflow_range) &&83(!cur_mte_cxt.fault_valid); j--) {84ptr[j] = '1';85last_index = j;86}87mte_wait_after_trig();88err = false;89/* Check whether the buffer is filled */90for (j = 0; j < sizes[i]; j++) {91if (ptr[j] != '1') {92err = true;93ksft_print_msg("Buffer is not filled at index:%d of ptr:0x%p\n",94j, ptr);95break;96}97}98if (err)99goto check_buffer_underflow_by_byte_err;100101switch (mode) {102case MTE_NONE_ERR:103if (cur_mte_cxt.fault_valid == true || last_index != -underflow_range) {104err = true;105break;106}107/* There were no fault so the underflow area should be filled */108und_ptr = (char *) MT_CLEAR_TAG((size_t) ptr - underflow_range);109for (j = 0 ; j < underflow_range; j++) {110if (und_ptr[j] != '1') {111err = true;112break;113}114}115break;116case MTE_ASYNC_ERR:117/* Imprecise fault should occur otherwise return error */118if (cur_mte_cxt.fault_valid == false) {119err = true;120break;121}122/*123* The imprecise fault is checked after the write to the buffer,124* so the underflow area before the fault should be filled.125*/126und_ptr = (char *) MT_CLEAR_TAG((size_t) ptr);127for (j = last_index ; j < 0 ; j++) {128if (und_ptr[j] != '1') {129err = true;130break;131}132}133break;134case MTE_SYNC_ERR:135/* Precise fault should occur otherwise return error */136if (!cur_mte_cxt.fault_valid || (last_index != (-1))) {137err = true;138break;139}140/* Underflow area should not be filled */141und_ptr = (char *) MT_CLEAR_TAG((size_t) ptr);142if (und_ptr[-1] == '1')143err = true;144break;145default:146err = true;147break;148}149check_buffer_underflow_by_byte_err:150mte_free_memory_tag_range((void *)ptr, sizes[i], mem_type, underflow_range, 0);151if (err)152break;153}154return (err ? KSFT_FAIL : KSFT_PASS);155}156157static int check_buffer_overflow_by_byte(int mem_type, int mode,158int overflow_range)159{160char *ptr;161int i, j, item, last_index;162bool err;163size_t tagged_size, overflow_size;164char *over_ptr = NULL;165166mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);167item = ARRAY_SIZE(sizes);168for (i = 0; i < item; i++) {169ptr = (char *)mte_allocate_memory_tag_range(sizes[i], mem_type, 0,1700, overflow_range);171if (check_allocated_memory_range(ptr, sizes[i], mem_type,1720, overflow_range) != KSFT_PASS)173return KSFT_FAIL;174175tagged_size = MT_ALIGN_UP(sizes[i]);176177mte_initialize_current_context(mode, (uintptr_t)ptr, sizes[i] + overflow_range);178179/* Set some value in tagged memory and make the buffer underflow */180for (j = 0, last_index = 0 ; (j < (sizes[i] + overflow_range)) &&181(cur_mte_cxt.fault_valid == false); j++) {182ptr[j] = '1';183last_index = j;184}185mte_wait_after_trig();186err = false;187/* Check whether the buffer is filled */188for (j = 0; j < sizes[i]; j++) {189if (ptr[j] != '1') {190err = true;191ksft_print_msg("Buffer is not filled at index:%d of ptr:0x%p\n",192j, ptr);193break;194}195}196if (err)197goto check_buffer_overflow_by_byte_err;198199overflow_size = overflow_range - (tagged_size - sizes[i]);200201switch (mode) {202case MTE_NONE_ERR:203if ((cur_mte_cxt.fault_valid == true) ||204(last_index != (sizes[i] + overflow_range - 1))) {205err = true;206break;207}208/* There were no fault so the overflow area should be filled */209over_ptr = (char *) MT_CLEAR_TAG((size_t) ptr + tagged_size);210for (j = 0 ; j < overflow_size; j++) {211if (over_ptr[j] != '1') {212err = true;213break;214}215}216break;217case MTE_ASYNC_ERR:218/* Imprecise fault should occur otherwise return error */219if (cur_mte_cxt.fault_valid == false) {220err = true;221break;222}223/*224* The imprecise fault is checked after the write to the buffer,225* so the overflow area should be filled before the fault.226*/227over_ptr = (char *) MT_CLEAR_TAG((size_t) ptr);228for (j = tagged_size ; j < last_index; j++) {229if (over_ptr[j] != '1') {230err = true;231break;232}233}234break;235case MTE_SYNC_ERR:236/* Precise fault should occur otherwise return error */237if (!cur_mte_cxt.fault_valid || (last_index != tagged_size)) {238err = true;239break;240}241/* Underflow area should not be filled */242over_ptr = (char *) MT_CLEAR_TAG((size_t) ptr + tagged_size);243for (j = 0 ; j < overflow_size; j++) {244if (over_ptr[j] == '1')245err = true;246}247break;248default:249err = true;250break;251}252check_buffer_overflow_by_byte_err:253mte_free_memory_tag_range((void *)ptr, sizes[i], mem_type, 0, overflow_range);254if (err)255break;256}257return (err ? KSFT_FAIL : KSFT_PASS);258}259260static int check_buffer_by_block_iterate(int mem_type, int mode, size_t size)261{262char *src, *dst;263int j, result = KSFT_PASS;264enum mte_block_test_alloc alloc_type = UNTAGGED_TAGGED;265266for (alloc_type = UNTAGGED_TAGGED; alloc_type < (int) BLOCK_ALLOC_MAX; alloc_type++) {267switch (alloc_type) {268case UNTAGGED_TAGGED:269src = (char *)mte_allocate_memory(size, mem_type, 0, false);270if (check_allocated_memory(src, size, mem_type, false) != KSFT_PASS)271return KSFT_FAIL;272273dst = (char *)mte_allocate_memory(size, mem_type, 0, true);274if (check_allocated_memory(dst, size, mem_type, true) != KSFT_PASS) {275mte_free_memory((void *)src, size, mem_type, false);276return KSFT_FAIL;277}278279break;280case TAGGED_UNTAGGED:281dst = (char *)mte_allocate_memory(size, mem_type, 0, false);282if (check_allocated_memory(dst, size, mem_type, false) != KSFT_PASS)283return KSFT_FAIL;284285src = (char *)mte_allocate_memory(size, mem_type, 0, true);286if (check_allocated_memory(src, size, mem_type, true) != KSFT_PASS) {287mte_free_memory((void *)dst, size, mem_type, false);288return KSFT_FAIL;289}290break;291case TAGGED_TAGGED:292src = (char *)mte_allocate_memory(size, mem_type, 0, true);293if (check_allocated_memory(src, size, mem_type, true) != KSFT_PASS)294return KSFT_FAIL;295296dst = (char *)mte_allocate_memory(size, mem_type, 0, true);297if (check_allocated_memory(dst, size, mem_type, true) != KSFT_PASS) {298mte_free_memory((void *)src, size, mem_type, true);299return KSFT_FAIL;300}301break;302default:303return KSFT_FAIL;304}305306cur_mte_cxt.fault_valid = false;307result = KSFT_PASS;308mte_initialize_current_context(mode, (uintptr_t)dst, size);309/* Set some value in memory and copy*/310memset((void *)src, (int)'1', size);311memcpy((void *)dst, (void *)src, size);312mte_wait_after_trig();313if (cur_mte_cxt.fault_valid) {314result = KSFT_FAIL;315goto check_buffer_by_block_err;316}317/* Check the buffer whether it is filled. */318for (j = 0; j < size; j++) {319if (src[j] != dst[j] || src[j] != '1') {320result = KSFT_FAIL;321break;322}323}324check_buffer_by_block_err:325mte_free_memory((void *)src, size, mem_type,326MT_FETCH_TAG((uintptr_t)src) ? true : false);327mte_free_memory((void *)dst, size, mem_type,328MT_FETCH_TAG((uintptr_t)dst) ? true : false);329if (result != KSFT_PASS)330return result;331}332return result;333}334335static int check_buffer_by_block(int mem_type, int mode)336{337int i, item, result = KSFT_PASS;338339mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);340item = ARRAY_SIZE(sizes);341cur_mte_cxt.fault_valid = false;342for (i = 0; i < item; i++) {343result = check_buffer_by_block_iterate(mem_type, mode, sizes[i]);344if (result != KSFT_PASS)345break;346}347return result;348}349350static int compare_memory_tags(char *ptr, size_t size, int tag)351{352int i, new_tag;353354for (i = 0 ; i < size ; i += MT_GRANULE_SIZE) {355new_tag = MT_FETCH_TAG((uintptr_t)(mte_get_tag_address(ptr + i)));356if (tag != new_tag) {357ksft_print_msg("FAIL: child mte tag mismatch\n");358return KSFT_FAIL;359}360}361return KSFT_PASS;362}363364static int check_memory_initial_tags(int mem_type, int mode, int mapping)365{366char *ptr;367int run, fd;368int total = ARRAY_SIZE(sizes);369370mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);371for (run = 0; run < total; run++) {372/* check initial tags for anonymous mmap */373ptr = (char *)mte_allocate_memory(sizes[run], mem_type, mapping, false);374if (check_allocated_memory(ptr, sizes[run], mem_type, false) != KSFT_PASS)375return KSFT_FAIL;376if (compare_memory_tags(ptr, sizes[run], 0) != KSFT_PASS) {377mte_free_memory((void *)ptr, sizes[run], mem_type, false);378return KSFT_FAIL;379}380mte_free_memory((void *)ptr, sizes[run], mem_type, false);381382/* check initial tags for file mmap */383fd = create_temp_file();384if (fd == -1)385return KSFT_FAIL;386ptr = (char *)mte_allocate_file_memory(sizes[run], mem_type, mapping, false, fd);387if (check_allocated_memory(ptr, sizes[run], mem_type, false) != KSFT_PASS) {388close(fd);389return KSFT_FAIL;390}391if (compare_memory_tags(ptr, sizes[run], 0) != KSFT_PASS) {392mte_free_memory((void *)ptr, sizes[run], mem_type, false);393close(fd);394return KSFT_FAIL;395}396mte_free_memory((void *)ptr, sizes[run], mem_type, false);397close(fd);398}399return KSFT_PASS;400}401402int main(int argc, char *argv[])403{404int err;405size_t page_size = getpagesize();406int item = ARRAY_SIZE(sizes);407408sizes[item - 3] = page_size - 1;409sizes[item - 2] = page_size;410sizes[item - 1] = page_size + 1;411412err = mte_default_setup();413if (err)414return err;415416/* Register SIGSEGV handler */417mte_register_signal(SIGSEGV, mte_default_handler, false);418419/* Set test plan */420ksft_set_plan(20);421422/* Buffer by byte tests */423evaluate_test(check_buffer_by_byte(USE_MMAP, MTE_SYNC_ERR),424"Check buffer correctness by byte with sync err mode and mmap memory\n");425evaluate_test(check_buffer_by_byte(USE_MMAP, MTE_ASYNC_ERR),426"Check buffer correctness by byte with async err mode and mmap memory\n");427evaluate_test(check_buffer_by_byte(USE_MPROTECT, MTE_SYNC_ERR),428"Check buffer correctness by byte with sync err mode and mmap/mprotect memory\n");429evaluate_test(check_buffer_by_byte(USE_MPROTECT, MTE_ASYNC_ERR),430"Check buffer correctness by byte with async err mode and mmap/mprotect memory\n");431432/* Check buffer underflow with underflow size as 16 */433evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_SYNC_ERR, MT_GRANULE_SIZE),434"Check buffer write underflow by byte with sync mode and mmap memory\n");435evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_ASYNC_ERR, MT_GRANULE_SIZE),436"Check buffer write underflow by byte with async mode and mmap memory\n");437evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_NONE_ERR, MT_GRANULE_SIZE),438"Check buffer write underflow by byte with tag check fault ignore and mmap memory\n");439440/* Check buffer underflow with underflow size as page size */441evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_SYNC_ERR, page_size),442"Check buffer write underflow by byte with sync mode and mmap memory\n");443evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_ASYNC_ERR, page_size),444"Check buffer write underflow by byte with async mode and mmap memory\n");445evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_NONE_ERR, page_size),446"Check buffer write underflow by byte with tag check fault ignore and mmap memory\n");447448/* Check buffer overflow with overflow size as 16 */449evaluate_test(check_buffer_overflow_by_byte(USE_MMAP, MTE_SYNC_ERR, MT_GRANULE_SIZE),450"Check buffer write overflow by byte with sync mode and mmap memory\n");451evaluate_test(check_buffer_overflow_by_byte(USE_MMAP, MTE_ASYNC_ERR, MT_GRANULE_SIZE),452"Check buffer write overflow by byte with async mode and mmap memory\n");453evaluate_test(check_buffer_overflow_by_byte(USE_MMAP, MTE_NONE_ERR, MT_GRANULE_SIZE),454"Check buffer write overflow by byte with tag fault ignore mode and mmap memory\n");455456/* Buffer by block tests */457evaluate_test(check_buffer_by_block(USE_MMAP, MTE_SYNC_ERR),458"Check buffer write correctness by block with sync mode and mmap memory\n");459evaluate_test(check_buffer_by_block(USE_MMAP, MTE_ASYNC_ERR),460"Check buffer write correctness by block with async mode and mmap memory\n");461evaluate_test(check_buffer_by_block(USE_MMAP, MTE_NONE_ERR),462"Check buffer write correctness by block with tag fault ignore and mmap memory\n");463464/* Initial tags are supposed to be 0 */465evaluate_test(check_memory_initial_tags(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),466"Check initial tags with private mapping, sync error mode and mmap memory\n");467evaluate_test(check_memory_initial_tags(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE),468"Check initial tags with private mapping, sync error mode and mmap/mprotect memory\n");469evaluate_test(check_memory_initial_tags(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED),470"Check initial tags with shared mapping, sync error mode and mmap memory\n");471evaluate_test(check_memory_initial_tags(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED),472"Check initial tags with shared mapping, sync error mode and mmap/mprotect memory\n");473474mte_restore_setup();475ksft_print_cnts();476return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;477}478479480