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