1 // SPDX-License-Identifier: GPL-2.0 2 3 #include "vmlinux.h" 4 #include <bpf/bpf_helpers.h> 5 #include <bpf/bpf_tracing.h> 6 #include <bpf/bpf_core_read.h> 7 #include "bpf_misc.h" 8 9 __u64 in_user; 10 __u64 ret_user; 11 12 int pid; 13 14 /* 15 * Skip all the tests if compiler doesn't support indirect jumps. 16 * 17 * If tests are skipped, then all functions below are compiled as 18 * dummy, such that the skeleton looks the same, and the userspace 19 * program can avoid any checks rather than if data->skip is set. 20 */ 21 #ifdef __BPF_FEATURE_GOTOX 22 __u64 skip SEC(".data") = 0; 23 #else 24 __u64 skip = 1; 25 #endif 26 27 struct simple_ctx { 28 __u64 x; 29 }; 30 31 #ifdef __BPF_FEATURE_GOTOX 32 __u64 some_var; 33 34 /* 35 * This function adds code which will be replaced by a different 36 * number of instructions by the verifier. This adds additional 37 * stress on testing the insn_array maps corresponding to indirect jumps. 38 */ 39 static __always_inline void adjust_insns(__u64 x) 40 { 41 some_var ^= x + bpf_jiffies64(); 42 } 43 44 SEC("syscall") 45 int one_switch(struct simple_ctx *ctx) 46 { 47 switch (ctx->x) { 48 case 0: 49 adjust_insns(ctx->x + 1); 50 ret_user = 2; 51 break; 52 case 1: 53 adjust_insns(ctx->x + 7); 54 ret_user = 3; 55 break; 56 case 2: 57 adjust_insns(ctx->x + 9); 58 ret_user = 4; 59 break; 60 case 3: 61 adjust_insns(ctx->x + 11); 62 ret_user = 5; 63 break; 64 case 4: 65 adjust_insns(ctx->x + 17); 66 ret_user = 7; 67 break; 68 default: 69 adjust_insns(ctx->x + 177); 70 ret_user = 19; 71 break; 72 } 73 74 return 0; 75 } 76 77 SEC("syscall") 78 int one_switch_non_zero_sec_off(struct simple_ctx *ctx) 79 { 80 switch (ctx->x) { 81 case 0: 82 adjust_insns(ctx->x + 1); 83 ret_user = 2; 84 break; 85 case 1: 86 adjust_insns(ctx->x + 7); 87 ret_user = 3; 88 break; 89 case 2: 90 adjust_insns(ctx->x + 9); 91 ret_user = 4; 92 break; 93 case 3: 94 adjust_insns(ctx->x + 11); 95 ret_user = 5; 96 break; 97 case 4: 98 adjust_insns(ctx->x + 17); 99 ret_user = 7; 100 break; 101 default: 102 adjust_insns(ctx->x + 177); 103 ret_user = 19; 104 break; 105 } 106 107 return 0; 108 } 109 110 SEC("fentry/" SYS_PREFIX "sys_nanosleep") 111 int simple_test_other_sec(struct pt_regs *ctx) 112 { 113 __u64 x = in_user; 114 115 if (bpf_get_current_pid_tgid() >> 32 != pid) 116 return 0; 117 118 switch (x) { 119 case 0: 120 adjust_insns(x + 1); 121 ret_user = 2; 122 break; 123 case 1: 124 adjust_insns(x + 7); 125 ret_user = 3; 126 break; 127 case 2: 128 adjust_insns(x + 9); 129 ret_user = 4; 130 break; 131 case 3: 132 adjust_insns(x + 11); 133 ret_user = 5; 134 break; 135 case 4: 136 adjust_insns(x + 17); 137 ret_user = 7; 138 break; 139 default: 140 adjust_insns(x + 177); 141 ret_user = 19; 142 break; 143 } 144 145 return 0; 146 } 147 148 SEC("syscall") 149 int two_switches(struct simple_ctx *ctx) 150 { 151 switch (ctx->x) { 152 case 0: 153 adjust_insns(ctx->x + 1); 154 ret_user = 2; 155 break; 156 case 1: 157 adjust_insns(ctx->x + 7); 158 ret_user = 3; 159 break; 160 case 2: 161 adjust_insns(ctx->x + 9); 162 ret_user = 4; 163 break; 164 case 3: 165 adjust_insns(ctx->x + 11); 166 ret_user = 5; 167 break; 168 case 4: 169 adjust_insns(ctx->x + 17); 170 ret_user = 7; 171 break; 172 default: 173 adjust_insns(ctx->x + 177); 174 ret_user = 19; 175 break; 176 } 177 178 switch (ctx->x + !!ret_user) { 179 case 1: 180 adjust_insns(ctx->x + 7); 181 ret_user = 103; 182 break; 183 case 2: 184 adjust_insns(ctx->x + 9); 185 ret_user = 104; 186 break; 187 case 3: 188 adjust_insns(ctx->x + 11); 189 ret_user = 107; 190 break; 191 case 4: 192 adjust_insns(ctx->x + 11); 193 ret_user = 205; 194 break; 195 case 5: 196 adjust_insns(ctx->x + 11); 197 ret_user = 115; 198 break; 199 default: 200 adjust_insns(ctx->x + 177); 201 ret_user = 1019; 202 break; 203 } 204 205 return 0; 206 } 207 208 SEC("syscall") 209 int big_jump_table(struct simple_ctx *ctx __attribute__((unused))) 210 { 211 const void *const jt[256] = { 212 [0 ... 255] = &&default_label, 213 [0] = &&l0, 214 [11] = &&l11, 215 [27] = &&l27, 216 [31] = &&l31, 217 }; 218 219 goto *jt[ctx->x & 0xff]; 220 221 l0: 222 adjust_insns(ctx->x + 1); 223 ret_user = 2; 224 return 0; 225 226 l11: 227 adjust_insns(ctx->x + 7); 228 ret_user = 3; 229 return 0; 230 231 l27: 232 adjust_insns(ctx->x + 9); 233 ret_user = 4; 234 return 0; 235 236 l31: 237 adjust_insns(ctx->x + 11); 238 ret_user = 5; 239 return 0; 240 241 default_label: 242 adjust_insns(ctx->x + 177); 243 ret_user = 19; 244 return 0; 245 } 246 247 SEC("syscall") 248 int one_jump_two_maps(struct simple_ctx *ctx __attribute__((unused))) 249 { 250 __label__ l1, l2, l3, l4; 251 void *jt1[2] = { &&l1, &&l2 }; 252 void *jt2[2] = { &&l3, &&l4 }; 253 unsigned int a = ctx->x % 2; 254 unsigned int b = (ctx->x / 2) % 2; 255 volatile int ret = 0; 256 257 if (!(a < 2 && b < 2)) 258 return 19; 259 260 if (ctx->x % 2) 261 goto *jt1[a]; 262 else 263 goto *jt2[b]; 264 265 l1: ret += 1; 266 l2: ret += 3; 267 l3: ret += 5; 268 l4: ret += 7; 269 270 ret_user = ret; 271 return ret; 272 } 273 274 SEC("syscall") 275 int one_map_two_jumps(struct simple_ctx *ctx __attribute__((unused))) 276 { 277 __label__ l1, l2, l3; 278 void *jt[3] = { &&l1, &&l2, &&l3 }; 279 unsigned int a = (ctx->x >> 2) & 1; 280 unsigned int b = (ctx->x >> 3) & 1; 281 volatile int ret = 0; 282 283 if (ctx->x % 2) 284 goto *jt[a]; 285 286 if (ctx->x % 3) 287 goto *jt[a + b]; 288 289 l1: ret += 3; 290 l2: ret += 5; 291 l3: ret += 7; 292 293 ret_user = ret; 294 return ret; 295 } 296 297 /* Just to introduce some non-zero offsets in .text */ 298 static __noinline int f0(volatile struct simple_ctx *ctx __arg_ctx) 299 { 300 if (ctx) 301 return 1; 302 else 303 return 13; 304 } 305 306 SEC("syscall") int f1(struct simple_ctx *ctx) 307 { 308 ret_user = 0; 309 return f0(ctx); 310 } 311 312 static __noinline int __static_global(__u64 x) 313 { 314 switch (x) { 315 case 0: 316 adjust_insns(x + 1); 317 ret_user = 2; 318 break; 319 case 1: 320 adjust_insns(x + 7); 321 ret_user = 3; 322 break; 323 case 2: 324 adjust_insns(x + 9); 325 ret_user = 4; 326 break; 327 case 3: 328 adjust_insns(x + 11); 329 ret_user = 5; 330 break; 331 case 4: 332 adjust_insns(x + 17); 333 ret_user = 7; 334 break; 335 default: 336 adjust_insns(x + 177); 337 ret_user = 19; 338 break; 339 } 340 341 return 0; 342 } 343 344 SEC("syscall") 345 int use_static_global1(struct simple_ctx *ctx) 346 { 347 ret_user = 0; 348 return __static_global(ctx->x); 349 } 350 351 SEC("syscall") 352 int use_static_global2(struct simple_ctx *ctx) 353 { 354 ret_user = 0; 355 adjust_insns(ctx->x + 1); 356 return __static_global(ctx->x); 357 } 358 359 SEC("fentry/" SYS_PREFIX "sys_nanosleep") 360 int use_static_global_other_sec(void *ctx) 361 { 362 if (bpf_get_current_pid_tgid() >> 32 != pid) 363 return 0; 364 365 return __static_global(in_user); 366 } 367 368 __noinline int __nonstatic_global(__u64 x) 369 { 370 switch (x) { 371 case 0: 372 adjust_insns(x + 1); 373 ret_user = 2; 374 break; 375 case 1: 376 adjust_insns(x + 7); 377 ret_user = 3; 378 break; 379 case 2: 380 adjust_insns(x + 9); 381 ret_user = 4; 382 break; 383 case 3: 384 adjust_insns(x + 11); 385 ret_user = 5; 386 break; 387 case 4: 388 adjust_insns(x + 17); 389 ret_user = 7; 390 break; 391 default: 392 adjust_insns(x + 177); 393 ret_user = 19; 394 break; 395 } 396 397 return 0; 398 } 399 400 SEC("syscall") 401 int use_nonstatic_global1(struct simple_ctx *ctx) 402 { 403 ret_user = 0; 404 return __nonstatic_global(ctx->x); 405 } 406 407 SEC("syscall") 408 int use_nonstatic_global2(struct simple_ctx *ctx) 409 { 410 ret_user = 0; 411 adjust_insns(ctx->x + 1); 412 return __nonstatic_global(ctx->x); 413 } 414 415 SEC("fentry/" SYS_PREFIX "sys_nanosleep") 416 int use_nonstatic_global_other_sec(void *ctx) 417 { 418 if (bpf_get_current_pid_tgid() >> 32 != pid) 419 return 0; 420 421 return __nonstatic_global(in_user); 422 } 423 424 #else /* __BPF_FEATURE_GOTOX */ 425 426 #define SKIP_TEST(TEST_NAME) \ 427 SEC("syscall") int TEST_NAME(void *ctx) \ 428 { \ 429 return 0; \ 430 } 431 432 SKIP_TEST(one_switch); 433 SKIP_TEST(one_switch_non_zero_sec_off); 434 SKIP_TEST(simple_test_other_sec); 435 SKIP_TEST(two_switches); 436 SKIP_TEST(big_jump_table); 437 SKIP_TEST(one_jump_two_maps); 438 SKIP_TEST(one_map_two_jumps); 439 SKIP_TEST(use_static_global1); 440 SKIP_TEST(use_static_global2); 441 SKIP_TEST(use_static_global_other_sec); 442 SKIP_TEST(use_nonstatic_global1); 443 SKIP_TEST(use_nonstatic_global2); 444 SKIP_TEST(use_nonstatic_global_other_sec); 445 446 #endif /* __BPF_FEATURE_GOTOX */ 447 448 char _license[] SEC("license") = "GPL"; 449