root/lib/livepatch/test_klp_shadow_vars.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. free_ptr_list
  2. ptr_id
  3. shadow_get
  4. shadow_alloc
  5. shadow_get_or_alloc
  6. shadow_free
  7. shadow_free_all
  8. shadow_ctor
  9. shadow_dtor
  10. test_klp_shadow_vars_init
  11. test_klp_shadow_vars_exit

   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");

/* [<][>][^][v][top][bottom][index][help] */