Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.1-rc2 258 lines 6.5 kB view raw
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 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 71static 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 83static 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 95static 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 102static 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 */ 111static 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 121static 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 127static 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 250static void test_klp_shadow_vars_exit(void) 251{ 252} 253 254module_init(test_klp_shadow_vars_init); 255module_exit(test_klp_shadow_vars_exit); 256MODULE_LICENSE("GPL"); 257MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>"); 258MODULE_DESCRIPTION("Livepatch test: shadow variables");