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 sv2 = shadow_alloc(obj + 1, id, size, gfp_flags, shadow_ctor, &var2); 158 sv3 = shadow_alloc(obj, id + 1, size, gfp_flags, shadow_ctor, &var3); 159 160 /* 161 * Verify we can find our new shadow variables and that they point 162 * to expected data. 163 */ 164 ret = shadow_get(obj, id); 165 if (ret == sv1 && *sv1 == &var1) 166 pr_info(" got expected PTR%d -> PTR%d result\n", 167 ptr_id(sv1), ptr_id(*sv1)); 168 ret = shadow_get(obj + 1, id); 169 if (ret == sv2 && *sv2 == &var2) 170 pr_info(" got expected PTR%d -> PTR%d result\n", 171 ptr_id(sv2), ptr_id(*sv2)); 172 ret = shadow_get(obj, id + 1); 173 if (ret == sv3 && *sv3 == &var3) 174 pr_info(" got expected PTR%d -> PTR%d result\n", 175 ptr_id(sv3), ptr_id(*sv3)); 176 177 /* 178 * Allocate or get a few more, this time with the same <obj>, <id>. 179 * The second invocation should return the same shadow var. 180 */ 181 sv4 = shadow_get_or_alloc(obj + 2, id, size, gfp_flags, shadow_ctor, &var4); 182 ret = shadow_get_or_alloc(obj + 2, id, size, gfp_flags, shadow_ctor, &var4); 183 if (ret == sv4 && *sv4 == &var4) 184 pr_info(" got expected PTR%d -> PTR%d result\n", 185 ptr_id(sv4), ptr_id(*sv4)); 186 187 /* 188 * Free the <obj=*, id> shadow variables and check that we can no 189 * longer find them. 190 */ 191 shadow_free(obj, id, shadow_dtor); /* sv1 */ 192 ret = shadow_get(obj, id); 193 if (!ret) 194 pr_info(" got expected NULL result\n"); 195 196 shadow_free(obj + 1, id, shadow_dtor); /* sv2 */ 197 ret = shadow_get(obj + 1, id); 198 if (!ret) 199 pr_info(" got expected NULL result\n"); 200 201 shadow_free(obj + 2, id, shadow_dtor); /* sv4 */ 202 ret = shadow_get(obj + 2, id); 203 if (!ret) 204 pr_info(" got expected NULL result\n"); 205 206 /* 207 * We should still find an <id+1> variable. 208 */ 209 ret = shadow_get(obj, id + 1); 210 if (ret == sv3 && *sv3 == &var3) 211 pr_info(" got expected PTR%d -> PTR%d result\n", 212 ptr_id(sv3), ptr_id(*sv3)); 213 214 /* 215 * Free all the <id+1> variables, too. 216 */ 217 shadow_free_all(id + 1, shadow_dtor); /* sv3 */ 218 ret = shadow_get(obj, id); 219 if (!ret) 220 pr_info(" shadow_get() got expected NULL result\n"); 221 222 223 free_ptr_list(); 224 225 return 0; 226 } 227 228 static void test_klp_shadow_vars_exit(void) 229 { 230 } 231 232 module_init(test_klp_shadow_vars_init); 233 module_exit(test_klp_shadow_vars_exit); 234 MODULE_LICENSE("GPL"); 235 MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>"); 236 MODULE_DESCRIPTION("Livepatch test: shadow variables"); 237