Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 #include <linux/bpf.h>
0004 #include <bpf/bpf_helpers.h>
0005 
0006 /* Permit pretty deep stack traces */
0007 #define MAX_STACK_RAWTP 100
0008 struct stack_trace_t {
0009     int pid;
0010     int kern_stack_size;
0011     int user_stack_size;
0012     int user_stack_buildid_size;
0013     __u64 kern_stack[MAX_STACK_RAWTP];
0014     __u64 user_stack[MAX_STACK_RAWTP];
0015     struct bpf_stack_build_id user_stack_buildid[MAX_STACK_RAWTP];
0016 };
0017 
0018 struct {
0019     __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
0020     __uint(max_entries, 2);
0021     __uint(key_size, sizeof(int));
0022     __uint(value_size, sizeof(__u32));
0023 } perfmap SEC(".maps");
0024 
0025 struct {
0026     __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
0027     __uint(max_entries, 1);
0028     __type(key, __u32);
0029     __type(value, struct stack_trace_t);
0030 } stackdata_map SEC(".maps");
0031 
0032 /* Allocate per-cpu space twice the needed. For the code below
0033  *   usize = bpf_get_stack(ctx, raw_data, max_len, BPF_F_USER_STACK);
0034  *   if (usize < 0)
0035  *     return 0;
0036  *   ksize = bpf_get_stack(ctx, raw_data + usize, max_len - usize, 0);
0037  *
0038  * If we have value_size = MAX_STACK_RAWTP * sizeof(__u64),
0039  * verifier will complain that access "raw_data + usize"
0040  * with size "max_len - usize" may be out of bound.
0041  * The maximum "raw_data + usize" is "raw_data + max_len"
0042  * and the maximum "max_len - usize" is "max_len", verifier
0043  * concludes that the maximum buffer access range is
0044  * "raw_data[0...max_len * 2 - 1]" and hence reject the program.
0045  *
0046  * Doubling the to-be-used max buffer size can fix this verifier
0047  * issue and avoid complicated C programming massaging.
0048  * This is an acceptable workaround since there is one entry here.
0049  */
0050 struct {
0051     __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
0052     __uint(max_entries, 1);
0053     __type(key, __u32);
0054     __type(value, __u64[2 * MAX_STACK_RAWTP]);
0055 } rawdata_map SEC(".maps");
0056 
0057 SEC("raw_tracepoint/sys_enter")
0058 int bpf_prog1(void *ctx)
0059 {
0060     int max_len, max_buildid_len, total_size;
0061     struct stack_trace_t *data;
0062     long usize, ksize;
0063     void *raw_data;
0064     __u32 key = 0;
0065 
0066     data = bpf_map_lookup_elem(&stackdata_map, &key);
0067     if (!data)
0068         return 0;
0069 
0070     max_len = MAX_STACK_RAWTP * sizeof(__u64);
0071     max_buildid_len = MAX_STACK_RAWTP * sizeof(struct bpf_stack_build_id);
0072     data->pid = bpf_get_current_pid_tgid();
0073     data->kern_stack_size = bpf_get_stack(ctx, data->kern_stack,
0074                           max_len, 0);
0075     data->user_stack_size = bpf_get_stack(ctx, data->user_stack, max_len,
0076                         BPF_F_USER_STACK);
0077     data->user_stack_buildid_size = bpf_get_stack(
0078         ctx, data->user_stack_buildid, max_buildid_len,
0079         BPF_F_USER_STACK | BPF_F_USER_BUILD_ID);
0080     bpf_perf_event_output(ctx, &perfmap, 0, data, sizeof(*data));
0081 
0082     /* write both kernel and user stacks to the same buffer */
0083     raw_data = bpf_map_lookup_elem(&rawdata_map, &key);
0084     if (!raw_data)
0085         return 0;
0086 
0087     usize = bpf_get_stack(ctx, raw_data, max_len, BPF_F_USER_STACK);
0088     if (usize < 0)
0089         return 0;
0090 
0091     ksize = bpf_get_stack(ctx, raw_data + usize, max_len - usize, 0);
0092     if (ksize < 0)
0093         return 0;
0094 
0095     total_size = usize + ksize;
0096     if (total_size > 0 && total_size <= max_len)
0097         bpf_perf_event_output(ctx, &perfmap, 0, raw_data, total_size);
0098 
0099     return 0;
0100 }
0101 
0102 char _license[] SEC("license") = "GPL";