1d6f39601SAlexei Starovoitov // SPDX-License-Identifier: GPL-2.0 2d6f39601SAlexei Starovoitov /* Copyright (c) 2019 Facebook */ 37805fe84SAlexei Starovoitov #include <linux/stddef.h> 47805fe84SAlexei Starovoitov #include <linux/ipv6.h> 5d6f39601SAlexei Starovoitov #include <linux/bpf.h> 63e689141SToke Høiland-Jørgensen #include <bpf/bpf_helpers.h> 77805fe84SAlexei Starovoitov #include <bpf/bpf_endian.h> 8df8ff353SAndrii Nakryiko #include <bpf/bpf_tracing.h> 9d6f39601SAlexei Starovoitov 10d6f39601SAlexei Starovoitov struct sk_buff { 11d6f39601SAlexei Starovoitov unsigned int len; 12d6f39601SAlexei Starovoitov }; 13d6f39601SAlexei Starovoitov 1453f8dd43SAndrii Nakryiko __u64 test_result = 0; 15ac065870SAndrii Nakryiko SEC("fexit/test_pkt_access") 16ac065870SAndrii Nakryiko int BPF_PROG(test_main, struct sk_buff *skb, int ret) 17d6f39601SAlexei Starovoitov { 18d6f39601SAlexei Starovoitov int len; 19d6f39601SAlexei Starovoitov 20d6f39601SAlexei Starovoitov __builtin_preserve_access_index(({ 21d6f39601SAlexei Starovoitov len = skb->len; 22d6f39601SAlexei Starovoitov })); 23f9a7cf6eSMartin KaFai Lau if (len != 74 || ret != 0) 24d6f39601SAlexei Starovoitov return 0; 25d6f39601SAlexei Starovoitov test_result = 1; 26d6f39601SAlexei Starovoitov return 0; 27d6f39601SAlexei Starovoitov } 28d6f39601SAlexei Starovoitov 2953f8dd43SAndrii Nakryiko __u64 test_result_subprog1 = 0; 30ac065870SAndrii Nakryiko SEC("fexit/test_pkt_access_subprog1") 31ac065870SAndrii Nakryiko int BPF_PROG(test_subprog1, struct sk_buff *skb, int ret) 32d6f39601SAlexei Starovoitov { 33d6f39601SAlexei Starovoitov int len; 34d6f39601SAlexei Starovoitov 35d6f39601SAlexei Starovoitov __builtin_preserve_access_index(({ 36d6f39601SAlexei Starovoitov len = skb->len; 37d6f39601SAlexei Starovoitov })); 38f9a7cf6eSMartin KaFai Lau if (len != 74 || ret != 148) 39d6f39601SAlexei Starovoitov return 0; 40d6f39601SAlexei Starovoitov test_result_subprog1 = 1; 41d6f39601SAlexei Starovoitov return 0; 42d6f39601SAlexei Starovoitov } 43d6f39601SAlexei Starovoitov 44d6f39601SAlexei Starovoitov /* Though test_pkt_access_subprog2() is defined in C as: 45d6f39601SAlexei Starovoitov * static __attribute__ ((noinline)) 46d6f39601SAlexei Starovoitov * int test_pkt_access_subprog2(int val, volatile struct __sk_buff *skb) 47d6f39601SAlexei Starovoitov * { 48d6f39601SAlexei Starovoitov * return skb->len * val; 49d6f39601SAlexei Starovoitov * } 50d6f39601SAlexei Starovoitov * llvm optimizations remove 'int val' argument and generate BPF assembly: 51d6f39601SAlexei Starovoitov * r0 = *(u32 *)(r1 + 0) 52d6f39601SAlexei Starovoitov * w0 <<= 1 53d6f39601SAlexei Starovoitov * exit 54d6f39601SAlexei Starovoitov * In such case the verifier falls back to conservative and 55d6f39601SAlexei Starovoitov * tracing program can access arguments and return value as u64 56d6f39601SAlexei Starovoitov * instead of accurate types. 57d6f39601SAlexei Starovoitov */ 58d6f39601SAlexei Starovoitov struct args_subprog2 { 59f9a7cf6eSMartin KaFai Lau __u64 args[5]; 60f9a7cf6eSMartin KaFai Lau __u64 ret; 61d6f39601SAlexei Starovoitov }; 6253f8dd43SAndrii Nakryiko __u64 test_result_subprog2 = 0; 63d6f39601SAlexei Starovoitov SEC("fexit/test_pkt_access_subprog2") 64d6f39601SAlexei Starovoitov int test_subprog2(struct args_subprog2 *ctx) 65d6f39601SAlexei Starovoitov { 66d6f39601SAlexei Starovoitov struct sk_buff *skb = (void *)ctx->args[0]; 67d6f39601SAlexei Starovoitov __u64 ret; 68d6f39601SAlexei Starovoitov int len; 69d6f39601SAlexei Starovoitov 70d6f39601SAlexei Starovoitov bpf_probe_read_kernel(&len, sizeof(len), 71d6f39601SAlexei Starovoitov __builtin_preserve_access_index(&skb->len)); 72d6f39601SAlexei Starovoitov 73d6f39601SAlexei Starovoitov ret = ctx->ret; 74d6f39601SAlexei Starovoitov /* bpf_prog_load() loads "test_pkt_access.o" with BPF_F_TEST_RND_HI32 75d6f39601SAlexei Starovoitov * which randomizes upper 32 bits after BPF_ALU32 insns. 76d6f39601SAlexei Starovoitov * Hence after 'w0 <<= 1' upper bits of $rax are random. 77d6f39601SAlexei Starovoitov * That is expected and correct. Trim them. 78d6f39601SAlexei Starovoitov */ 79d6f39601SAlexei Starovoitov ret = (__u32) ret; 80d6f39601SAlexei Starovoitov if (len != 74 || ret != 148) 81d6f39601SAlexei Starovoitov return 0; 82d6f39601SAlexei Starovoitov test_result_subprog2 = 1; 83d6f39601SAlexei Starovoitov return 0; 84d6f39601SAlexei Starovoitov } 857608e4dbSAlexei Starovoitov 867608e4dbSAlexei Starovoitov __u64 test_result_subprog3 = 0; 87ac065870SAndrii Nakryiko SEC("fexit/test_pkt_access_subprog3") 88ac065870SAndrii Nakryiko int BPF_PROG(test_subprog3, int val, struct sk_buff *skb, int ret) 897608e4dbSAlexei Starovoitov { 907608e4dbSAlexei Starovoitov int len; 917608e4dbSAlexei Starovoitov 927608e4dbSAlexei Starovoitov __builtin_preserve_access_index(({ 937608e4dbSAlexei Starovoitov len = skb->len; 947608e4dbSAlexei Starovoitov })); 957608e4dbSAlexei Starovoitov if (len != 74 || ret != 74 * val || val != 3) 967608e4dbSAlexei Starovoitov return 0; 977608e4dbSAlexei Starovoitov test_result_subprog3 = 1; 987608e4dbSAlexei Starovoitov return 0; 997608e4dbSAlexei Starovoitov } 1007805fe84SAlexei Starovoitov 1017805fe84SAlexei Starovoitov __u64 test_get_skb_len = 0; 1027805fe84SAlexei Starovoitov SEC("freplace/get_skb_len") 1037805fe84SAlexei Starovoitov int new_get_skb_len(struct __sk_buff *skb) 1047805fe84SAlexei Starovoitov { 1057805fe84SAlexei Starovoitov int len = skb->len; 1067805fe84SAlexei Starovoitov 1077805fe84SAlexei Starovoitov if (len != 74) 1087805fe84SAlexei Starovoitov return 0; 1097805fe84SAlexei Starovoitov test_get_skb_len = 1; 1107805fe84SAlexei Starovoitov return 74; /* original get_skb_len() returns skb->len */ 1117805fe84SAlexei Starovoitov } 1127805fe84SAlexei Starovoitov 1137805fe84SAlexei Starovoitov __u64 test_get_skb_ifindex = 0; 1147805fe84SAlexei Starovoitov SEC("freplace/get_skb_ifindex") 1157805fe84SAlexei Starovoitov int new_get_skb_ifindex(int val, struct __sk_buff *skb, int var) 1167805fe84SAlexei Starovoitov { 1177805fe84SAlexei Starovoitov void *data_end = (void *)(long)skb->data_end; 1187805fe84SAlexei Starovoitov void *data = (void *)(long)skb->data; 1197805fe84SAlexei Starovoitov struct ipv6hdr ip6, *ip6p; 1207805fe84SAlexei Starovoitov int ifindex = skb->ifindex; 1217805fe84SAlexei Starovoitov __u32 eth_proto; 1227805fe84SAlexei Starovoitov __u32 nh_off; 1237805fe84SAlexei Starovoitov 1247805fe84SAlexei Starovoitov /* check that BPF extension can read packet via direct packet access */ 1257805fe84SAlexei Starovoitov if (data + 14 + sizeof(ip6) > data_end) 1267805fe84SAlexei Starovoitov return 0; 1277805fe84SAlexei Starovoitov ip6p = data + 14; 1287805fe84SAlexei Starovoitov 1297805fe84SAlexei Starovoitov if (ip6p->nexthdr != 6 || ip6p->payload_len != __bpf_constant_htons(123)) 1307805fe84SAlexei Starovoitov return 0; 1317805fe84SAlexei Starovoitov 1327805fe84SAlexei Starovoitov /* check that legacy packet access helper works too */ 1337805fe84SAlexei Starovoitov if (bpf_skb_load_bytes(skb, 14, &ip6, sizeof(ip6)) < 0) 1347805fe84SAlexei Starovoitov return 0; 1357805fe84SAlexei Starovoitov ip6p = &ip6; 1367805fe84SAlexei Starovoitov if (ip6p->nexthdr != 6 || ip6p->payload_len != __bpf_constant_htons(123)) 1377805fe84SAlexei Starovoitov return 0; 1387805fe84SAlexei Starovoitov 1397805fe84SAlexei Starovoitov if (ifindex != 1 || val != 3 || var != 1) 1407805fe84SAlexei Starovoitov return 0; 1417805fe84SAlexei Starovoitov test_get_skb_ifindex = 1; 1427805fe84SAlexei Starovoitov return 3; /* original get_skb_ifindex() returns val * ifindex * var */ 1437805fe84SAlexei Starovoitov } 1447805fe84SAlexei Starovoitov 1457805fe84SAlexei Starovoitov volatile __u64 test_get_constant = 0; 1467805fe84SAlexei Starovoitov SEC("freplace/get_constant") 1477805fe84SAlexei Starovoitov int new_get_constant(long val) 1487805fe84SAlexei Starovoitov { 1497805fe84SAlexei Starovoitov if (val != 123) 1507805fe84SAlexei Starovoitov return 0; 1517805fe84SAlexei Starovoitov test_get_constant = 1; 1527805fe84SAlexei Starovoitov return test_get_constant; /* original get_constant() returns val - 122 */ 1537805fe84SAlexei Starovoitov } 154d6f39601SAlexei Starovoitov char _license[] SEC("license") = "GPL"; 155