14e5070b6SJoanne Koong // SPDX-License-Identifier: GPL-2.0 24e5070b6SJoanne Koong /* Copyright (c) 2021 Facebook */ 34e5070b6SJoanne Koong 44e5070b6SJoanne Koong #include "vmlinux.h" 54e5070b6SJoanne Koong #include <bpf/bpf_helpers.h> 6e91d280cSNaveen N. Rao #include "bpf_misc.h" 74e5070b6SJoanne Koong 84e5070b6SJoanne Koong char _license[] SEC("license") = "GPL"; 94e5070b6SJoanne Koong 104e5070b6SJoanne Koong struct callback_ctx { 114e5070b6SJoanne Koong int output; 124e5070b6SJoanne Koong }; 134e5070b6SJoanne Koong 14*0e1bf9edSEduard Zingerman struct { 15*0e1bf9edSEduard Zingerman __uint(type, BPF_MAP_TYPE_HASH); 16*0e1bf9edSEduard Zingerman __uint(max_entries, 32); 17*0e1bf9edSEduard Zingerman __type(key, int); 18*0e1bf9edSEduard Zingerman __type(value, int); 19*0e1bf9edSEduard Zingerman } map1 SEC(".maps"); 20*0e1bf9edSEduard Zingerman 214e5070b6SJoanne Koong /* These should be set by the user program */ 224e5070b6SJoanne Koong u32 nested_callback_nr_loops; 234e5070b6SJoanne Koong u32 stop_index = -1; 244e5070b6SJoanne Koong u32 nr_loops; 254e5070b6SJoanne Koong int pid; 26*0e1bf9edSEduard Zingerman int callback_selector; 274e5070b6SJoanne Koong 284e5070b6SJoanne Koong /* Making these global variables so that the userspace program 294e5070b6SJoanne Koong * can verify the output through the skeleton 304e5070b6SJoanne Koong */ 314e5070b6SJoanne Koong int nr_loops_returned; 324e5070b6SJoanne Koong int g_output; 334e5070b6SJoanne Koong int err; 344e5070b6SJoanne Koong 354e5070b6SJoanne Koong static int callback(__u32 index, void *data) 364e5070b6SJoanne Koong { 374e5070b6SJoanne Koong struct callback_ctx *ctx = data; 384e5070b6SJoanne Koong 394e5070b6SJoanne Koong if (index >= stop_index) 404e5070b6SJoanne Koong return 1; 414e5070b6SJoanne Koong 424e5070b6SJoanne Koong ctx->output += index; 434e5070b6SJoanne Koong 444e5070b6SJoanne Koong return 0; 454e5070b6SJoanne Koong } 464e5070b6SJoanne Koong 474e5070b6SJoanne Koong static int empty_callback(__u32 index, void *data) 484e5070b6SJoanne Koong { 494e5070b6SJoanne Koong return 0; 504e5070b6SJoanne Koong } 514e5070b6SJoanne Koong 524e5070b6SJoanne Koong static int nested_callback2(__u32 index, void *data) 534e5070b6SJoanne Koong { 544e5070b6SJoanne Koong nr_loops_returned += bpf_loop(nested_callback_nr_loops, callback, data, 0); 554e5070b6SJoanne Koong 564e5070b6SJoanne Koong return 0; 574e5070b6SJoanne Koong } 584e5070b6SJoanne Koong 594e5070b6SJoanne Koong static int nested_callback1(__u32 index, void *data) 604e5070b6SJoanne Koong { 614e5070b6SJoanne Koong bpf_loop(nested_callback_nr_loops, nested_callback2, data, 0); 624e5070b6SJoanne Koong return 0; 634e5070b6SJoanne Koong } 644e5070b6SJoanne Koong 65e91d280cSNaveen N. Rao SEC("fentry/" SYS_PREFIX "sys_nanosleep") 664e5070b6SJoanne Koong int test_prog(void *ctx) 674e5070b6SJoanne Koong { 684e5070b6SJoanne Koong struct callback_ctx data = {}; 694e5070b6SJoanne Koong 704e5070b6SJoanne Koong if (bpf_get_current_pid_tgid() >> 32 != pid) 714e5070b6SJoanne Koong return 0; 724e5070b6SJoanne Koong 734e5070b6SJoanne Koong nr_loops_returned = bpf_loop(nr_loops, callback, &data, 0); 744e5070b6SJoanne Koong 754e5070b6SJoanne Koong if (nr_loops_returned < 0) 764e5070b6SJoanne Koong err = nr_loops_returned; 774e5070b6SJoanne Koong else 784e5070b6SJoanne Koong g_output = data.output; 794e5070b6SJoanne Koong 804e5070b6SJoanne Koong return 0; 814e5070b6SJoanne Koong } 824e5070b6SJoanne Koong 83e91d280cSNaveen N. Rao SEC("fentry/" SYS_PREFIX "sys_nanosleep") 844e5070b6SJoanne Koong int prog_null_ctx(void *ctx) 854e5070b6SJoanne Koong { 864e5070b6SJoanne Koong if (bpf_get_current_pid_tgid() >> 32 != pid) 874e5070b6SJoanne Koong return 0; 884e5070b6SJoanne Koong 894e5070b6SJoanne Koong nr_loops_returned = bpf_loop(nr_loops, empty_callback, NULL, 0); 904e5070b6SJoanne Koong 914e5070b6SJoanne Koong return 0; 924e5070b6SJoanne Koong } 934e5070b6SJoanne Koong 94e91d280cSNaveen N. Rao SEC("fentry/" SYS_PREFIX "sys_nanosleep") 954e5070b6SJoanne Koong int prog_invalid_flags(void *ctx) 964e5070b6SJoanne Koong { 974e5070b6SJoanne Koong struct callback_ctx data = {}; 984e5070b6SJoanne Koong 994e5070b6SJoanne Koong if (bpf_get_current_pid_tgid() >> 32 != pid) 1004e5070b6SJoanne Koong return 0; 1014e5070b6SJoanne Koong 1024e5070b6SJoanne Koong err = bpf_loop(nr_loops, callback, &data, 1); 1034e5070b6SJoanne Koong 1044e5070b6SJoanne Koong return 0; 1054e5070b6SJoanne Koong } 1064e5070b6SJoanne Koong 107e91d280cSNaveen N. Rao SEC("fentry/" SYS_PREFIX "sys_nanosleep") 1084e5070b6SJoanne Koong int prog_nested_calls(void *ctx) 1094e5070b6SJoanne Koong { 1104e5070b6SJoanne Koong struct callback_ctx data = {}; 1114e5070b6SJoanne Koong 1124e5070b6SJoanne Koong if (bpf_get_current_pid_tgid() >> 32 != pid) 1134e5070b6SJoanne Koong return 0; 1144e5070b6SJoanne Koong 1154e5070b6SJoanne Koong nr_loops_returned = 0; 1164e5070b6SJoanne Koong bpf_loop(nr_loops, nested_callback1, &data, 0); 1174e5070b6SJoanne Koong 1184e5070b6SJoanne Koong g_output = data.output; 1194e5070b6SJoanne Koong 1204e5070b6SJoanne Koong return 0; 1214e5070b6SJoanne Koong } 122*0e1bf9edSEduard Zingerman 123*0e1bf9edSEduard Zingerman static int callback_set_f0(int i, void *ctx) 124*0e1bf9edSEduard Zingerman { 125*0e1bf9edSEduard Zingerman g_output = 0xF0; 126*0e1bf9edSEduard Zingerman return 0; 127*0e1bf9edSEduard Zingerman } 128*0e1bf9edSEduard Zingerman 129*0e1bf9edSEduard Zingerman static int callback_set_0f(int i, void *ctx) 130*0e1bf9edSEduard Zingerman { 131*0e1bf9edSEduard Zingerman g_output = 0x0F; 132*0e1bf9edSEduard Zingerman return 0; 133*0e1bf9edSEduard Zingerman } 134*0e1bf9edSEduard Zingerman 135*0e1bf9edSEduard Zingerman /* 136*0e1bf9edSEduard Zingerman * non-constant callback is a corner case for bpf_loop inline logic 137*0e1bf9edSEduard Zingerman */ 138*0e1bf9edSEduard Zingerman SEC("fentry/" SYS_PREFIX "sys_nanosleep") 139*0e1bf9edSEduard Zingerman int prog_non_constant_callback(void *ctx) 140*0e1bf9edSEduard Zingerman { 141*0e1bf9edSEduard Zingerman struct callback_ctx data = {}; 142*0e1bf9edSEduard Zingerman 143*0e1bf9edSEduard Zingerman if (bpf_get_current_pid_tgid() >> 32 != pid) 144*0e1bf9edSEduard Zingerman return 0; 145*0e1bf9edSEduard Zingerman 146*0e1bf9edSEduard Zingerman int (*callback)(int i, void *ctx); 147*0e1bf9edSEduard Zingerman 148*0e1bf9edSEduard Zingerman g_output = 0; 149*0e1bf9edSEduard Zingerman 150*0e1bf9edSEduard Zingerman if (callback_selector == 0x0F) 151*0e1bf9edSEduard Zingerman callback = callback_set_0f; 152*0e1bf9edSEduard Zingerman else 153*0e1bf9edSEduard Zingerman callback = callback_set_f0; 154*0e1bf9edSEduard Zingerman 155*0e1bf9edSEduard Zingerman bpf_loop(1, callback, NULL, 0); 156*0e1bf9edSEduard Zingerman 157*0e1bf9edSEduard Zingerman return 0; 158*0e1bf9edSEduard Zingerman } 159*0e1bf9edSEduard Zingerman 160*0e1bf9edSEduard Zingerman static int stack_check_inner_callback(void *ctx) 161*0e1bf9edSEduard Zingerman { 162*0e1bf9edSEduard Zingerman return 0; 163*0e1bf9edSEduard Zingerman } 164*0e1bf9edSEduard Zingerman 165*0e1bf9edSEduard Zingerman static int map1_lookup_elem(int key) 166*0e1bf9edSEduard Zingerman { 167*0e1bf9edSEduard Zingerman int *val = bpf_map_lookup_elem(&map1, &key); 168*0e1bf9edSEduard Zingerman 169*0e1bf9edSEduard Zingerman return val ? *val : -1; 170*0e1bf9edSEduard Zingerman } 171*0e1bf9edSEduard Zingerman 172*0e1bf9edSEduard Zingerman static void map1_update_elem(int key, int val) 173*0e1bf9edSEduard Zingerman { 174*0e1bf9edSEduard Zingerman bpf_map_update_elem(&map1, &key, &val, BPF_ANY); 175*0e1bf9edSEduard Zingerman } 176*0e1bf9edSEduard Zingerman 177*0e1bf9edSEduard Zingerman static int stack_check_outer_callback(void *ctx) 178*0e1bf9edSEduard Zingerman { 179*0e1bf9edSEduard Zingerman int a = map1_lookup_elem(1); 180*0e1bf9edSEduard Zingerman int b = map1_lookup_elem(2); 181*0e1bf9edSEduard Zingerman int c = map1_lookup_elem(3); 182*0e1bf9edSEduard Zingerman int d = map1_lookup_elem(4); 183*0e1bf9edSEduard Zingerman int e = map1_lookup_elem(5); 184*0e1bf9edSEduard Zingerman int f = map1_lookup_elem(6); 185*0e1bf9edSEduard Zingerman 186*0e1bf9edSEduard Zingerman bpf_loop(1, stack_check_inner_callback, NULL, 0); 187*0e1bf9edSEduard Zingerman 188*0e1bf9edSEduard Zingerman map1_update_elem(1, a + 1); 189*0e1bf9edSEduard Zingerman map1_update_elem(2, b + 1); 190*0e1bf9edSEduard Zingerman map1_update_elem(3, c + 1); 191*0e1bf9edSEduard Zingerman map1_update_elem(4, d + 1); 192*0e1bf9edSEduard Zingerman map1_update_elem(5, e + 1); 193*0e1bf9edSEduard Zingerman map1_update_elem(6, f + 1); 194*0e1bf9edSEduard Zingerman 195*0e1bf9edSEduard Zingerman return 0; 196*0e1bf9edSEduard Zingerman } 197*0e1bf9edSEduard Zingerman 198*0e1bf9edSEduard Zingerman /* Some of the local variables in stack_check and 199*0e1bf9edSEduard Zingerman * stack_check_outer_callback would be allocated on stack by 200*0e1bf9edSEduard Zingerman * compiler. This test should verify that stack content for these 201*0e1bf9edSEduard Zingerman * variables is preserved between calls to bpf_loop (might be an issue 202*0e1bf9edSEduard Zingerman * if loop inlining allocates stack slots incorrectly). 203*0e1bf9edSEduard Zingerman */ 204*0e1bf9edSEduard Zingerman SEC("fentry/" SYS_PREFIX "sys_nanosleep") 205*0e1bf9edSEduard Zingerman int stack_check(void *ctx) 206*0e1bf9edSEduard Zingerman { 207*0e1bf9edSEduard Zingerman if (bpf_get_current_pid_tgid() >> 32 != pid) 208*0e1bf9edSEduard Zingerman return 0; 209*0e1bf9edSEduard Zingerman 210*0e1bf9edSEduard Zingerman int a = map1_lookup_elem(7); 211*0e1bf9edSEduard Zingerman int b = map1_lookup_elem(8); 212*0e1bf9edSEduard Zingerman int c = map1_lookup_elem(9); 213*0e1bf9edSEduard Zingerman int d = map1_lookup_elem(10); 214*0e1bf9edSEduard Zingerman int e = map1_lookup_elem(11); 215*0e1bf9edSEduard Zingerman int f = map1_lookup_elem(12); 216*0e1bf9edSEduard Zingerman 217*0e1bf9edSEduard Zingerman bpf_loop(1, stack_check_outer_callback, NULL, 0); 218*0e1bf9edSEduard Zingerman 219*0e1bf9edSEduard Zingerman map1_update_elem(7, a + 1); 220*0e1bf9edSEduard Zingerman map1_update_elem(8, b + 1); 221*0e1bf9edSEduard Zingerman map1_update_elem(9, c + 1); 222*0e1bf9edSEduard Zingerman map1_update_elem(10, d + 1); 223*0e1bf9edSEduard Zingerman map1_update_elem(11, e + 1); 224*0e1bf9edSEduard Zingerman map1_update_elem(12, f + 1); 225*0e1bf9edSEduard Zingerman 226*0e1bf9edSEduard Zingerman return 0; 227*0e1bf9edSEduard Zingerman } 228