Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2021 Facebook */ #include "vmlinux.h" #include <bpf/bpf_helpers.h> #include "bpf_misc.h" char _license[] SEC("license") = "GPL"; struct callback_ctx { int output; }; struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 32); __type(key, int); __type(value, int); } map1 SEC(".maps"); /* These should be set by the user program */ u32 nested_callback_nr_loops; u32 stop_index = -1; u32 nr_loops; int pid; int callback_selector; /* Making these global variables so that the userspace program * can verify the output through the skeleton */ int nr_loops_returned; int g_output; int err; static int callback(__u32 index, void *data) { struct callback_ctx *ctx = data; if (index >= stop_index) return 1; ctx->output += index; return 0; } static int empty_callback(__u32 index, void *data) { return 0; } static int nested_callback2(__u32 index, void *data) { nr_loops_returned += bpf_loop(nested_callback_nr_loops, callback, data, 0); return 0; } static int nested_callback1(__u32 index, void *data) { bpf_loop(nested_callback_nr_loops, nested_callback2, data, 0); return 0; } SEC("fentry/" SYS_PREFIX "sys_nanosleep") int test_prog(void *ctx) { struct callback_ctx data = {}; if (bpf_get_current_pid_tgid() >> 32 != pid) return 0; nr_loops_returned = bpf_loop(nr_loops, callback, &data, 0); if (nr_loops_returned < 0) err = nr_loops_returned; else g_output = data.output; return 0; } SEC("fentry/" SYS_PREFIX "sys_nanosleep") int prog_null_ctx(void *ctx) { if (bpf_get_current_pid_tgid() >> 32 != pid) return 0; nr_loops_returned = bpf_loop(nr_loops, empty_callback, NULL, 0); return 0; } SEC("fentry/" SYS_PREFIX "sys_nanosleep") int prog_invalid_flags(void *ctx) { struct callback_ctx data = {}; if (bpf_get_current_pid_tgid() >> 32 != pid) return 0; err = bpf_loop(nr_loops, callback, &data, 1); return 0; } SEC("fentry/" SYS_PREFIX "sys_nanosleep") int prog_nested_calls(void *ctx) { struct callback_ctx data = {}; if (bpf_get_current_pid_tgid() >> 32 != pid) return 0; nr_loops_returned = 0; bpf_loop(nr_loops, nested_callback1, &data, 0); g_output = data.output; return 0; } static int callback_set_f0(int i, void *ctx) { g_output = 0xF0; return 0; } static int callback_set_0f(int i, void *ctx) { g_output = 0x0F; return 0; } /* * non-constant callback is a corner case for bpf_loop inline logic */ SEC("fentry/" SYS_PREFIX "sys_nanosleep") int prog_non_constant_callback(void *ctx) { if (bpf_get_current_pid_tgid() >> 32 != pid) return 0; int (*callback)(int i, void *ctx); g_output = 0; if (callback_selector == 0x0F) callback = callback_set_0f; else callback = callback_set_f0; bpf_loop(1, callback, NULL, 0); return 0; } static int stack_check_inner_callback(void *ctx) { return 0; } static int map1_lookup_elem(int key) { int *val = bpf_map_lookup_elem(&map1, &key); return val ? *val : -1; } static void map1_update_elem(int key, int val) { bpf_map_update_elem(&map1, &key, &val, BPF_ANY); } static int stack_check_outer_callback(void *ctx) { int a = map1_lookup_elem(1); int b = map1_lookup_elem(2); int c = map1_lookup_elem(3); int d = map1_lookup_elem(4); int e = map1_lookup_elem(5); int f = map1_lookup_elem(6); bpf_loop(1, stack_check_inner_callback, NULL, 0); map1_update_elem(1, a + 1); map1_update_elem(2, b + 1); map1_update_elem(3, c + 1); map1_update_elem(4, d + 1); map1_update_elem(5, e + 1); map1_update_elem(6, f + 1); return 0; } /* Some of the local variables in stack_check and * stack_check_outer_callback would be allocated on stack by * compiler. This test should verify that stack content for these * variables is preserved between calls to bpf_loop (might be an issue * if loop inlining allocates stack slots incorrectly). */ SEC("fentry/" SYS_PREFIX "sys_nanosleep") int stack_check(void *ctx) { if (bpf_get_current_pid_tgid() >> 32 != pid) return 0; int a = map1_lookup_elem(7); int b = map1_lookup_elem(8); int c = map1_lookup_elem(9); int d = map1_lookup_elem(10); int e = map1_lookup_elem(11); int f = map1_lookup_elem(12); bpf_loop(1, stack_check_outer_callback, NULL, 0); map1_update_elem(7, a + 1); map1_update_elem(8, b + 1); map1_update_elem(9, c + 1); map1_update_elem(10, d + 1); map1_update_elem(11, e + 1); map1_update_elem(12, f + 1); return 0; } |