brintos

brintos / linux-shallow public Read only

0
0
Text · 7.6 KiB · b991164 Raw
302 lines · c
1// SPDX-License-Identifier: GPL-2.02// Copyright (C) 2018 Joe Lawrence <joe.lawrence@redhat.com>3 4#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt5 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-agnostic14 * pointer values.  Use a rolling integer count to differentiate the values.15 * Ironically we could have used the shadow variable API to do this, but16 * 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 arguments58 * 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 and133 * shadow_dtor will not be passed to shadow_free_all() which would make the134 * 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 3146 147/* dynamically created obj fields have the following shadow var id values */148#define SV_ID1 0x1234149#define SV_ID2 0x1235150 151/*152 * The main test case adds/removes new fields (shadow var) to each of these153 * test structure instances. The last group of fields in the struct represent154 * the idea that shadow variables may be added and removed to and from the155 * 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 find180	 * 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");302