cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

check_buffer_fill.c (14956B)


      1// SPDX-License-Identifier: GPL-2.0
      2// Copyright (C) 2020 ARM Limited
      3
      4#define _GNU_SOURCE
      5
      6#include <stddef.h>
      7#include <stdio.h>
      8#include <string.h>
      9
     10#include "kselftest.h"
     11#include "mte_common_util.h"
     12#include "mte_def.h"
     13
     14#define OVERFLOW_RANGE MT_GRANULE_SIZE
     15
     16static int sizes[] = {
     17	1, 555, 1033, MT_GRANULE_SIZE - 1, MT_GRANULE_SIZE,
     18	/* page size - 1*/ 0, /* page_size */ 0, /* page size + 1 */ 0
     19};
     20
     21enum mte_block_test_alloc {
     22	UNTAGGED_TAGGED,
     23	TAGGED_UNTAGGED,
     24	TAGGED_TAGGED,
     25	BLOCK_ALLOC_MAX,
     26};
     27
     28static int check_buffer_by_byte(int mem_type, int mode)
     29{
     30	char *ptr;
     31	int i, j, item;
     32	bool err;
     33
     34	mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
     35	item = sizeof(sizes)/sizeof(int);
     36
     37	for (i = 0; i < item; i++) {
     38		ptr = (char *)mte_allocate_memory(sizes[i], mem_type, 0, true);
     39		if (check_allocated_memory(ptr, sizes[i], mem_type, true) != KSFT_PASS)
     40			return KSFT_FAIL;
     41		mte_initialize_current_context(mode, (uintptr_t)ptr, sizes[i]);
     42		/* Set some value in tagged memory */
     43		for (j = 0; j < sizes[i]; j++)
     44			ptr[j] = '1';
     45		mte_wait_after_trig();
     46		err = cur_mte_cxt.fault_valid;
     47		/* Check the buffer whether it is filled. */
     48		for (j = 0; j < sizes[i] && !err; j++) {
     49			if (ptr[j] != '1')
     50				err = true;
     51		}
     52		mte_free_memory((void *)ptr, sizes[i], mem_type, true);
     53
     54		if (err)
     55			break;
     56	}
     57	if (!err)
     58		return KSFT_PASS;
     59	else
     60		return KSFT_FAIL;
     61}
     62
     63static int check_buffer_underflow_by_byte(int mem_type, int mode,
     64					  int underflow_range)
     65{
     66	char *ptr;
     67	int i, j, item, last_index;
     68	bool err;
     69	char *und_ptr = NULL;
     70
     71	mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
     72	item = sizeof(sizes)/sizeof(int);
     73	for (i = 0; i < item; i++) {
     74		ptr = (char *)mte_allocate_memory_tag_range(sizes[i], mem_type, 0,
     75							    underflow_range, 0);
     76		if (check_allocated_memory_range(ptr, sizes[i], mem_type,
     77					       underflow_range, 0) != KSFT_PASS)
     78			return KSFT_FAIL;
     79
     80		mte_initialize_current_context(mode, (uintptr_t)ptr, -underflow_range);
     81		last_index = 0;
     82		/* Set some value in tagged memory and make the buffer underflow */
     83		for (j = sizes[i] - 1; (j >= -underflow_range) &&
     84				       (!cur_mte_cxt.fault_valid); j--) {
     85			ptr[j] = '1';
     86			last_index = j;
     87		}
     88		mte_wait_after_trig();
     89		err = false;
     90		/* Check whether the buffer is filled */
     91		for (j = 0; j < sizes[i]; j++) {
     92			if (ptr[j] != '1') {
     93				err = true;
     94				ksft_print_msg("Buffer is not filled at index:%d of ptr:0x%lx\n",
     95						j, ptr);
     96				break;
     97			}
     98		}
     99		if (err)
    100			goto check_buffer_underflow_by_byte_err;
    101
    102		switch (mode) {
    103		case MTE_NONE_ERR:
    104			if (cur_mte_cxt.fault_valid == true || last_index != -underflow_range) {
    105				err = true;
    106				break;
    107			}
    108			/* There were no fault so the underflow area should be filled */
    109			und_ptr = (char *) MT_CLEAR_TAG((size_t) ptr - underflow_range);
    110			for (j = 0 ; j < underflow_range; j++) {
    111				if (und_ptr[j] != '1') {
    112					err = true;
    113					break;
    114				}
    115			}
    116			break;
    117		case MTE_ASYNC_ERR:
    118			/* Imprecise fault should occur otherwise return error */
    119			if (cur_mte_cxt.fault_valid == false) {
    120				err = true;
    121				break;
    122			}
    123			/*
    124			 * The imprecise fault is checked after the write to the buffer,
    125			 * so the underflow area before the fault should be filled.
    126			 */
    127			und_ptr = (char *) MT_CLEAR_TAG((size_t) ptr);
    128			for (j = last_index ; j < 0 ; j++) {
    129				if (und_ptr[j] != '1') {
    130					err = true;
    131					break;
    132				}
    133			}
    134			break;
    135		case MTE_SYNC_ERR:
    136			/* Precise fault should occur otherwise return error */
    137			if (!cur_mte_cxt.fault_valid || (last_index != (-1))) {
    138				err = true;
    139				break;
    140			}
    141			/* Underflow area should not be filled */
    142			und_ptr = (char *) MT_CLEAR_TAG((size_t) ptr);
    143			if (und_ptr[-1] == '1')
    144				err = true;
    145			break;
    146		default:
    147			err = true;
    148		break;
    149		}
    150check_buffer_underflow_by_byte_err:
    151		mte_free_memory_tag_range((void *)ptr, sizes[i], mem_type, underflow_range, 0);
    152		if (err)
    153			break;
    154	}
    155	return (err ? KSFT_FAIL : KSFT_PASS);
    156}
    157
    158static int check_buffer_overflow_by_byte(int mem_type, int mode,
    159					  int overflow_range)
    160{
    161	char *ptr;
    162	int i, j, item, last_index;
    163	bool err;
    164	size_t tagged_size, overflow_size;
    165	char *over_ptr = NULL;
    166
    167	mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
    168	item = sizeof(sizes)/sizeof(int);
    169	for (i = 0; i < item; i++) {
    170		ptr = (char *)mte_allocate_memory_tag_range(sizes[i], mem_type, 0,
    171							    0, overflow_range);
    172		if (check_allocated_memory_range(ptr, sizes[i], mem_type,
    173						 0, overflow_range) != KSFT_PASS)
    174			return KSFT_FAIL;
    175
    176		tagged_size = MT_ALIGN_UP(sizes[i]);
    177
    178		mte_initialize_current_context(mode, (uintptr_t)ptr, sizes[i] + overflow_range);
    179
    180		/* Set some value in tagged memory and make the buffer underflow */
    181		for (j = 0, last_index = 0 ; (j < (sizes[i] + overflow_range)) &&
    182					     (cur_mte_cxt.fault_valid == false); j++) {
    183			ptr[j] = '1';
    184			last_index = j;
    185		}
    186		mte_wait_after_trig();
    187		err = false;
    188		/* Check whether the buffer is filled */
    189		for (j = 0; j < sizes[i]; j++) {
    190			if (ptr[j] != '1') {
    191				err = true;
    192				ksft_print_msg("Buffer is not filled at index:%d of ptr:0x%lx\n",
    193						j, ptr);
    194				break;
    195			}
    196		}
    197		if (err)
    198			goto check_buffer_overflow_by_byte_err;
    199
    200		overflow_size = overflow_range - (tagged_size - sizes[i]);
    201
    202		switch (mode) {
    203		case MTE_NONE_ERR:
    204			if ((cur_mte_cxt.fault_valid == true) ||
    205			    (last_index != (sizes[i] + overflow_range - 1))) {
    206				err = true;
    207				break;
    208			}
    209			/* There were no fault so the overflow area should be filled */
    210			over_ptr = (char *) MT_CLEAR_TAG((size_t) ptr + tagged_size);
    211			for (j = 0 ; j < overflow_size; j++) {
    212				if (over_ptr[j] != '1') {
    213					err = true;
    214					break;
    215				}
    216			}
    217			break;
    218		case MTE_ASYNC_ERR:
    219			/* Imprecise fault should occur otherwise return error */
    220			if (cur_mte_cxt.fault_valid == false) {
    221				err = true;
    222				break;
    223			}
    224			/*
    225			 * The imprecise fault is checked after the write to the buffer,
    226			 * so the overflow area should be filled before the fault.
    227			 */
    228			over_ptr = (char *) MT_CLEAR_TAG((size_t) ptr);
    229			for (j = tagged_size ; j < last_index; j++) {
    230				if (over_ptr[j] != '1') {
    231					err = true;
    232					break;
    233				}
    234			}
    235			break;
    236		case MTE_SYNC_ERR:
    237			/* Precise fault should occur otherwise return error */
    238			if (!cur_mte_cxt.fault_valid || (last_index != tagged_size)) {
    239				err = true;
    240				break;
    241			}
    242			/* Underflow area should not be filled */
    243			over_ptr = (char *) MT_CLEAR_TAG((size_t) ptr + tagged_size);
    244			for (j = 0 ; j < overflow_size; j++) {
    245				if (over_ptr[j] == '1')
    246					err = true;
    247			}
    248			break;
    249		default:
    250			err = true;
    251		break;
    252		}
    253check_buffer_overflow_by_byte_err:
    254		mte_free_memory_tag_range((void *)ptr, sizes[i], mem_type, 0, overflow_range);
    255		if (err)
    256			break;
    257	}
    258	return (err ? KSFT_FAIL : KSFT_PASS);
    259}
    260
    261static int check_buffer_by_block_iterate(int mem_type, int mode, size_t size)
    262{
    263	char *src, *dst;
    264	int j, result = KSFT_PASS;
    265	enum mte_block_test_alloc alloc_type = UNTAGGED_TAGGED;
    266
    267	for (alloc_type = UNTAGGED_TAGGED; alloc_type < (int) BLOCK_ALLOC_MAX; alloc_type++) {
    268		switch (alloc_type) {
    269		case UNTAGGED_TAGGED:
    270			src = (char *)mte_allocate_memory(size, mem_type, 0, false);
    271			if (check_allocated_memory(src, size, mem_type, false) != KSFT_PASS)
    272				return KSFT_FAIL;
    273
    274			dst = (char *)mte_allocate_memory(size, mem_type, 0, true);
    275			if (check_allocated_memory(dst, size, mem_type, true) != KSFT_PASS) {
    276				mte_free_memory((void *)src, size, mem_type, false);
    277				return KSFT_FAIL;
    278			}
    279
    280			break;
    281		case TAGGED_UNTAGGED:
    282			dst = (char *)mte_allocate_memory(size, mem_type, 0, false);
    283			if (check_allocated_memory(dst, size, mem_type, false) != KSFT_PASS)
    284				return KSFT_FAIL;
    285
    286			src = (char *)mte_allocate_memory(size, mem_type, 0, true);
    287			if (check_allocated_memory(src, size, mem_type, true) != KSFT_PASS) {
    288				mte_free_memory((void *)dst, size, mem_type, false);
    289				return KSFT_FAIL;
    290			}
    291			break;
    292		case TAGGED_TAGGED:
    293			src = (char *)mte_allocate_memory(size, mem_type, 0, true);
    294			if (check_allocated_memory(src, size, mem_type, true) != KSFT_PASS)
    295				return KSFT_FAIL;
    296
    297			dst = (char *)mte_allocate_memory(size, mem_type, 0, true);
    298			if (check_allocated_memory(dst, size, mem_type, true) != KSFT_PASS) {
    299				mte_free_memory((void *)src, size, mem_type, true);
    300				return KSFT_FAIL;
    301			}
    302			break;
    303		default:
    304			return KSFT_FAIL;
    305		}
    306
    307		cur_mte_cxt.fault_valid = false;
    308		result = KSFT_PASS;
    309		mte_initialize_current_context(mode, (uintptr_t)dst, size);
    310		/* Set some value in memory and copy*/
    311		memset((void *)src, (int)'1', size);
    312		memcpy((void *)dst, (void *)src, size);
    313		mte_wait_after_trig();
    314		if (cur_mte_cxt.fault_valid) {
    315			result = KSFT_FAIL;
    316			goto check_buffer_by_block_err;
    317		}
    318		/* Check the buffer whether it is filled. */
    319		for (j = 0; j < size; j++) {
    320			if (src[j] != dst[j] || src[j] != '1') {
    321				result = KSFT_FAIL;
    322				break;
    323			}
    324		}
    325check_buffer_by_block_err:
    326		mte_free_memory((void *)src, size, mem_type,
    327				MT_FETCH_TAG((uintptr_t)src) ? true : false);
    328		mte_free_memory((void *)dst, size, mem_type,
    329				MT_FETCH_TAG((uintptr_t)dst) ? true : false);
    330		if (result != KSFT_PASS)
    331			return result;
    332	}
    333	return result;
    334}
    335
    336static int check_buffer_by_block(int mem_type, int mode)
    337{
    338	int i, item, result = KSFT_PASS;
    339
    340	mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
    341	item = sizeof(sizes)/sizeof(int);
    342	cur_mte_cxt.fault_valid = false;
    343	for (i = 0; i < item; i++) {
    344		result = check_buffer_by_block_iterate(mem_type, mode, sizes[i]);
    345		if (result != KSFT_PASS)
    346			break;
    347	}
    348	return result;
    349}
    350
    351static int compare_memory_tags(char *ptr, size_t size, int tag)
    352{
    353	int i, new_tag;
    354
    355	for (i = 0 ; i < size ; i += MT_GRANULE_SIZE) {
    356		new_tag = MT_FETCH_TAG((uintptr_t)(mte_get_tag_address(ptr + i)));
    357		if (tag != new_tag) {
    358			ksft_print_msg("FAIL: child mte tag mismatch\n");
    359			return KSFT_FAIL;
    360		}
    361	}
    362	return KSFT_PASS;
    363}
    364
    365static int check_memory_initial_tags(int mem_type, int mode, int mapping)
    366{
    367	char *ptr;
    368	int run, fd;
    369	int total = sizeof(sizes)/sizeof(int);
    370
    371	mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
    372	for (run = 0; run < total; run++) {
    373		/* check initial tags for anonymous mmap */
    374		ptr = (char *)mte_allocate_memory(sizes[run], mem_type, mapping, false);
    375		if (check_allocated_memory(ptr, sizes[run], mem_type, false) != KSFT_PASS)
    376			return KSFT_FAIL;
    377		if (compare_memory_tags(ptr, sizes[run], 0) != KSFT_PASS) {
    378			mte_free_memory((void *)ptr, sizes[run], mem_type, false);
    379			return KSFT_FAIL;
    380		}
    381		mte_free_memory((void *)ptr, sizes[run], mem_type, false);
    382
    383		/* check initial tags for file mmap */
    384		fd = create_temp_file();
    385		if (fd == -1)
    386			return KSFT_FAIL;
    387		ptr = (char *)mte_allocate_file_memory(sizes[run], mem_type, mapping, false, fd);
    388		if (check_allocated_memory(ptr, sizes[run], mem_type, false) != KSFT_PASS) {
    389			close(fd);
    390			return KSFT_FAIL;
    391		}
    392		if (compare_memory_tags(ptr, sizes[run], 0) != KSFT_PASS) {
    393			mte_free_memory((void *)ptr, sizes[run], mem_type, false);
    394			close(fd);
    395			return KSFT_FAIL;
    396		}
    397		mte_free_memory((void *)ptr, sizes[run], mem_type, false);
    398		close(fd);
    399	}
    400	return KSFT_PASS;
    401}
    402
    403int main(int argc, char *argv[])
    404{
    405	int err;
    406	size_t page_size = getpagesize();
    407	int item = sizeof(sizes)/sizeof(int);
    408
    409	sizes[item - 3] = page_size - 1;
    410	sizes[item - 2] = page_size;
    411	sizes[item - 1] = page_size + 1;
    412
    413	err = mte_default_setup();
    414	if (err)
    415		return err;
    416
    417	/* Register SIGSEGV handler */
    418	mte_register_signal(SIGSEGV, mte_default_handler);
    419
    420	/* Set test plan */
    421	ksft_set_plan(20);
    422
    423	/* Buffer by byte tests */
    424	evaluate_test(check_buffer_by_byte(USE_MMAP, MTE_SYNC_ERR),
    425	"Check buffer correctness by byte with sync err mode and mmap memory\n");
    426	evaluate_test(check_buffer_by_byte(USE_MMAP, MTE_ASYNC_ERR),
    427	"Check buffer correctness by byte with async err mode and mmap memory\n");
    428	evaluate_test(check_buffer_by_byte(USE_MPROTECT, MTE_SYNC_ERR),
    429	"Check buffer correctness by byte with sync err mode and mmap/mprotect memory\n");
    430	evaluate_test(check_buffer_by_byte(USE_MPROTECT, MTE_ASYNC_ERR),
    431	"Check buffer correctness by byte with async err mode and mmap/mprotect memory\n");
    432
    433	/* Check buffer underflow with underflow size as 16 */
    434	evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_SYNC_ERR, MT_GRANULE_SIZE),
    435	"Check buffer write underflow by byte with sync mode and mmap memory\n");
    436	evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_ASYNC_ERR, MT_GRANULE_SIZE),
    437	"Check buffer write underflow by byte with async mode and mmap memory\n");
    438	evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_NONE_ERR, MT_GRANULE_SIZE),
    439	"Check buffer write underflow by byte with tag check fault ignore and mmap memory\n");
    440
    441	/* Check buffer underflow with underflow size as page size */
    442	evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_SYNC_ERR, page_size),
    443	"Check buffer write underflow by byte with sync mode and mmap memory\n");
    444	evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_ASYNC_ERR, page_size),
    445	"Check buffer write underflow by byte with async mode and mmap memory\n");
    446	evaluate_test(check_buffer_underflow_by_byte(USE_MMAP, MTE_NONE_ERR, page_size),
    447	"Check buffer write underflow by byte with tag check fault ignore and mmap memory\n");
    448
    449	/* Check buffer overflow with overflow size as 16 */
    450	evaluate_test(check_buffer_overflow_by_byte(USE_MMAP, MTE_SYNC_ERR, MT_GRANULE_SIZE),
    451	"Check buffer write overflow by byte with sync mode and mmap memory\n");
    452	evaluate_test(check_buffer_overflow_by_byte(USE_MMAP, MTE_ASYNC_ERR, MT_GRANULE_SIZE),
    453	"Check buffer write overflow by byte with async mode and mmap memory\n");
    454	evaluate_test(check_buffer_overflow_by_byte(USE_MMAP, MTE_NONE_ERR, MT_GRANULE_SIZE),
    455	"Check buffer write overflow by byte with tag fault ignore mode and mmap memory\n");
    456
    457	/* Buffer by block tests */
    458	evaluate_test(check_buffer_by_block(USE_MMAP, MTE_SYNC_ERR),
    459	"Check buffer write correctness by block with sync mode and mmap memory\n");
    460	evaluate_test(check_buffer_by_block(USE_MMAP, MTE_ASYNC_ERR),
    461	"Check buffer write correctness by block with async mode and mmap memory\n");
    462	evaluate_test(check_buffer_by_block(USE_MMAP, MTE_NONE_ERR),
    463	"Check buffer write correctness by block with tag fault ignore and mmap memory\n");
    464
    465	/* Initial tags are supposed to be 0 */
    466	evaluate_test(check_memory_initial_tags(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),
    467	"Check initial tags with private mapping, sync error mode and mmap memory\n");
    468	evaluate_test(check_memory_initial_tags(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE),
    469	"Check initial tags with private mapping, sync error mode and mmap/mprotect memory\n");
    470	evaluate_test(check_memory_initial_tags(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED),
    471	"Check initial tags with shared mapping, sync error mode and mmap memory\n");
    472	evaluate_test(check_memory_initial_tags(USE_MPROTECT, MTE_SYNC_ERR, MAP_SHARED),
    473	"Check initial tags with shared mapping, sync error mode and mmap/mprotect memory\n");
    474
    475	mte_restore_setup();
    476	ksft_print_cnts();
    477	return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
    478}