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 */ 18 static LIST_HEAD(ptr_list); 19 struct shadow_ptr { 20 void *ptr; 21 int id; 22 struct list_head list; 23 }; 24 25 static 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 35 static 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 */ 61 static 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 72 static 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 87 static 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 102 static 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 109 static 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 */ 117 static 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 static void shadow_dtor(void *obj, void *shadow_data) 132 { 133 int **sv = shadow_data; 134 135 pr_info("%s(obj=PTR%d, shadow_data=PTR%d)\n", 136 __func__, ptr_id(obj), ptr_id(sv)); 137 } 138 139 /* dynamically created obj fields have the following shadow var id values */ 140 #define SV_ID1 0x1234 141 #define SV_ID2 0x1235 142 143 /* 144 * The main test case adds/removes new fields (shadow var) to each of these 145 * test structure instances. The last group of fields in the struct represent 146 * the idea that shadow variables may be added and removed to and from the 147 * struct during execution. 148 */ 149 struct test_object { 150 /* add anything here below and avoid to define an empty struct */ 151 struct shadow_ptr sp; 152 153 /* these represent shadow vars added and removed with SV_ID{1,2} */ 154 /* char nfield1; */ 155 /* int nfield2; */ 156 }; 157 158 static int test_klp_shadow_vars_init(void) 159 { 160 struct test_object obj1, obj2, obj3; 161 char nfield1, nfield2, *pnfield1, *pnfield2, **sv1, **sv2; 162 int nfield3, nfield4, *pnfield3, *pnfield4, **sv3, **sv4; 163 void **sv; 164 165 pnfield1 = &nfield1; 166 pnfield2 = &nfield2; 167 pnfield3 = &nfield3; 168 pnfield4 = &nfield4; 169 170 ptr_id(NULL); 171 ptr_id(pnfield1); 172 ptr_id(pnfield2); 173 ptr_id(pnfield3); 174 ptr_id(pnfield4); 175 176 /* 177 * With an empty shadow variable hash table, expect not to find 178 * any matches. 179 */ 180 sv = shadow_get(&obj1, SV_ID1); 181 if (!sv) 182 pr_info(" got expected NULL result\n"); 183 184 /* 185 * Allocate a few shadow variables with different <obj> and <id>. 186 */ 187 sv1 = shadow_alloc(&obj1, SV_ID1, sizeof(pnfield1), GFP_KERNEL, shadow_ctor, &pnfield1); 188 if (!sv1) 189 return -ENOMEM; 190 191 sv2 = shadow_alloc(&obj2, SV_ID1, sizeof(pnfield2), GFP_KERNEL, shadow_ctor, &pnfield2); 192 if (!sv2) 193 return -ENOMEM; 194 195 sv3 = shadow_alloc(&obj1, SV_ID2, sizeof(pnfield3), GFP_KERNEL, shadow_ctor, &pnfield3); 196 if (!sv3) 197 return -ENOMEM; 198 199 /* 200 * Verify we can find our new shadow variables and that they point 201 * to expected data. 202 */ 203 sv = shadow_get(&obj1, SV_ID1); 204 if (!sv) 205 return -EINVAL; 206 if ((char **)sv == sv1 && *sv1 == pnfield1) 207 pr_info(" got expected PTR%d -> PTR%d result\n", 208 ptr_id(sv1), ptr_id(*sv1)); 209 210 sv = shadow_get(&obj2, SV_ID1); 211 if (!sv) 212 return -EINVAL; 213 if ((char **)sv == sv2 && *sv2 == pnfield2) 214 pr_info(" got expected PTR%d -> PTR%d result\n", 215 ptr_id(sv2), ptr_id(*sv2)); 216 217 sv = shadow_get(&obj1, SV_ID2); 218 if (!sv) 219 return -EINVAL; 220 if ((int **)sv == sv3 && *sv3 == pnfield3) 221 pr_info(" got expected PTR%d -> PTR%d result\n", 222 ptr_id(sv3), ptr_id(*sv3)); 223 224 /* 225 * Allocate or get a few more, this time with the same <obj>, <id>. 226 * The second invocation should return the same shadow var. 227 */ 228 sv4 = shadow_get_or_alloc(&obj3, SV_ID1, sizeof(pnfield4), GFP_KERNEL, shadow_ctor, &pnfield4); 229 if (!sv4) 230 return -ENOMEM; 231 232 sv = shadow_get_or_alloc(&obj3, SV_ID1, sizeof(pnfield4), GFP_KERNEL, shadow_ctor, &pnfield4); 233 if (!sv) 234 return -EINVAL; 235 if ((int **)sv == sv4 && *sv4 == pnfield4) 236 pr_info(" got expected PTR%d -> PTR%d result\n", 237 ptr_id(sv4), ptr_id(*sv4)); 238 239 /* 240 * Free the <obj=*, id> shadow variables and check that we can no 241 * longer find them. 242 */ 243 shadow_free(&obj1, SV_ID1, shadow_dtor); /* sv1 */ 244 sv = shadow_get(&obj1, SV_ID1); 245 if (!sv) 246 pr_info(" got expected NULL result\n"); 247 248 shadow_free(&obj2, SV_ID1, shadow_dtor); /* sv2 */ 249 sv = shadow_get(&obj2, SV_ID1); 250 if (!sv) 251 pr_info(" got expected NULL result\n"); 252 253 shadow_free(&obj3, SV_ID1, shadow_dtor); /* sv4 */ 254 sv = shadow_get(&obj3, SV_ID1); 255 if (!sv) 256 pr_info(" got expected NULL result\n"); 257 258 /* 259 * We should still find an <id+1> variable. 260 */ 261 sv = shadow_get(&obj1, SV_ID2); 262 if (!sv) 263 return -EINVAL; 264 if ((int **)sv == sv3 && *sv3 == pnfield3) 265 pr_info(" got expected PTR%d -> PTR%d result\n", 266 ptr_id(sv3), ptr_id(*sv3)); 267 268 /* 269 * Free all the <id+1> variables, too. 270 */ 271 shadow_free_all(SV_ID2, shadow_dtor); /* sv3 */ 272 sv = shadow_get(&obj1, SV_ID1); 273 if (!sv) 274 pr_info(" shadow_get() got expected NULL result\n"); 275 276 277 free_ptr_list(); 278 279 return 0; 280 } 281 282 static void test_klp_shadow_vars_exit(void) 283 { 284 } 285 286 module_init(test_klp_shadow_vars_init); 287 module_exit(test_klp_shadow_vars_exit); 288 MODULE_LICENSE("GPL"); 289 MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>"); 290 MODULE_DESCRIPTION("Livepatch test: shadow variables"); 291