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, nh_off: sizeof(*eth), data_end, eth_proto: eth->h_proto, ipv4: &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 | |