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

test_klp_shadow_vars.c (7794B)


      1// SPDX-License-Identifier: GPL-2.0
      2// Copyright (C) 2018 Joe Lawrence <joe.lawrence@redhat.com>
      3
      4#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      5
      6#include <linux/module.h>
      7#include <linux/kernel.h>
      8#include <linux/list.h>
      9#include <linux/livepatch.h>
     10#include <linux/slab.h>
     11
     12/*
     13 * Keep a small list of pointers so that we can print address-agnostic
     14 * pointer values.  Use a rolling integer count to differentiate the values.
     15 * Ironically we could have used the shadow variable API to do this, but
     16 * let's not lean too heavily on the very code we're testing.
     17 */
     18static LIST_HEAD(ptr_list);
     19struct shadow_ptr {
     20	void *ptr;
     21	int id;
     22	struct list_head list;
     23};
     24
     25static void free_ptr_list(void)
     26{
     27	struct shadow_ptr *sp, *tmp_sp;
     28
     29	list_for_each_entry_safe(sp, tmp_sp, &ptr_list, list) {
     30		list_del(&sp->list);
     31		kfree(sp);
     32	}
     33}
     34
     35static int ptr_id(void *ptr)
     36{
     37	struct shadow_ptr *sp;
     38	static int count;
     39
     40	list_for_each_entry(sp, &ptr_list, list) {
     41		if (sp->ptr == ptr)
     42			return sp->id;
     43	}
     44
     45	sp = kmalloc(sizeof(*sp), GFP_ATOMIC);
     46	if (!sp)
     47		return -ENOMEM;
     48	sp->ptr = ptr;
     49	sp->id = count++;
     50
     51	list_add(&sp->list, &ptr_list);
     52
     53	return sp->id;
     54}
     55
     56/*
     57 * Shadow variable wrapper functions that echo the function and arguments
     58 * to the kernel log for testing verification.  Don't display raw pointers,
     59 * but use the ptr_id() value instead.
     60 */
     61static void *shadow_get(void *obj, unsigned long id)
     62{
     63	int **sv;
     64
     65	sv = klp_shadow_get(obj, id);
     66	pr_info("klp_%s(obj=PTR%d, id=0x%lx) = PTR%d\n",
     67		__func__, ptr_id(obj), id, ptr_id(sv));
     68
     69	return sv;
     70}
     71
     72static void *shadow_alloc(void *obj, unsigned long id, size_t size,
     73			  gfp_t gfp_flags, klp_shadow_ctor_t ctor,
     74			  void *ctor_data)
     75{
     76	int **var = ctor_data;
     77	int **sv;
     78
     79	sv = klp_shadow_alloc(obj, id, size, gfp_flags, ctor, var);
     80	pr_info("klp_%s(obj=PTR%d, id=0x%lx, size=%zx, gfp_flags=%pGg), ctor=PTR%d, ctor_data=PTR%d = PTR%d\n",
     81		__func__, ptr_id(obj), id, size, &gfp_flags, ptr_id(ctor),
     82		ptr_id(*var), ptr_id(sv));
     83
     84	return sv;
     85}
     86
     87static void *shadow_get_or_alloc(void *obj, unsigned long id, size_t size,
     88				 gfp_t gfp_flags, klp_shadow_ctor_t ctor,
     89				 void *ctor_data)
     90{
     91	int **var = ctor_data;
     92	int **sv;
     93
     94	sv = klp_shadow_get_or_alloc(obj, id, size, gfp_flags, ctor, var);
     95	pr_info("klp_%s(obj=PTR%d, id=0x%lx, size=%zx, gfp_flags=%pGg), ctor=PTR%d, ctor_data=PTR%d = PTR%d\n",
     96		__func__, ptr_id(obj), id, size, &gfp_flags, ptr_id(ctor),
     97		ptr_id(*var), ptr_id(sv));
     98
     99	return sv;
    100}
    101
    102static void shadow_free(void *obj, unsigned long id, klp_shadow_dtor_t dtor)
    103{
    104	klp_shadow_free(obj, id, dtor);
    105	pr_info("klp_%s(obj=PTR%d, id=0x%lx, dtor=PTR%d)\n",
    106		__func__, ptr_id(obj), id, ptr_id(dtor));
    107}
    108
    109static void shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor)
    110{
    111	klp_shadow_free_all(id, dtor);
    112	pr_info("klp_%s(id=0x%lx, dtor=PTR%d)\n", __func__, id, ptr_id(dtor));
    113}
    114
    115
    116/* Shadow variable constructor - remember simple pointer data */
    117static int shadow_ctor(void *obj, void *shadow_data, void *ctor_data)
    118{
    119	int **sv = shadow_data;
    120	int **var = ctor_data;
    121
    122	if (!var)
    123		return -EINVAL;
    124
    125	*sv = *var;
    126	pr_info("%s: PTR%d -> PTR%d\n", __func__, ptr_id(sv), ptr_id(*var));
    127
    128	return 0;
    129}
    130
    131/*
    132 * With more than one item to free in the list, order is not determined and
    133 * shadow_dtor will not be passed to shadow_free_all() which would make the
    134 * test fail. (see pass 6)
    135 */
    136static void shadow_dtor(void *obj, void *shadow_data)
    137{
    138	int **sv = shadow_data;
    139
    140	pr_info("%s(obj=PTR%d, shadow_data=PTR%d)\n",
    141		__func__, ptr_id(obj), ptr_id(sv));
    142}
    143
    144/* number of objects we simulate that need shadow vars */
    145#define NUM_OBJS 3
    146
    147/* dynamically created obj fields have the following shadow var id values */
    148#define SV_ID1 0x1234
    149#define SV_ID2 0x1235
    150
    151/*
    152 * The main test case adds/removes new fields (shadow var) to each of these
    153 * test structure instances. The last group of fields in the struct represent
    154 * the idea that shadow variables may be added and removed to and from the
    155 * struct during execution.
    156 */
    157struct test_object {
    158	 /* add anything here below and avoid to define an empty struct */
    159	struct shadow_ptr sp;
    160
    161	/* these represent shadow vars added and removed with SV_ID{1,2} */
    162	/* char nfield1; */
    163	/* int  nfield2; */
    164};
    165
    166static int test_klp_shadow_vars_init(void)
    167{
    168	struct test_object objs[NUM_OBJS];
    169	char nfields1[NUM_OBJS], *pnfields1[NUM_OBJS], **sv1[NUM_OBJS];
    170	char *pndup[NUM_OBJS];
    171	int nfields2[NUM_OBJS], *pnfields2[NUM_OBJS], **sv2[NUM_OBJS];
    172	void **sv;
    173	int ret;
    174	int i;
    175
    176	ptr_id(NULL);
    177
    178	/*
    179	 * With an empty shadow variable hash table, expect not to find
    180	 * any matches.
    181	 */
    182	sv = shadow_get(&objs[0], SV_ID1);
    183	if (!sv)
    184		pr_info("  got expected NULL result\n");
    185
    186	/* pass 1: init & alloc a char+int pair of svars for each objs */
    187	for (i = 0; i < NUM_OBJS; i++) {
    188		pnfields1[i] = &nfields1[i];
    189		ptr_id(pnfields1[i]);
    190
    191		if (i % 2) {
    192			sv1[i] = shadow_alloc(&objs[i], SV_ID1,
    193					sizeof(pnfields1[i]), GFP_KERNEL,
    194					shadow_ctor, &pnfields1[i]);
    195		} else {
    196			sv1[i] = shadow_get_or_alloc(&objs[i], SV_ID1,
    197					sizeof(pnfields1[i]), GFP_KERNEL,
    198					shadow_ctor, &pnfields1[i]);
    199		}
    200		if (!sv1[i]) {
    201			ret = -ENOMEM;
    202			goto out;
    203		}
    204
    205		pnfields2[i] = &nfields2[i];
    206		ptr_id(pnfields2[i]);
    207		sv2[i] = shadow_alloc(&objs[i], SV_ID2, sizeof(pnfields2[i]),
    208					GFP_KERNEL, shadow_ctor, &pnfields2[i]);
    209		if (!sv2[i]) {
    210			ret = -ENOMEM;
    211			goto out;
    212		}
    213	}
    214
    215	/* pass 2: verify we find allocated svars and where they point to */
    216	for (i = 0; i < NUM_OBJS; i++) {
    217		/* check the "char" svar for all objects */
    218		sv = shadow_get(&objs[i], SV_ID1);
    219		if (!sv) {
    220			ret = -EINVAL;
    221			goto out;
    222		}
    223		if ((char **)sv == sv1[i] && *sv1[i] == pnfields1[i])
    224			pr_info("  got expected PTR%d -> PTR%d result\n",
    225				ptr_id(sv1[i]), ptr_id(*sv1[i]));
    226
    227		/* check the "int" svar for all objects */
    228		sv = shadow_get(&objs[i], SV_ID2);
    229		if (!sv) {
    230			ret = -EINVAL;
    231			goto out;
    232		}
    233		if ((int **)sv == sv2[i] && *sv2[i] == pnfields2[i])
    234			pr_info("  got expected PTR%d -> PTR%d result\n",
    235				ptr_id(sv2[i]), ptr_id(*sv2[i]));
    236	}
    237
    238	/* pass 3: verify that 'get_or_alloc' returns already allocated svars */
    239	for (i = 0; i < NUM_OBJS; i++) {
    240		pndup[i] = &nfields1[i];
    241		ptr_id(pndup[i]);
    242
    243		sv = shadow_get_or_alloc(&objs[i], SV_ID1, sizeof(pndup[i]),
    244					GFP_KERNEL, shadow_ctor, &pndup[i]);
    245		if (!sv) {
    246			ret = -EINVAL;
    247			goto out;
    248		}
    249		if ((char **)sv == sv1[i] && *sv1[i] == pnfields1[i])
    250			pr_info("  got expected PTR%d -> PTR%d result\n",
    251					ptr_id(sv1[i]), ptr_id(*sv1[i]));
    252	}
    253
    254	/* pass 4: free <objs[*], SV_ID1> pairs of svars, verify removal */
    255	for (i = 0; i < NUM_OBJS; i++) {
    256		shadow_free(&objs[i], SV_ID1, shadow_dtor); /* 'char' pairs */
    257		sv = shadow_get(&objs[i], SV_ID1);
    258		if (!sv)
    259			pr_info("  got expected NULL result\n");
    260	}
    261
    262	/* pass 5: check we still find <objs[*], SV_ID2> svar pairs */
    263	for (i = 0; i < NUM_OBJS; i++) {
    264		sv = shadow_get(&objs[i], SV_ID2);	/* 'int' pairs */
    265		if (!sv) {
    266			ret = -EINVAL;
    267			goto out;
    268		}
    269		if ((int **)sv == sv2[i] && *sv2[i] == pnfields2[i])
    270			pr_info("  got expected PTR%d -> PTR%d result\n",
    271					ptr_id(sv2[i]), ptr_id(*sv2[i]));
    272	}
    273
    274	/* pass 6: free all the <objs[*], SV_ID2> svar pairs too. */
    275	shadow_free_all(SV_ID2, NULL);		/* 'int' pairs */
    276	for (i = 0; i < NUM_OBJS; i++) {
    277		sv = shadow_get(&objs[i], SV_ID2);
    278		if (!sv)
    279			pr_info("  got expected NULL result\n");
    280	}
    281
    282	free_ptr_list();
    283
    284	return 0;
    285out:
    286	shadow_free_all(SV_ID1, NULL);		/* 'char' pairs */
    287	shadow_free_all(SV_ID2, NULL);		/* 'int' pairs */
    288	free_ptr_list();
    289
    290	return ret;
    291}
    292
    293static void test_klp_shadow_vars_exit(void)
    294{
    295}
    296
    297module_init(test_klp_shadow_vars_init);
    298module_exit(test_klp_shadow_vars_exit);
    299MODULE_LICENSE("GPL");
    300MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>");
    301MODULE_DESCRIPTION("Livepatch test: shadow variables");