Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* Copyright (c) 2017 Facebook
0003  */
0004 #include <stddef.h>
0005 #include <string.h>
0006 #include <linux/bpf.h>
0007 #include <linux/if_ether.h>
0008 #include <linux/if_packet.h>
0009 #include <linux/ip.h>
0010 #include <linux/ipv6.h>
0011 #include <linux/in.h>
0012 #include <linux/tcp.h>
0013 #include <linux/pkt_cls.h>
0014 #include <bpf/bpf_helpers.h>
0015 #include <bpf/bpf_endian.h>
0016 
0017 /* llvm will optimize both subprograms into exactly the same BPF assembly
0018  *
0019  * Disassembly of section .text:
0020  *
0021  * 0000000000000000 test_pkt_access_subprog1:
0022  * ;    return skb->len * 2;
0023  *        0:    61 10 00 00 00 00 00 00 r0 = *(u32 *)(r1 + 0)
0024  *        1:    64 00 00 00 01 00 00 00 w0 <<= 1
0025  *        2:    95 00 00 00 00 00 00 00 exit
0026  *
0027  * 0000000000000018 test_pkt_access_subprog2:
0028  * ;    return skb->len * val;
0029  *        3:    61 10 00 00 00 00 00 00 r0 = *(u32 *)(r1 + 0)
0030  *        4:    64 00 00 00 01 00 00 00 w0 <<= 1
0031  *        5:    95 00 00 00 00 00 00 00 exit
0032  *
0033  * Which makes it an interesting test for BTF-enabled verifier.
0034  */
0035 static __attribute__ ((noinline))
0036 int test_pkt_access_subprog1(volatile struct __sk_buff *skb)
0037 {
0038     return skb->len * 2;
0039 }
0040 
0041 static __attribute__ ((noinline))
0042 int test_pkt_access_subprog2(int val, volatile struct __sk_buff *skb)
0043 {
0044     return skb->len * val;
0045 }
0046 
0047 #define MAX_STACK (512 - 2 * 32)
0048 
0049 __attribute__ ((noinline))
0050 int get_skb_len(struct __sk_buff *skb)
0051 {
0052     volatile char buf[MAX_STACK] = {};
0053 
0054     return skb->len;
0055 }
0056 
0057 __attribute__ ((noinline))
0058 int get_constant(long val)
0059 {
0060     return val - 122;
0061 }
0062 
0063 int get_skb_ifindex(int, struct __sk_buff *skb, int);
0064 
0065 __attribute__ ((noinline))
0066 int test_pkt_access_subprog3(int val, struct __sk_buff *skb)
0067 {
0068     return get_skb_len(skb) * get_skb_ifindex(val, skb, get_constant(123));
0069 }
0070 
0071 __attribute__ ((noinline))
0072 int get_skb_ifindex(int val, struct __sk_buff *skb, int var)
0073 {
0074     volatile char buf[MAX_STACK] = {};
0075 
0076     return skb->ifindex * val * var;
0077 }
0078 
0079 __attribute__ ((noinline))
0080 int test_pkt_write_access_subprog(struct __sk_buff *skb, __u32 off)
0081 {
0082     void *data = (void *)(long)skb->data;
0083     void *data_end = (void *)(long)skb->data_end;
0084     struct tcphdr *tcp = NULL;
0085 
0086     if (off > sizeof(struct ethhdr) + sizeof(struct ipv6hdr))
0087         return -1;
0088 
0089     tcp = data + off;
0090     if (tcp + 1 > data_end)
0091         return -1;
0092     /* make modification to the packet data */
0093     tcp->check++;
0094     return 0;
0095 }
0096 
0097 SEC("tc")
0098 int test_pkt_access(struct __sk_buff *skb)
0099 {
0100     void *data_end = (void *)(long)skb->data_end;
0101     void *data = (void *)(long)skb->data;
0102     struct ethhdr *eth = (struct ethhdr *)(data);
0103     struct tcphdr *tcp = NULL;
0104     __u8 proto = 255;
0105     __u64 ihl_len;
0106 
0107     if (eth + 1 > data_end)
0108         return TC_ACT_SHOT;
0109 
0110     if (eth->h_proto == bpf_htons(ETH_P_IP)) {
0111         struct iphdr *iph = (struct iphdr *)(eth + 1);
0112 
0113         if (iph + 1 > data_end)
0114             return TC_ACT_SHOT;
0115         ihl_len = iph->ihl * 4;
0116         proto = iph->protocol;
0117         tcp = (struct tcphdr *)((void *)(iph) + ihl_len);
0118     } else if (eth->h_proto == bpf_htons(ETH_P_IPV6)) {
0119         struct ipv6hdr *ip6h = (struct ipv6hdr *)(eth + 1);
0120 
0121         if (ip6h + 1 > data_end)
0122             return TC_ACT_SHOT;
0123         ihl_len = sizeof(*ip6h);
0124         proto = ip6h->nexthdr;
0125         tcp = (struct tcphdr *)((void *)(ip6h) + ihl_len);
0126     }
0127 
0128     if (test_pkt_access_subprog1(skb) != skb->len * 2)
0129         return TC_ACT_SHOT;
0130     if (test_pkt_access_subprog2(2, skb) != skb->len * 2)
0131         return TC_ACT_SHOT;
0132     if (test_pkt_access_subprog3(3, skb) != skb->len * 3 * skb->ifindex)
0133         return TC_ACT_SHOT;
0134     if (tcp) {
0135         if (test_pkt_write_access_subprog(skb, (void *)tcp - data))
0136             return TC_ACT_SHOT;
0137         if (((void *)(tcp) + 20) > data_end || proto != 6)
0138             return TC_ACT_SHOT;
0139         barrier(); /* to force ordering of checks */
0140         if (((void *)(tcp) + 18) > data_end)
0141             return TC_ACT_SHOT;
0142         if (tcp->urg_ptr == 123)
0143             return TC_ACT_OK;
0144     }
0145 
0146     return TC_ACT_UNSPEC;
0147 }