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 void *ret = klp_shadow_get(obj, id); 64 65 pr_info("klp_%s(obj=PTR%d, id=0x%lx) = PTR%d\n", 66 __func__, ptr_id(obj), id, ptr_id(ret)); 67 68 return ret; 69 } 70 71 static void *shadow_alloc(void *obj, unsigned long id, size_t size, 72 gfp_t gfp_flags, klp_shadow_ctor_t ctor, 73 void *ctor_data) 74 { 75 void *ret = klp_shadow_alloc(obj, id, size, gfp_flags, ctor, 76 ctor_data); 77 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", 78 __func__, ptr_id(obj), id, size, &gfp_flags, ptr_id(ctor), 79 ptr_id(ctor_data), ptr_id(ret)); 80 return ret; 81 } 82 83 static void *shadow_get_or_alloc(void *obj, unsigned long id, size_t size, 84 gfp_t gfp_flags, klp_shadow_ctor_t ctor, 85 void *ctor_data) 86 { 87 void *ret = klp_shadow_get_or_alloc(obj, id, size, gfp_flags, ctor, 88 ctor_data); 89 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", 90 __func__, ptr_id(obj), id, size, &gfp_flags, ptr_id(ctor), 91 ptr_id(ctor_data), ptr_id(ret)); 92 return ret; 93 } 94 95 static void shadow_free(void *obj, unsigned long id, klp_shadow_dtor_t dtor) 96 { 97 klp_shadow_free(obj, id, dtor); 98 pr_info("klp_%s(obj=PTR%d, id=0x%lx, dtor=PTR%d)\n", 99 __func__, ptr_id(obj), id, ptr_id(dtor)); 100 } 101 102 static void shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor) 103 { 104 klp_shadow_free_all(id, dtor); 105 pr_info("klp_%s(id=0x%lx, dtor=PTR%d)\n", 106 __func__, id, ptr_id(dtor)); 107 } 108 109 110 /* Shadow variable constructor - remember simple pointer data */ 111 static int shadow_ctor(void *obj, void *shadow_data, void *ctor_data) 112 { 113 int **shadow_int = shadow_data; 114 *shadow_int = ctor_data; 115 pr_info("%s: PTR%d -> PTR%d\n", 116 __func__, ptr_id(shadow_int), ptr_id(ctor_data)); 117 118 return 0; 119 } 120 121 static void shadow_dtor(void *obj, void *shadow_data) 122 { 123 pr_info("%s(obj=PTR%d, shadow_data=PTR%d)\n", 124 __func__, ptr_id(obj), ptr_id(shadow_data)); 125 } 126 127 static int test_klp_shadow_vars_init(void) 128 { 129 void *obj = THIS_MODULE; 130 int id = 0x1234; 131 size_t size = sizeof(int *); 132 gfp_t gfp_flags = GFP_KERNEL; 133 134 int var1, var2, var3, var4; 135 int **sv1, **sv2, **sv3, **sv4; 136 137 void *ret; 138 139 ptr_id(NULL); 140 ptr_id(&var1); 141 ptr_id(&var2); 142 ptr_id(&var3); 143 ptr_id(&var4); 144 145 /* 146 * With an empty shadow variable hash table, expect not to find 147 * any matches. 148 */ 149 ret = shadow_get(obj, id); 150 if (!ret) 151 pr_info(" got expected NULL result\n"); 152 153 /* 154 * Allocate a few shadow variables with different <obj> and <id>. 155 */ 156 sv1 = shadow_alloc(obj, id, size, gfp_flags, shadow_ctor, &var1); 157 if (!sv1) 158 return -ENOMEM; 159 160 sv2 = shadow_alloc(obj + 1, id, size, gfp_flags, shadow_ctor, &var2); 161 if (!sv2) 162 return -ENOMEM; 163 164 sv3 = shadow_alloc(obj, id + 1, size, gfp_flags, shadow_ctor, &var3); 165 if (!sv3) 166 return -ENOMEM; 167 168 /* 169 * Verify we can find our new shadow variables and that they point 170 * to expected data. 171 */ 172 ret = shadow_get(obj, id); 173 if (!ret) 174 return -EINVAL; 175 if (ret == sv1 && *sv1 == &var1) 176 pr_info(" got expected PTR%d -> PTR%d result\n", 177 ptr_id(sv1), ptr_id(*sv1)); 178 179 ret = shadow_get(obj + 1, id); 180 if (!ret) 181 return -EINVAL; 182 if (ret == sv2 && *sv2 == &var2) 183 pr_info(" got expected PTR%d -> PTR%d result\n", 184 ptr_id(sv2), ptr_id(*sv2)); 185 ret = shadow_get(obj, id + 1); 186 if (!ret) 187 return -EINVAL; 188 if (ret == sv3 && *sv3 == &var3) 189 pr_info(" got expected PTR%d -> PTR%d result\n", 190 ptr_id(sv3), ptr_id(*sv3)); 191 192 /* 193 * Allocate or get a few more, this time with the same <obj>, <id>. 194 * The second invocation should return the same shadow var. 195 */ 196 sv4 = shadow_get_or_alloc(obj + 2, id, size, gfp_flags, shadow_ctor, &var4); 197 if (!sv4) 198 return -ENOMEM; 199 200 ret = shadow_get_or_alloc(obj + 2, id, size, gfp_flags, shadow_ctor, &var4); 201 if (!ret) 202 return -EINVAL; 203 if (ret == sv4 && *sv4 == &var4) 204 pr_info(" got expected PTR%d -> PTR%d result\n", 205 ptr_id(sv4), ptr_id(*sv4)); 206 207 /* 208 * Free the <obj=*, id> shadow variables and check that we can no 209 * longer find them. 210 */ 211 shadow_free(obj, id, shadow_dtor); /* sv1 */ 212 ret = shadow_get(obj, id); 213 if (!ret) 214 pr_info(" got expected NULL result\n"); 215 216 shadow_free(obj + 1, id, shadow_dtor); /* sv2 */ 217 ret = shadow_get(obj + 1, id); 218 if (!ret) 219 pr_info(" got expected NULL result\n"); 220 221 shadow_free(obj + 2, id, shadow_dtor); /* sv4 */ 222 ret = shadow_get(obj + 2, id); 223 if (!ret) 224 pr_info(" got expected NULL result\n"); 225 226 /* 227 * We should still find an <id+1> variable. 228 */ 229 ret = shadow_get(obj, id + 1); 230 if (!ret) 231 return -EINVAL; 232 if (ret == sv3 && *sv3 == &var3) 233 pr_info(" got expected PTR%d -> PTR%d result\n", 234 ptr_id(sv3), ptr_id(*sv3)); 235 236 /* 237 * Free all the <id+1> variables, too. 238 */ 239 shadow_free_all(id + 1, shadow_dtor); /* sv3 */ 240 ret = shadow_get(obj, id); 241 if (!ret) 242 pr_info(" shadow_get() got expected NULL result\n"); 243 244 245 free_ptr_list(); 246 247 return 0; 248 } 249 250 static void test_klp_shadow_vars_exit(void) 251 { 252 } 253 254 module_init(test_klp_shadow_vars_init); 255 module_exit(test_klp_shadow_vars_exit); 256 MODULE_LICENSE("GPL"); 257 MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>"); 258 MODULE_DESCRIPTION("Livepatch test: shadow variables"); 259