bpf: Add BTF_ID_LIST/BTF_ID/BTF_ID_UNUSED macros
[linux-2.6-microblaze.git] / lib / livepatch / test_klp_shadow_vars.c
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",
113                 __func__, id, ptr_id(dtor));
114 }
115
116
117 /* Shadow variable constructor - remember simple pointer data */
118 static int shadow_ctor(void *obj, void *shadow_data, void *ctor_data)
119 {
120         int **sv = shadow_data;
121         int **var = ctor_data;
122
123         if (!var)
124                 return -EINVAL;
125
126         *sv = *var;
127         pr_info("%s: PTR%d -> PTR%d\n",
128                 __func__, ptr_id(sv), ptr_id(*var));
129
130         return 0;
131 }
132
133 static void shadow_dtor(void *obj, void *shadow_data)
134 {
135         int **sv = shadow_data;
136
137         pr_info("%s(obj=PTR%d, shadow_data=PTR%d)\n",
138                 __func__, ptr_id(obj), ptr_id(sv));
139 }
140
141 static int test_klp_shadow_vars_init(void)
142 {
143         void *obj                       = THIS_MODULE;
144         int id                  = 0x1234;
145         gfp_t gfp_flags         = GFP_KERNEL;
146
147         int var1, var2, var3, var4;
148         int *pv1, *pv2, *pv3, *pv4;
149         int **sv1, **sv2, **sv3, **sv4;
150
151         int **sv;
152
153         pv1 = &var1;
154         pv2 = &var2;
155         pv3 = &var3;
156         pv4 = &var4;
157
158         ptr_id(NULL);
159         ptr_id(pv1);
160         ptr_id(pv2);
161         ptr_id(pv3);
162         ptr_id(pv4);
163
164         /*
165          * With an empty shadow variable hash table, expect not to find
166          * any matches.
167          */
168         sv = shadow_get(obj, id);
169         if (!sv)
170                 pr_info("  got expected NULL result\n");
171
172         /*
173          * Allocate a few shadow variables with different <obj> and <id>.
174          */
175         sv1 = shadow_alloc(obj, id, sizeof(pv1), gfp_flags, shadow_ctor, &pv1);
176         if (!sv1)
177                 return -ENOMEM;
178
179         sv2 = shadow_alloc(obj + 1, id, sizeof(pv2), gfp_flags, shadow_ctor, &pv2);
180         if (!sv2)
181                 return -ENOMEM;
182
183         sv3 = shadow_alloc(obj, id + 1, sizeof(pv3), gfp_flags, shadow_ctor, &pv3);
184         if (!sv3)
185                 return -ENOMEM;
186
187         /*
188          * Verify we can find our new shadow variables and that they point
189          * to expected data.
190          */
191         sv = shadow_get(obj, id);
192         if (!sv)
193                 return -EINVAL;
194         if (sv == sv1 && *sv1 == pv1)
195                 pr_info("  got expected PTR%d -> PTR%d result\n",
196                         ptr_id(sv1), ptr_id(*sv1));
197
198         sv = shadow_get(obj + 1, id);
199         if (!sv)
200                 return -EINVAL;
201         if (sv == sv2 && *sv2 == pv2)
202                 pr_info("  got expected PTR%d -> PTR%d result\n",
203                         ptr_id(sv2), ptr_id(*sv2));
204         sv = shadow_get(obj, id + 1);
205         if (!sv)
206                 return -EINVAL;
207         if (sv == sv3 && *sv3 == pv3)
208                 pr_info("  got expected PTR%d -> PTR%d result\n",
209                         ptr_id(sv3), ptr_id(*sv3));
210
211         /*
212          * Allocate or get a few more, this time with the same <obj>, <id>.
213          * The second invocation should return the same shadow var.
214          */
215         sv4 = shadow_get_or_alloc(obj + 2, id, sizeof(pv4), gfp_flags, shadow_ctor, &pv4);
216         if (!sv4)
217                 return -ENOMEM;
218
219         sv = shadow_get_or_alloc(obj + 2, id, sizeof(pv4), gfp_flags, shadow_ctor, &pv4);
220         if (!sv)
221                 return -EINVAL;
222         if (sv == sv4 && *sv4 == pv4)
223                 pr_info("  got expected PTR%d -> PTR%d result\n",
224                         ptr_id(sv4), ptr_id(*sv4));
225
226         /*
227          * Free the <obj=*, id> shadow variables and check that we can no
228          * longer find them.
229          */
230         shadow_free(obj, id, shadow_dtor);                      /* sv1 */
231         sv = shadow_get(obj, id);
232         if (!sv)
233                 pr_info("  got expected NULL result\n");
234
235         shadow_free(obj + 1, id, shadow_dtor);                  /* sv2 */
236         sv = shadow_get(obj + 1, id);
237         if (!sv)
238                 pr_info("  got expected NULL result\n");
239
240         shadow_free(obj + 2, id, shadow_dtor);                  /* sv4 */
241         sv = shadow_get(obj + 2, id);
242         if (!sv)
243                 pr_info("  got expected NULL result\n");
244
245         /*
246          * We should still find an <id+1> variable.
247          */
248         sv = shadow_get(obj, id + 1);
249         if (!sv)
250                 return -EINVAL;
251         if (sv == sv3 && *sv3 == pv3)
252                 pr_info("  got expected PTR%d -> PTR%d result\n",
253                         ptr_id(sv3), ptr_id(*sv3));
254
255         /*
256          * Free all the <id+1> variables, too.
257          */
258         shadow_free_all(id + 1, shadow_dtor);                   /* sv3 */
259         sv = shadow_get(obj, id);
260         if (!sv)
261                 pr_info("  shadow_get() got expected NULL result\n");
262
263
264         free_ptr_list();
265
266         return 0;
267 }
268
269 static void test_klp_shadow_vars_exit(void)
270 {
271 }
272
273 module_init(test_klp_shadow_vars_init);
274 module_exit(test_klp_shadow_vars_exit);
275 MODULE_LICENSE("GPL");
276 MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>");
277 MODULE_DESCRIPTION("Livepatch test: shadow variables");