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

selftests/livepatch: more verification in test-klp-shadow-vars

This change makes the test feel more familiar with narrowing to a
typical usage by operating on a number of identical structure instances
and populating the same two new shadow variables symmetrically while
keeping the same testing and verification criteria for the extra
variables.

Signed-off-by: Yannick Cote <ycote@redhat.com>
Reviewed-by: Kamalesh Babulal <kamalesh@linux.vnet.ibm.com>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Acked-by: Miroslav Benes <mbenes@suse.cz>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20200603182058.109470-4-ycote@redhat.com

authored by

Yannick Cote and committed by
Petr Mladek
76efe6da 6a26a9df

+139 -126
+88 -96
lib/livepatch/test_klp_shadow_vars.c
··· 128 128 return 0; 129 129 } 130 130 131 + /* 132 + * With more than one item to free in the list, order is not determined and 133 + * shadow_dtor will not be passed to shadow_free_all() which would make the 134 + * test fail. (see pass 6) 135 + */ 131 136 static void shadow_dtor(void *obj, void *shadow_data) 132 137 { 133 138 int **sv = shadow_data; ··· 140 135 pr_info("%s(obj=PTR%d, shadow_data=PTR%d)\n", 141 136 __func__, ptr_id(obj), ptr_id(sv)); 142 137 } 138 + 139 + /* number of objects we simulate that need shadow vars */ 140 + #define NUM_OBJS 3 143 141 144 142 /* dynamically created obj fields have the following shadow var id values */ 145 143 #define SV_ID1 0x1234 ··· 165 157 166 158 static int test_klp_shadow_vars_init(void) 167 159 { 168 - struct test_object obj1, obj2, obj3; 169 - char nfield1, nfield2, *pnfield1, *pnfield2, **sv1, **sv2; 170 - int nfield3, nfield4, *pnfield3, *pnfield4, **sv3, **sv4; 160 + struct test_object objs[NUM_OBJS]; 161 + char nfields1[NUM_OBJS], *pnfields1[NUM_OBJS], **sv1[NUM_OBJS]; 162 + char *pndup[NUM_OBJS]; 163 + int nfields2[NUM_OBJS], *pnfields2[NUM_OBJS], **sv2[NUM_OBJS]; 171 164 void **sv; 172 - 173 - pnfield1 = &nfield1; 174 - pnfield2 = &nfield2; 175 - pnfield3 = &nfield3; 176 - pnfield4 = &nfield4; 165 + int i; 177 166 178 167 ptr_id(NULL); 179 - ptr_id(pnfield1); 180 - ptr_id(pnfield2); 181 - ptr_id(pnfield3); 182 - ptr_id(pnfield4); 183 168 184 169 /* 185 170 * With an empty shadow variable hash table, expect not to find 186 171 * any matches. 187 172 */ 188 - sv = shadow_get(&obj1, SV_ID1); 173 + sv = shadow_get(&objs[0], SV_ID1); 189 174 if (!sv) 190 175 pr_info(" got expected NULL result\n"); 191 176 192 - /* 193 - * Allocate a few shadow variables with different <obj> and <id>. 194 - */ 195 - sv1 = shadow_alloc(&obj1, SV_ID1, sizeof(pnfield1), GFP_KERNEL, shadow_ctor, &pnfield1); 196 - if (!sv1) 197 - return -ENOMEM; 177 + /* pass 1: init & alloc a char+int pair of svars for each objs */ 178 + for (i = 0; i < NUM_OBJS; i++) { 179 + pnfields1[i] = &nfields1[i]; 180 + ptr_id(pnfields1[i]); 198 181 199 - sv2 = shadow_alloc(&obj2, SV_ID1, sizeof(pnfield2), GFP_KERNEL, shadow_ctor, &pnfield2); 200 - if (!sv2) 201 - return -ENOMEM; 182 + if (i % 2) { 183 + sv1[i] = shadow_alloc(&objs[i], SV_ID1, 184 + sizeof(pnfields1[i]), GFP_KERNEL, 185 + shadow_ctor, &pnfields1[i]); 186 + } else { 187 + sv1[i] = shadow_get_or_alloc(&objs[i], SV_ID1, 188 + sizeof(pnfields1[i]), GFP_KERNEL, 189 + shadow_ctor, &pnfields1[i]); 190 + } 191 + if (!sv1[i]) 192 + return -ENOMEM; 202 193 203 - sv3 = shadow_alloc(&obj1, SV_ID2, sizeof(pnfield3), GFP_KERNEL, shadow_ctor, &pnfield3); 204 - if (!sv3) 205 - return -ENOMEM; 194 + pnfields2[i] = &nfields2[i]; 195 + ptr_id(pnfields2[i]); 196 + sv2[i] = shadow_alloc(&objs[i], SV_ID2, sizeof(pnfields2[i]), 197 + GFP_KERNEL, shadow_ctor, &pnfields2[i]); 198 + if (!sv2[i]) 199 + return -ENOMEM; 200 + } 206 201 207 - /* 208 - * Verify we can find our new shadow variables and that they point 209 - * to expected data. 210 - */ 211 - sv = shadow_get(&obj1, SV_ID1); 212 - if (!sv) 213 - return -EINVAL; 214 - if ((char **)sv == sv1 && *sv1 == pnfield1) 215 - pr_info(" got expected PTR%d -> PTR%d result\n", 216 - ptr_id(sv1), ptr_id(*sv1)); 202 + /* pass 2: verify we find allocated svars and where they point to */ 203 + for (i = 0; i < NUM_OBJS; i++) { 204 + /* check the "char" svar for all objects */ 205 + sv = shadow_get(&objs[i], SV_ID1); 206 + if (!sv) 207 + return -EINVAL; 208 + if ((char **)sv == sv1[i] && *sv1[i] == pnfields1[i]) 209 + pr_info(" got expected PTR%d -> PTR%d result\n", 210 + ptr_id(sv1[i]), ptr_id(*sv1[i])); 217 211 218 - sv = shadow_get(&obj2, SV_ID1); 219 - if (!sv) 220 - return -EINVAL; 221 - if ((char **)sv == sv2 && *sv2 == pnfield2) 222 - pr_info(" got expected PTR%d -> PTR%d result\n", 223 - ptr_id(sv2), ptr_id(*sv2)); 212 + /* check the "int" svar for all objects */ 213 + sv = shadow_get(&objs[i], SV_ID2); 214 + if (!sv) 215 + return -EINVAL; 216 + if ((int **)sv == sv2[i] && *sv2[i] == pnfields2[i]) 217 + pr_info(" got expected PTR%d -> PTR%d result\n", 218 + ptr_id(sv2[i]), ptr_id(*sv2[i])); 219 + } 224 220 225 - sv = shadow_get(&obj1, SV_ID2); 226 - if (!sv) 227 - return -EINVAL; 228 - if ((int **)sv == sv3 && *sv3 == pnfield3) 229 - pr_info(" got expected PTR%d -> PTR%d result\n", 230 - ptr_id(sv3), ptr_id(*sv3)); 221 + /* pass 3: verify that 'get_or_alloc' returns already allocated svars */ 222 + for (i = 0; i < NUM_OBJS; i++) { 223 + pndup[i] = &nfields1[i]; 224 + ptr_id(pndup[i]); 231 225 232 - /* 233 - * Allocate or get a few more, this time with the same <obj>, <id>. 234 - * The second invocation should return the same shadow var. 235 - */ 236 - sv4 = shadow_get_or_alloc(&obj3, SV_ID1, sizeof(pnfield4), GFP_KERNEL, shadow_ctor, &pnfield4); 237 - if (!sv4) 238 - return -ENOMEM; 226 + sv = shadow_get_or_alloc(&objs[i], SV_ID1, sizeof(pndup[i]), 227 + GFP_KERNEL, shadow_ctor, &pndup[i]); 228 + if (!sv) 229 + return -EINVAL; 230 + if ((char **)sv == sv1[i] && *sv1[i] == pnfields1[i]) 231 + pr_info(" got expected PTR%d -> PTR%d result\n", 232 + ptr_id(sv1[i]), ptr_id(*sv1[i])); 233 + } 239 234 240 - sv = shadow_get_or_alloc(&obj3, SV_ID1, sizeof(pnfield4), GFP_KERNEL, shadow_ctor, &pnfield4); 241 - if (!sv) 242 - return -EINVAL; 243 - if ((int **)sv == sv4 && *sv4 == pnfield4) 244 - pr_info(" got expected PTR%d -> PTR%d result\n", 245 - ptr_id(sv4), ptr_id(*sv4)); 235 + /* pass 4: free <objs[*], SV_ID1> pairs of svars, verify removal */ 236 + for (i = 0; i < NUM_OBJS; i++) { 237 + shadow_free(&objs[i], SV_ID1, shadow_dtor); /* 'char' pairs */ 238 + sv = shadow_get(&objs[i], SV_ID1); 239 + if (!sv) 240 + pr_info(" got expected NULL result\n"); 241 + } 246 242 247 - /* 248 - * Free the <obj=*, id> shadow variables and check that we can no 249 - * longer find them. 250 - */ 251 - shadow_free(&obj1, SV_ID1, shadow_dtor); /* sv1 */ 252 - sv = shadow_get(&obj1, SV_ID1); 253 - if (!sv) 254 - pr_info(" got expected NULL result\n"); 243 + /* pass 5: check we still find <objs[*], SV_ID2> svar pairs */ 244 + for (i = 0; i < NUM_OBJS; i++) { 245 + sv = shadow_get(&objs[i], SV_ID2); /* 'int' pairs */ 246 + if (!sv) 247 + return -EINVAL; 248 + if ((int **)sv == sv2[i] && *sv2[i] == pnfields2[i]) 249 + pr_info(" got expected PTR%d -> PTR%d result\n", 250 + ptr_id(sv2[i]), ptr_id(*sv2[i])); 251 + } 255 252 256 - shadow_free(&obj2, SV_ID1, shadow_dtor); /* sv2 */ 257 - sv = shadow_get(&obj2, SV_ID1); 258 - if (!sv) 259 - pr_info(" got expected NULL result\n"); 260 - 261 - shadow_free(&obj3, SV_ID1, shadow_dtor); /* sv4 */ 262 - sv = shadow_get(&obj3, SV_ID1); 263 - if (!sv) 264 - pr_info(" got expected NULL result\n"); 265 - 266 - /* 267 - * We should still find an <id+1> variable. 268 - */ 269 - sv = shadow_get(&obj1, SV_ID2); 270 - if (!sv) 271 - return -EINVAL; 272 - if ((int **)sv == sv3 && *sv3 == pnfield3) 273 - pr_info(" got expected PTR%d -> PTR%d result\n", 274 - ptr_id(sv3), ptr_id(*sv3)); 275 - 276 - /* 277 - * Free all the <id+1> variables, too. 278 - */ 279 - shadow_free_all(SV_ID2, shadow_dtor); /* sv3 */ 280 - sv = shadow_get(&obj1, SV_ID1); 281 - if (!sv) 282 - pr_info(" shadow_get() got expected NULL result\n"); 283 - 253 + /* pass 6: free all the <objs[*], SV_ID2> svar pairs too. */ 254 + shadow_free_all(SV_ID2, NULL); /* 'int' pairs */ 255 + for (i = 0; i < NUM_OBJS; i++) { 256 + sv = shadow_get(&objs[i], SV_ID2); 257 + if (!sv) 258 + pr_info(" got expected NULL result\n"); 259 + } 284 260 285 261 free_ptr_list(); 286 262
+51 -30
tools/testing/selftests/livepatch/test-shadow-vars.sh
··· 19 19 unload_mod $MOD_TEST 20 20 21 21 check_result "% modprobe $MOD_TEST 22 - $MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1234) = PTR0 22 + $MOD_TEST: klp_shadow_get(obj=PTR1, id=0x1234) = PTR0 23 23 $MOD_TEST: got expected NULL result 24 - $MOD_TEST: shadow_ctor: PTR6 -> PTR1 25 - $MOD_TEST: klp_shadow_alloc(obj=PTR5, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR7, ctor_data=PTR1 = PTR6 26 - $MOD_TEST: shadow_ctor: PTR8 -> PTR2 27 - $MOD_TEST: klp_shadow_alloc(obj=PTR9, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR7, ctor_data=PTR2 = PTR8 28 - $MOD_TEST: shadow_ctor: PTR10 -> PTR3 29 - $MOD_TEST: klp_shadow_alloc(obj=PTR5, id=0x1235, size=8, gfp_flags=GFP_KERNEL), ctor=PTR7, ctor_data=PTR3 = PTR10 30 - $MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1234) = PTR6 31 - $MOD_TEST: got expected PTR6 -> PTR1 result 24 + $MOD_TEST: shadow_ctor: PTR3 -> PTR2 25 + $MOD_TEST: klp_shadow_get_or_alloc(obj=PTR1, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR4, ctor_data=PTR2 = PTR3 26 + $MOD_TEST: shadow_ctor: PTR6 -> PTR5 27 + $MOD_TEST: klp_shadow_alloc(obj=PTR1, id=0x1235, size=8, gfp_flags=GFP_KERNEL), ctor=PTR4, ctor_data=PTR5 = PTR6 28 + $MOD_TEST: shadow_ctor: PTR8 -> PTR7 29 + $MOD_TEST: klp_shadow_alloc(obj=PTR9, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR4, ctor_data=PTR7 = PTR8 30 + $MOD_TEST: shadow_ctor: PTR11 -> PTR10 31 + $MOD_TEST: klp_shadow_alloc(obj=PTR9, id=0x1235, size=8, gfp_flags=GFP_KERNEL), ctor=PTR4, ctor_data=PTR10 = PTR11 32 + $MOD_TEST: shadow_ctor: PTR13 -> PTR12 33 + $MOD_TEST: klp_shadow_get_or_alloc(obj=PTR14, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR4, ctor_data=PTR12 = PTR13 34 + $MOD_TEST: shadow_ctor: PTR16 -> PTR15 35 + $MOD_TEST: klp_shadow_alloc(obj=PTR14, id=0x1235, size=8, gfp_flags=GFP_KERNEL), ctor=PTR4, ctor_data=PTR15 = PTR16 36 + $MOD_TEST: klp_shadow_get(obj=PTR1, id=0x1234) = PTR3 37 + $MOD_TEST: got expected PTR3 -> PTR2 result 38 + $MOD_TEST: klp_shadow_get(obj=PTR1, id=0x1235) = PTR6 39 + $MOD_TEST: got expected PTR6 -> PTR5 result 32 40 $MOD_TEST: klp_shadow_get(obj=PTR9, id=0x1234) = PTR8 33 - $MOD_TEST: got expected PTR8 -> PTR2 result 34 - $MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1235) = PTR10 35 - $MOD_TEST: got expected PTR10 -> PTR3 result 36 - $MOD_TEST: shadow_ctor: PTR11 -> PTR4 37 - $MOD_TEST: klp_shadow_get_or_alloc(obj=PTR12, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR7, ctor_data=PTR4 = PTR11 38 - $MOD_TEST: klp_shadow_get_or_alloc(obj=PTR12, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR7, ctor_data=PTR4 = PTR11 39 - $MOD_TEST: got expected PTR11 -> PTR4 result 40 - $MOD_TEST: shadow_dtor(obj=PTR5, shadow_data=PTR6) 41 - $MOD_TEST: klp_shadow_free(obj=PTR5, id=0x1234, dtor=PTR13) 42 - $MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1234) = PTR0 41 + $MOD_TEST: got expected PTR8 -> PTR7 result 42 + $MOD_TEST: klp_shadow_get(obj=PTR9, id=0x1235) = PTR11 43 + $MOD_TEST: got expected PTR11 -> PTR10 result 44 + $MOD_TEST: klp_shadow_get(obj=PTR14, id=0x1234) = PTR13 45 + $MOD_TEST: got expected PTR13 -> PTR12 result 46 + $MOD_TEST: klp_shadow_get(obj=PTR14, id=0x1235) = PTR16 47 + $MOD_TEST: got expected PTR16 -> PTR15 result 48 + $MOD_TEST: klp_shadow_get_or_alloc(obj=PTR1, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR4, ctor_data=PTR2 = PTR3 49 + $MOD_TEST: got expected PTR3 -> PTR2 result 50 + $MOD_TEST: klp_shadow_get_or_alloc(obj=PTR9, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR4, ctor_data=PTR7 = PTR8 51 + $MOD_TEST: got expected PTR8 -> PTR7 result 52 + $MOD_TEST: klp_shadow_get_or_alloc(obj=PTR14, id=0x1234, size=8, gfp_flags=GFP_KERNEL), ctor=PTR4, ctor_data=PTR12 = PTR13 53 + $MOD_TEST: got expected PTR13 -> PTR12 result 54 + $MOD_TEST: shadow_dtor(obj=PTR1, shadow_data=PTR3) 55 + $MOD_TEST: klp_shadow_free(obj=PTR1, id=0x1234, dtor=PTR17) 56 + $MOD_TEST: klp_shadow_get(obj=PTR1, id=0x1234) = PTR0 43 57 $MOD_TEST: got expected NULL result 44 58 $MOD_TEST: shadow_dtor(obj=PTR9, shadow_data=PTR8) 45 - $MOD_TEST: klp_shadow_free(obj=PTR9, id=0x1234, dtor=PTR13) 59 + $MOD_TEST: klp_shadow_free(obj=PTR9, id=0x1234, dtor=PTR17) 46 60 $MOD_TEST: klp_shadow_get(obj=PTR9, id=0x1234) = PTR0 47 61 $MOD_TEST: got expected NULL result 48 - $MOD_TEST: shadow_dtor(obj=PTR12, shadow_data=PTR11) 49 - $MOD_TEST: klp_shadow_free(obj=PTR12, id=0x1234, dtor=PTR13) 50 - $MOD_TEST: klp_shadow_get(obj=PTR12, id=0x1234) = PTR0 62 + $MOD_TEST: shadow_dtor(obj=PTR14, shadow_data=PTR13) 63 + $MOD_TEST: klp_shadow_free(obj=PTR14, id=0x1234, dtor=PTR17) 64 + $MOD_TEST: klp_shadow_get(obj=PTR14, id=0x1234) = PTR0 51 65 $MOD_TEST: got expected NULL result 52 - $MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1235) = PTR10 53 - $MOD_TEST: got expected PTR10 -> PTR3 result 54 - $MOD_TEST: shadow_dtor(obj=PTR5, shadow_data=PTR10) 55 - $MOD_TEST: klp_shadow_free_all(id=0x1235, dtor=PTR13) 56 - $MOD_TEST: klp_shadow_get(obj=PTR5, id=0x1234) = PTR0 57 - $MOD_TEST: shadow_get() got expected NULL result 58 - % rmmod test_klp_shadow_vars" 66 + $MOD_TEST: klp_shadow_get(obj=PTR1, id=0x1235) = PTR6 67 + $MOD_TEST: got expected PTR6 -> PTR5 result 68 + $MOD_TEST: klp_shadow_get(obj=PTR9, id=0x1235) = PTR11 69 + $MOD_TEST: got expected PTR11 -> PTR10 result 70 + $MOD_TEST: klp_shadow_get(obj=PTR14, id=0x1235) = PTR16 71 + $MOD_TEST: got expected PTR16 -> PTR15 result 72 + $MOD_TEST: klp_shadow_free_all(id=0x1235, dtor=PTR0) 73 + $MOD_TEST: klp_shadow_get(obj=PTR1, id=0x1235) = PTR0 74 + $MOD_TEST: got expected NULL result 75 + $MOD_TEST: klp_shadow_get(obj=PTR9, id=0x1235) = PTR0 76 + $MOD_TEST: got expected NULL result 77 + $MOD_TEST: klp_shadow_get(obj=PTR14, id=0x1235) = PTR0 78 + $MOD_TEST: got expected NULL result 79 + % rmmod $MOD_TEST" 59 80 60 81 exit 0