1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright (c) 2019 Facebook */
3*4882a593Smuzhiyun #include <linux/stddef.h>
4*4882a593Smuzhiyun #include <linux/if_ether.h>
5*4882a593Smuzhiyun #include <linux/ipv6.h>
6*4882a593Smuzhiyun #include <linux/bpf.h>
7*4882a593Smuzhiyun #include <linux/tcp.h>
8*4882a593Smuzhiyun #include <bpf/bpf_helpers.h>
9*4882a593Smuzhiyun #include <bpf/bpf_endian.h>
10*4882a593Smuzhiyun #include <bpf/bpf_tracing.h>
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun struct sk_buff {
13*4882a593Smuzhiyun unsigned int len;
14*4882a593Smuzhiyun };
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun __u64 test_result = 0;
17*4882a593Smuzhiyun SEC("fexit/test_pkt_access")
BPF_PROG(test_main,struct sk_buff * skb,int ret)18*4882a593Smuzhiyun int BPF_PROG(test_main, struct sk_buff *skb, int ret)
19*4882a593Smuzhiyun {
20*4882a593Smuzhiyun int len;
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun __builtin_preserve_access_index(({
23*4882a593Smuzhiyun len = skb->len;
24*4882a593Smuzhiyun }));
25*4882a593Smuzhiyun if (len != 74 || ret != 0)
26*4882a593Smuzhiyun return 0;
27*4882a593Smuzhiyun test_result = 1;
28*4882a593Smuzhiyun return 0;
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun __u64 test_result_subprog1 = 0;
32*4882a593Smuzhiyun SEC("fexit/test_pkt_access_subprog1")
BPF_PROG(test_subprog1,struct sk_buff * skb,int ret)33*4882a593Smuzhiyun int BPF_PROG(test_subprog1, struct sk_buff *skb, int ret)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun int len;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun __builtin_preserve_access_index(({
38*4882a593Smuzhiyun len = skb->len;
39*4882a593Smuzhiyun }));
40*4882a593Smuzhiyun if (len != 74 || ret != 148)
41*4882a593Smuzhiyun return 0;
42*4882a593Smuzhiyun test_result_subprog1 = 1;
43*4882a593Smuzhiyun return 0;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun /* Though test_pkt_access_subprog2() is defined in C as:
47*4882a593Smuzhiyun * static __attribute__ ((noinline))
48*4882a593Smuzhiyun * int test_pkt_access_subprog2(int val, volatile struct __sk_buff *skb)
49*4882a593Smuzhiyun * {
50*4882a593Smuzhiyun * return skb->len * val;
51*4882a593Smuzhiyun * }
52*4882a593Smuzhiyun * llvm optimizations remove 'int val' argument and generate BPF assembly:
53*4882a593Smuzhiyun * r0 = *(u32 *)(r1 + 0)
54*4882a593Smuzhiyun * w0 <<= 1
55*4882a593Smuzhiyun * exit
56*4882a593Smuzhiyun * In such case the verifier falls back to conservative and
57*4882a593Smuzhiyun * tracing program can access arguments and return value as u64
58*4882a593Smuzhiyun * instead of accurate types.
59*4882a593Smuzhiyun */
60*4882a593Smuzhiyun struct args_subprog2 {
61*4882a593Smuzhiyun __u64 args[5];
62*4882a593Smuzhiyun __u64 ret;
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun __u64 test_result_subprog2 = 0;
65*4882a593Smuzhiyun SEC("fexit/test_pkt_access_subprog2")
test_subprog2(struct args_subprog2 * ctx)66*4882a593Smuzhiyun int test_subprog2(struct args_subprog2 *ctx)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun struct sk_buff *skb = (void *)ctx->args[0];
69*4882a593Smuzhiyun __u64 ret;
70*4882a593Smuzhiyun int len;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun bpf_probe_read_kernel(&len, sizeof(len),
73*4882a593Smuzhiyun __builtin_preserve_access_index(&skb->len));
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun ret = ctx->ret;
76*4882a593Smuzhiyun /* bpf_prog_load() loads "test_pkt_access.o" with BPF_F_TEST_RND_HI32
77*4882a593Smuzhiyun * which randomizes upper 32 bits after BPF_ALU32 insns.
78*4882a593Smuzhiyun * Hence after 'w0 <<= 1' upper bits of $rax are random.
79*4882a593Smuzhiyun * That is expected and correct. Trim them.
80*4882a593Smuzhiyun */
81*4882a593Smuzhiyun ret = (__u32) ret;
82*4882a593Smuzhiyun if (len != 74 || ret != 148)
83*4882a593Smuzhiyun return 0;
84*4882a593Smuzhiyun test_result_subprog2 = 1;
85*4882a593Smuzhiyun return 0;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun __u64 test_result_subprog3 = 0;
89*4882a593Smuzhiyun SEC("fexit/test_pkt_access_subprog3")
BPF_PROG(test_subprog3,int val,struct sk_buff * skb,int ret)90*4882a593Smuzhiyun int BPF_PROG(test_subprog3, int val, struct sk_buff *skb, int ret)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun int len;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun __builtin_preserve_access_index(({
95*4882a593Smuzhiyun len = skb->len;
96*4882a593Smuzhiyun }));
97*4882a593Smuzhiyun if (len != 74 || ret != 74 * val || val != 3)
98*4882a593Smuzhiyun return 0;
99*4882a593Smuzhiyun test_result_subprog3 = 1;
100*4882a593Smuzhiyun return 0;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun __u64 test_get_skb_len = 0;
104*4882a593Smuzhiyun SEC("freplace/get_skb_len")
new_get_skb_len(struct __sk_buff * skb)105*4882a593Smuzhiyun int new_get_skb_len(struct __sk_buff *skb)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun int len = skb->len;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun if (len != 74)
110*4882a593Smuzhiyun return 0;
111*4882a593Smuzhiyun test_get_skb_len = 1;
112*4882a593Smuzhiyun return 74; /* original get_skb_len() returns skb->len */
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun __u64 test_get_skb_ifindex = 0;
116*4882a593Smuzhiyun SEC("freplace/get_skb_ifindex")
new_get_skb_ifindex(int val,struct __sk_buff * skb,int var)117*4882a593Smuzhiyun int new_get_skb_ifindex(int val, struct __sk_buff *skb, int var)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun void *data_end = (void *)(long)skb->data_end;
120*4882a593Smuzhiyun void *data = (void *)(long)skb->data;
121*4882a593Smuzhiyun struct ipv6hdr ip6, *ip6p;
122*4882a593Smuzhiyun int ifindex = skb->ifindex;
123*4882a593Smuzhiyun __u32 eth_proto;
124*4882a593Smuzhiyun __u32 nh_off;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun /* check that BPF extension can read packet via direct packet access */
127*4882a593Smuzhiyun if (data + 14 + sizeof(ip6) > data_end)
128*4882a593Smuzhiyun return 0;
129*4882a593Smuzhiyun ip6p = data + 14;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun if (ip6p->nexthdr != 6 || ip6p->payload_len != __bpf_constant_htons(123))
132*4882a593Smuzhiyun return 0;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /* check that legacy packet access helper works too */
135*4882a593Smuzhiyun if (bpf_skb_load_bytes(skb, 14, &ip6, sizeof(ip6)) < 0)
136*4882a593Smuzhiyun return 0;
137*4882a593Smuzhiyun ip6p = &ip6;
138*4882a593Smuzhiyun if (ip6p->nexthdr != 6 || ip6p->payload_len != __bpf_constant_htons(123))
139*4882a593Smuzhiyun return 0;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun if (ifindex != 1 || val != 3 || var != 1)
142*4882a593Smuzhiyun return 0;
143*4882a593Smuzhiyun test_get_skb_ifindex = 1;
144*4882a593Smuzhiyun return 3; /* original get_skb_ifindex() returns val * ifindex * var */
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun volatile __u64 test_get_constant = 0;
148*4882a593Smuzhiyun SEC("freplace/get_constant")
new_get_constant(long val)149*4882a593Smuzhiyun int new_get_constant(long val)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun if (val != 123)
152*4882a593Smuzhiyun return 0;
153*4882a593Smuzhiyun test_get_constant = 1;
154*4882a593Smuzhiyun return test_get_constant; /* original get_constant() returns val - 122 */
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun __u64 test_pkt_write_access_subprog = 0;
158*4882a593Smuzhiyun SEC("freplace/test_pkt_write_access_subprog")
new_test_pkt_write_access_subprog(struct __sk_buff * skb,__u32 off)159*4882a593Smuzhiyun int new_test_pkt_write_access_subprog(struct __sk_buff *skb, __u32 off)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun void *data = (void *)(long)skb->data;
163*4882a593Smuzhiyun void *data_end = (void *)(long)skb->data_end;
164*4882a593Smuzhiyun struct tcphdr *tcp;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun if (off > sizeof(struct ethhdr) + sizeof(struct ipv6hdr))
167*4882a593Smuzhiyun return -1;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun tcp = data + off;
170*4882a593Smuzhiyun if (tcp + 1 > data_end)
171*4882a593Smuzhiyun return -1;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun /* make modifications to the packet data */
174*4882a593Smuzhiyun tcp->check++;
175*4882a593Smuzhiyun tcp->syn = 0;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun test_pkt_write_access_subprog = 1;
178*4882a593Smuzhiyun return 0;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun char _license[] SEC("license") = "GPL";
182