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

soft-dirty.c (3624B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <stdio.h>
      3#include <string.h>
      4#include <stdbool.h>
      5#include <fcntl.h>
      6#include <stdint.h>
      7#include <malloc.h>
      8#include <sys/mman.h>
      9#include "../kselftest.h"
     10#include "vm_util.h"
     11
     12#define PAGEMAP_FILE_PATH "/proc/self/pagemap"
     13#define TEST_ITERATIONS 10000
     14
     15static void test_simple(int pagemap_fd, int pagesize)
     16{
     17	int i;
     18	char *map;
     19
     20	map = aligned_alloc(pagesize, pagesize);
     21	if (!map)
     22		ksft_exit_fail_msg("mmap failed\n");
     23
     24	clear_softdirty();
     25
     26	for (i = 0 ; i < TEST_ITERATIONS; i++) {
     27		if (pagemap_is_softdirty(pagemap_fd, map) == 1) {
     28			ksft_print_msg("dirty bit was 1, but should be 0 (i=%d)\n", i);
     29			break;
     30		}
     31
     32		clear_softdirty();
     33		// Write something to the page to get the dirty bit enabled on the page
     34		map[0]++;
     35
     36		if (pagemap_is_softdirty(pagemap_fd, map) == 0) {
     37			ksft_print_msg("dirty bit was 0, but should be 1 (i=%d)\n", i);
     38			break;
     39		}
     40
     41		clear_softdirty();
     42	}
     43	free(map);
     44
     45	ksft_test_result(i == TEST_ITERATIONS, "Test %s\n", __func__);
     46}
     47
     48static void test_vma_reuse(int pagemap_fd, int pagesize)
     49{
     50	char *map, *map2;
     51
     52	map = mmap(NULL, pagesize, (PROT_READ | PROT_WRITE), (MAP_PRIVATE | MAP_ANON), -1, 0);
     53	if (map == MAP_FAILED)
     54		ksft_exit_fail_msg("mmap failed");
     55
     56	// The kernel always marks new regions as soft dirty
     57	ksft_test_result(pagemap_is_softdirty(pagemap_fd, map) == 1,
     58			 "Test %s dirty bit of allocated page\n", __func__);
     59
     60	clear_softdirty();
     61	munmap(map, pagesize);
     62
     63	map2 = mmap(NULL, pagesize, (PROT_READ | PROT_WRITE), (MAP_PRIVATE | MAP_ANON), -1, 0);
     64	if (map2 == MAP_FAILED)
     65		ksft_exit_fail_msg("mmap failed");
     66
     67	// Dirty bit is set for new regions even if they are reused
     68	if (map == map2)
     69		ksft_test_result(pagemap_is_softdirty(pagemap_fd, map2) == 1,
     70				 "Test %s dirty bit of reused address page\n", __func__);
     71	else
     72		ksft_test_result_skip("Test %s dirty bit of reused address page\n", __func__);
     73
     74	munmap(map2, pagesize);
     75}
     76
     77static void test_hugepage(int pagemap_fd, int pagesize)
     78{
     79	char *map;
     80	int i, ret;
     81	size_t hpage_len = read_pmd_pagesize();
     82
     83	map = memalign(hpage_len, hpage_len);
     84	if (!map)
     85		ksft_exit_fail_msg("memalign failed\n");
     86
     87	ret = madvise(map, hpage_len, MADV_HUGEPAGE);
     88	if (ret)
     89		ksft_exit_fail_msg("madvise failed %d\n", ret);
     90
     91	for (i = 0; i < hpage_len; i++)
     92		map[i] = (char)i;
     93
     94	if (check_huge(map)) {
     95		ksft_test_result_pass("Test %s huge page allocation\n", __func__);
     96
     97		clear_softdirty();
     98		for (i = 0 ; i < TEST_ITERATIONS ; i++) {
     99			if (pagemap_is_softdirty(pagemap_fd, map) == 1) {
    100				ksft_print_msg("dirty bit was 1, but should be 0 (i=%d)\n", i);
    101				break;
    102			}
    103
    104			clear_softdirty();
    105			// Write something to the page to get the dirty bit enabled on the page
    106			map[0]++;
    107
    108			if (pagemap_is_softdirty(pagemap_fd, map) == 0) {
    109				ksft_print_msg("dirty bit was 0, but should be 1 (i=%d)\n", i);
    110				break;
    111			}
    112			clear_softdirty();
    113		}
    114
    115		ksft_test_result(i == TEST_ITERATIONS, "Test %s huge page dirty bit\n", __func__);
    116	} else {
    117		// hugepage allocation failed. skip these tests
    118		ksft_test_result_skip("Test %s huge page allocation\n", __func__);
    119		ksft_test_result_skip("Test %s huge page dirty bit\n", __func__);
    120	}
    121	free(map);
    122}
    123
    124int main(int argc, char **argv)
    125{
    126	int pagemap_fd;
    127	int pagesize;
    128
    129	ksft_print_header();
    130	ksft_set_plan(5);
    131
    132	pagemap_fd = open(PAGEMAP_FILE_PATH, O_RDONLY);
    133	if (pagemap_fd < 0)
    134		ksft_exit_fail_msg("Failed to open %s\n", PAGEMAP_FILE_PATH);
    135
    136	pagesize = getpagesize();
    137
    138	test_simple(pagemap_fd, pagesize);
    139	test_vma_reuse(pagemap_fd, pagesize);
    140	test_hugepage(pagemap_fd, pagesize);
    141
    142	close(pagemap_fd);
    143
    144	return ksft_exit_pass();
    145}