1 /* SPDX-License-Identifier: GPL-2.0 */ 2 // Copyright (c) 2018 Covalent IO, Inc. http://covalent.io 3 4 #include <stddef.h> 5 #include <stdbool.h> 6 #include <string.h> 7 #include <linux/bpf.h> 8 #include <linux/if_ether.h> 9 #include <linux/in.h> 10 #include <linux/ip.h> 11 #include <linux/ipv6.h> 12 #include <linux/pkt_cls.h> 13 #include <linux/tcp.h> 14 #include <sys/socket.h> 15 #include <bpf/bpf_helpers.h> 16 #include <bpf/bpf_endian.h> 17 18 char _license[] SEC("license") = "GPL"; 19 20 /* Fill 'tuple' with L3 info, and attempt to find L4. On fail, return NULL. */ 21 static struct bpf_sock_tuple *get_tuple(void *data, __u64 nh_off, 22 void *data_end, __u16 eth_proto, 23 bool *ipv4) 24 { 25 struct bpf_sock_tuple *result; 26 __u64 ihl_len = 0; 27 __u8 proto = 0; 28 29 if (eth_proto == bpf_htons(ETH_P_IP)) { 30 struct iphdr *iph = (struct iphdr *)(data + nh_off); 31 32 if (iph + 1 > data_end) 33 return NULL; 34 ihl_len = iph->ihl * 4; 35 proto = iph->protocol; 36 *ipv4 = true; 37 result = (struct bpf_sock_tuple *)&iph->saddr; 38 } else if (eth_proto == bpf_htons(ETH_P_IPV6)) { 39 struct ipv6hdr *ip6h = (struct ipv6hdr *)(data + nh_off); 40 41 if (ip6h + 1 > data_end) 42 return NULL; 43 ihl_len = sizeof(*ip6h); 44 proto = ip6h->nexthdr; 45 *ipv4 = true; 46 result = (struct bpf_sock_tuple *)&ip6h->saddr; 47 } 48 49 if (data + nh_off + ihl_len > data_end || proto != IPPROTO_TCP) 50 return NULL; 51 52 return result; 53 } 54 55 SEC("?tc") 56 int sk_lookup_success(struct __sk_buff *skb) 57 { 58 void *data_end = (void *)(long)skb->data_end; 59 void *data = (void *)(long)skb->data; 60 struct ethhdr *eth = (struct ethhdr *)(data); 61 struct bpf_sock_tuple *tuple; 62 struct bpf_sock *sk; 63 size_t tuple_len; 64 bool ipv4; 65 66 if (eth + 1 > data_end) 67 return TC_ACT_SHOT; 68 69 tuple = get_tuple(data, sizeof(*eth), data_end, eth->h_proto, &ipv4); 70 if (!tuple || tuple + sizeof *tuple > data_end) 71 return TC_ACT_SHOT; 72 73 tuple_len = ipv4 ? sizeof(tuple->ipv4) : sizeof(tuple->ipv6); 74 sk = bpf_sk_lookup_tcp(skb, tuple, tuple_len, BPF_F_CURRENT_NETNS, 0); 75 bpf_printk("sk=%d\n", sk ? 1 : 0); 76 if (sk) 77 bpf_sk_release(sk); 78 return sk ? TC_ACT_OK : TC_ACT_UNSPEC; 79 } 80 81 SEC("?tc") 82 int sk_lookup_success_simple(struct __sk_buff *skb) 83 { 84 struct bpf_sock_tuple tuple = {}; 85 struct bpf_sock *sk; 86 87 sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); 88 if (sk) 89 bpf_sk_release(sk); 90 return 0; 91 } 92 93 SEC("?tc") 94 int err_use_after_free(struct __sk_buff *skb) 95 { 96 struct bpf_sock_tuple tuple = {}; 97 struct bpf_sock *sk; 98 __u32 family = 0; 99 100 sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); 101 if (sk) { 102 bpf_sk_release(sk); 103 family = sk->family; 104 } 105 return family; 106 } 107 108 SEC("?tc") 109 int err_modify_sk_pointer(struct __sk_buff *skb) 110 { 111 struct bpf_sock_tuple tuple = {}; 112 struct bpf_sock *sk; 113 114 sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); 115 if (sk) { 116 sk += 1; 117 bpf_sk_release(sk); 118 } 119 return 0; 120 } 121 122 SEC("?tc") 123 int err_modify_sk_or_null_pointer(struct __sk_buff *skb) 124 { 125 struct bpf_sock_tuple tuple = {}; 126 struct bpf_sock *sk; 127 128 sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); 129 sk += 1; 130 if (sk) 131 bpf_sk_release(sk); 132 return 0; 133 } 134 135 SEC("?tc") 136 int err_no_release(struct __sk_buff *skb) 137 { 138 struct bpf_sock_tuple tuple = {}; 139 140 bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); 141 return 0; 142 } 143 144 SEC("?tc") 145 int err_release_twice(struct __sk_buff *skb) 146 { 147 struct bpf_sock_tuple tuple = {}; 148 struct bpf_sock *sk; 149 150 sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); 151 bpf_sk_release(sk); 152 bpf_sk_release(sk); 153 return 0; 154 } 155 156 SEC("?tc") 157 int err_release_unchecked(struct __sk_buff *skb) 158 { 159 struct bpf_sock_tuple tuple = {}; 160 struct bpf_sock *sk; 161 162 sk = bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); 163 bpf_sk_release(sk); 164 return 0; 165 } 166 167 void lookup_no_release(struct __sk_buff *skb) 168 { 169 struct bpf_sock_tuple tuple = {}; 170 bpf_sk_lookup_tcp(skb, &tuple, sizeof(tuple), BPF_F_CURRENT_NETNS, 0); 171 } 172 173 SEC("?tc") 174 int err_no_release_subcall(struct __sk_buff *skb) 175 { 176 lookup_no_release(skb); 177 return 0; 178 } 179