Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (c) 2019 Facebook */
0003 #include <linux/stddef.h>
0004 #include <linux/if_ether.h>
0005 #include <linux/ipv6.h>
0006 #include <linux/bpf.h>
0007 #include <linux/tcp.h>
0008 #include <bpf/bpf_helpers.h>
0009 #include <bpf/bpf_endian.h>
0010 #include <bpf/bpf_tracing.h>
0011 
0012 struct sk_buff {
0013     unsigned int len;
0014 };
0015 
0016 __u64 test_result = 0;
0017 SEC("fexit/test_pkt_access")
0018 int BPF_PROG(test_main, struct sk_buff *skb, int ret)
0019 {
0020     int len;
0021 
0022     __builtin_preserve_access_index(({
0023         len = skb->len;
0024     }));
0025     if (len != 74 || ret != 0)
0026         return 0;
0027     test_result = 1;
0028     return 0;
0029 }
0030 
0031 __u64 test_result_subprog1 = 0;
0032 SEC("fexit/test_pkt_access_subprog1")
0033 int BPF_PROG(test_subprog1, struct sk_buff *skb, int ret)
0034 {
0035     int len;
0036 
0037     __builtin_preserve_access_index(({
0038         len = skb->len;
0039     }));
0040     if (len != 74 || ret != 148)
0041         return 0;
0042     test_result_subprog1 = 1;
0043     return 0;
0044 }
0045 
0046 /* Though test_pkt_access_subprog2() is defined in C as:
0047  * static __attribute__ ((noinline))
0048  * int test_pkt_access_subprog2(int val, volatile struct __sk_buff *skb)
0049  * {
0050  *     return skb->len * val;
0051  * }
0052  * llvm optimizations remove 'int val' argument and generate BPF assembly:
0053  *   r0 = *(u32 *)(r1 + 0)
0054  *   w0 <<= 1
0055  *   exit
0056  * In such case the verifier falls back to conservative and
0057  * tracing program can access arguments and return value as u64
0058  * instead of accurate types.
0059  */
0060 struct args_subprog2 {
0061     __u64 args[5];
0062     __u64 ret;
0063 };
0064 __u64 test_result_subprog2 = 0;
0065 SEC("fexit/test_pkt_access_subprog2")
0066 int test_subprog2(struct args_subprog2 *ctx)
0067 {
0068     struct sk_buff *skb = (void *)ctx->args[0];
0069     __u64 ret;
0070     int len;
0071 
0072     bpf_probe_read_kernel(&len, sizeof(len),
0073                   __builtin_preserve_access_index(&skb->len));
0074 
0075     ret = ctx->ret;
0076     /* bpf_prog_test_load() loads "test_pkt_access.o" with BPF_F_TEST_RND_HI32
0077      * which randomizes upper 32 bits after BPF_ALU32 insns.
0078      * Hence after 'w0 <<= 1' upper bits of $rax are random.
0079      * That is expected and correct. Trim them.
0080      */
0081     ret = (__u32) ret;
0082     if (len != 74 || ret != 148)
0083         return 0;
0084     test_result_subprog2 = 1;
0085     return 0;
0086 }
0087 
0088 __u64 test_result_subprog3 = 0;
0089 SEC("fexit/test_pkt_access_subprog3")
0090 int BPF_PROG(test_subprog3, int val, struct sk_buff *skb, int ret)
0091 {
0092     int len;
0093 
0094     __builtin_preserve_access_index(({
0095         len = skb->len;
0096     }));
0097     if (len != 74 || ret != 74 * val || val != 3)
0098         return 0;
0099     test_result_subprog3 = 1;
0100     return 0;
0101 }
0102 
0103 __u64 test_get_skb_len = 0;
0104 SEC("freplace/get_skb_len")
0105 int new_get_skb_len(struct __sk_buff *skb)
0106 {
0107     int len = skb->len;
0108 
0109     if (len != 74)
0110         return 0;
0111     test_get_skb_len = 1;
0112     return 74; /* original get_skb_len() returns skb->len */
0113 }
0114 
0115 __u64 test_get_skb_ifindex = 0;
0116 SEC("freplace/get_skb_ifindex")
0117 int new_get_skb_ifindex(int val, struct __sk_buff *skb, int var)
0118 {
0119     void *data_end = (void *)(long)skb->data_end;
0120     void *data = (void *)(long)skb->data;
0121     struct ipv6hdr ip6, *ip6p;
0122     int ifindex = skb->ifindex;
0123     __u32 eth_proto;
0124     __u32 nh_off;
0125 
0126     /* check that BPF extension can read packet via direct packet access */
0127     if (data + 14 + sizeof(ip6) > data_end)
0128         return 0;
0129     ip6p = data + 14;
0130 
0131     if (ip6p->nexthdr != 6 || ip6p->payload_len != __bpf_constant_htons(123))
0132         return 0;
0133 
0134     /* check that legacy packet access helper works too */
0135     if (bpf_skb_load_bytes(skb, 14, &ip6, sizeof(ip6)) < 0)
0136         return 0;
0137     ip6p = &ip6;
0138     if (ip6p->nexthdr != 6 || ip6p->payload_len != __bpf_constant_htons(123))
0139         return 0;
0140 
0141     if (ifindex != 1 || val != 3 || var != 1)
0142         return 0;
0143     test_get_skb_ifindex = 1;
0144     return 3; /* original get_skb_ifindex() returns val * ifindex * var */
0145 }
0146 
0147 volatile __u64 test_get_constant = 0;
0148 SEC("freplace/get_constant")
0149 int new_get_constant(long val)
0150 {
0151     if (val != 123)
0152         return 0;
0153     test_get_constant = 1;
0154     return test_get_constant; /* original get_constant() returns val - 122 */
0155 }
0156 
0157 __u64 test_pkt_write_access_subprog = 0;
0158 SEC("freplace/test_pkt_write_access_subprog")
0159 int new_test_pkt_write_access_subprog(struct __sk_buff *skb, __u32 off)
0160 {
0161 
0162     void *data = (void *)(long)skb->data;
0163     void *data_end = (void *)(long)skb->data_end;
0164     struct tcphdr *tcp;
0165 
0166     if (off > sizeof(struct ethhdr) + sizeof(struct ipv6hdr))
0167         return -1;
0168 
0169     tcp = data + off;
0170     if (tcp + 1 > data_end)
0171         return -1;
0172 
0173     /* make modifications to the packet data */
0174     tcp->check++;
0175     tcp->syn = 0;
0176 
0177     test_pkt_write_access_subprog = 1;
0178     return 0;
0179 }
0180 
0181 char _license[] SEC("license") = "GPL";