Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (c) 2021 Facebook */
0003 
0004 #include "vmlinux.h"
0005 #include <bpf/bpf_helpers.h>
0006 #include "bpf_misc.h"
0007 
0008 char _license[] SEC("license") = "GPL";
0009 
0010 struct callback_ctx {
0011     int output;
0012 };
0013 
0014 struct {
0015     __uint(type, BPF_MAP_TYPE_HASH);
0016     __uint(max_entries, 32);
0017     __type(key, int);
0018     __type(value, int);
0019 } map1 SEC(".maps");
0020 
0021 /* These should be set by the user program */
0022 u32 nested_callback_nr_loops;
0023 u32 stop_index = -1;
0024 u32 nr_loops;
0025 int pid;
0026 int callback_selector;
0027 
0028 /* Making these global variables so that the userspace program
0029  * can verify the output through the skeleton
0030  */
0031 int nr_loops_returned;
0032 int g_output;
0033 int err;
0034 
0035 static int callback(__u32 index, void *data)
0036 {
0037     struct callback_ctx *ctx = data;
0038 
0039     if (index >= stop_index)
0040         return 1;
0041 
0042     ctx->output += index;
0043 
0044     return 0;
0045 }
0046 
0047 static int empty_callback(__u32 index, void *data)
0048 {
0049     return 0;
0050 }
0051 
0052 static int nested_callback2(__u32 index, void *data)
0053 {
0054     nr_loops_returned += bpf_loop(nested_callback_nr_loops, callback, data, 0);
0055 
0056     return 0;
0057 }
0058 
0059 static int nested_callback1(__u32 index, void *data)
0060 {
0061     bpf_loop(nested_callback_nr_loops, nested_callback2, data, 0);
0062     return 0;
0063 }
0064 
0065 SEC("fentry/" SYS_PREFIX "sys_nanosleep")
0066 int test_prog(void *ctx)
0067 {
0068     struct callback_ctx data = {};
0069 
0070     if (bpf_get_current_pid_tgid() >> 32 != pid)
0071         return 0;
0072 
0073     nr_loops_returned = bpf_loop(nr_loops, callback, &data, 0);
0074 
0075     if (nr_loops_returned < 0)
0076         err = nr_loops_returned;
0077     else
0078         g_output = data.output;
0079 
0080     return 0;
0081 }
0082 
0083 SEC("fentry/" SYS_PREFIX "sys_nanosleep")
0084 int prog_null_ctx(void *ctx)
0085 {
0086     if (bpf_get_current_pid_tgid() >> 32 != pid)
0087         return 0;
0088 
0089     nr_loops_returned = bpf_loop(nr_loops, empty_callback, NULL, 0);
0090 
0091     return 0;
0092 }
0093 
0094 SEC("fentry/" SYS_PREFIX "sys_nanosleep")
0095 int prog_invalid_flags(void *ctx)
0096 {
0097     struct callback_ctx data = {};
0098 
0099     if (bpf_get_current_pid_tgid() >> 32 != pid)
0100         return 0;
0101 
0102     err = bpf_loop(nr_loops, callback, &data, 1);
0103 
0104     return 0;
0105 }
0106 
0107 SEC("fentry/" SYS_PREFIX "sys_nanosleep")
0108 int prog_nested_calls(void *ctx)
0109 {
0110     struct callback_ctx data = {};
0111 
0112     if (bpf_get_current_pid_tgid() >> 32 != pid)
0113         return 0;
0114 
0115     nr_loops_returned = 0;
0116     bpf_loop(nr_loops, nested_callback1, &data, 0);
0117 
0118     g_output = data.output;
0119 
0120     return 0;
0121 }
0122 
0123 static int callback_set_f0(int i, void *ctx)
0124 {
0125     g_output = 0xF0;
0126     return 0;
0127 }
0128 
0129 static int callback_set_0f(int i, void *ctx)
0130 {
0131     g_output = 0x0F;
0132     return 0;
0133 }
0134 
0135 /*
0136  * non-constant callback is a corner case for bpf_loop inline logic
0137  */
0138 SEC("fentry/" SYS_PREFIX "sys_nanosleep")
0139 int prog_non_constant_callback(void *ctx)
0140 {
0141     struct callback_ctx data = {};
0142 
0143     if (bpf_get_current_pid_tgid() >> 32 != pid)
0144         return 0;
0145 
0146     int (*callback)(int i, void *ctx);
0147 
0148     g_output = 0;
0149 
0150     if (callback_selector == 0x0F)
0151         callback = callback_set_0f;
0152     else
0153         callback = callback_set_f0;
0154 
0155     bpf_loop(1, callback, NULL, 0);
0156 
0157     return 0;
0158 }
0159 
0160 static int stack_check_inner_callback(void *ctx)
0161 {
0162     return 0;
0163 }
0164 
0165 static int map1_lookup_elem(int key)
0166 {
0167     int *val = bpf_map_lookup_elem(&map1, &key);
0168 
0169     return val ? *val : -1;
0170 }
0171 
0172 static void map1_update_elem(int key, int val)
0173 {
0174     bpf_map_update_elem(&map1, &key, &val, BPF_ANY);
0175 }
0176 
0177 static int stack_check_outer_callback(void *ctx)
0178 {
0179     int a = map1_lookup_elem(1);
0180     int b = map1_lookup_elem(2);
0181     int c = map1_lookup_elem(3);
0182     int d = map1_lookup_elem(4);
0183     int e = map1_lookup_elem(5);
0184     int f = map1_lookup_elem(6);
0185 
0186     bpf_loop(1, stack_check_inner_callback, NULL, 0);
0187 
0188     map1_update_elem(1, a + 1);
0189     map1_update_elem(2, b + 1);
0190     map1_update_elem(3, c + 1);
0191     map1_update_elem(4, d + 1);
0192     map1_update_elem(5, e + 1);
0193     map1_update_elem(6, f + 1);
0194 
0195     return 0;
0196 }
0197 
0198 /* Some of the local variables in stack_check and
0199  * stack_check_outer_callback would be allocated on stack by
0200  * compiler. This test should verify that stack content for these
0201  * variables is preserved between calls to bpf_loop (might be an issue
0202  * if loop inlining allocates stack slots incorrectly).
0203  */
0204 SEC("fentry/" SYS_PREFIX "sys_nanosleep")
0205 int stack_check(void *ctx)
0206 {
0207     if (bpf_get_current_pid_tgid() >> 32 != pid)
0208         return 0;
0209 
0210     int a = map1_lookup_elem(7);
0211     int b = map1_lookup_elem(8);
0212     int c = map1_lookup_elem(9);
0213     int d = map1_lookup_elem(10);
0214     int e = map1_lookup_elem(11);
0215     int f = map1_lookup_elem(12);
0216 
0217     bpf_loop(1, stack_check_outer_callback, NULL, 0);
0218 
0219     map1_update_elem(7,  a + 1);
0220     map1_update_elem(8, b + 1);
0221     map1_update_elem(9, c + 1);
0222     map1_update_elem(10, d + 1);
0223     map1_update_elem(11, e + 1);
0224     map1_update_elem(12, f + 1);
0225 
0226     return 0;
0227 }