Blame view
net/core/filter.c
22.7 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* * Linux Socket Filter - Kernel level socket filtering * * Author: * Jay Schulist <jschlst@samba.org> * * Based on the design of: * - The Berkeley Packet Filter * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Andi Kleen - Fix a few bad bugs and races. |
936998630 [NET]: More instr... |
16 |
* Kris Katterjohn - Added many additional checks in sk_chk_filter() |
1da177e4c Linux-2.6.12-rc2 |
17 18 19 20 |
*/ #include <linux/module.h> #include <linux/types.h> |
1da177e4c Linux-2.6.12-rc2 |
21 22 23 24 25 26 27 |
#include <linux/mm.h> #include <linux/fcntl.h> #include <linux/socket.h> #include <linux/in.h> #include <linux/inet.h> #include <linux/netdevice.h> #include <linux/if_packet.h> |
5a0e3ad6a include cleanup: ... |
28 |
#include <linux/gfp.h> |
1da177e4c Linux-2.6.12-rc2 |
29 30 |
#include <net/ip.h> #include <net/protocol.h> |
4738c1db1 [SKFILTER]: Add S... |
31 |
#include <net/netlink.h> |
1da177e4c Linux-2.6.12-rc2 |
32 33 34 35 |
#include <linux/skbuff.h> #include <net/sock.h> #include <linux/errno.h> #include <linux/timer.h> |
1da177e4c Linux-2.6.12-rc2 |
36 |
#include <asm/uaccess.h> |
40daafc80 unaligned access ... |
37 |
#include <asm/unaligned.h> |
1da177e4c Linux-2.6.12-rc2 |
38 |
#include <linux/filter.h> |
c26aed40f filter: use recip... |
39 |
#include <linux/reciprocal_div.h> |
86e4ca66e bug.h: Move ratel... |
40 |
#include <linux/ratelimit.h> |
46b325c7e sk_run_filter: ad... |
41 |
#include <linux/seccomp.h> |
f3335031b net: filter: add ... |
42 |
#include <linux/if_vlan.h> |
1da177e4c Linux-2.6.12-rc2 |
43 |
|
f03fb3f45 bpf jit: Make the... |
44 45 46 47 48 |
/* No hurry in this branch * * Exported for the bpf jit load helper. */ void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, int k, unsigned int size) |
1da177e4c Linux-2.6.12-rc2 |
49 50 51 52 |
{ u8 *ptr = NULL; if (k >= SKF_NET_OFF) |
d56f90a7c [SK_BUFF]: Introd... |
53 |
ptr = skb_network_header(skb) + k - SKF_NET_OFF; |
1da177e4c Linux-2.6.12-rc2 |
54 |
else if (k >= SKF_LL_OFF) |
98e399f82 [SK_BUFF]: Introd... |
55 |
ptr = skb_mac_header(skb) + k - SKF_LL_OFF; |
1da177e4c Linux-2.6.12-rc2 |
56 |
|
4bc65dd8d filter: use size ... |
57 |
if (ptr >= skb->head && ptr + size <= skb_tail_pointer(skb)) |
1da177e4c Linux-2.6.12-rc2 |
58 59 60 |
return ptr; return NULL; } |
62ab08121 filter: constify ... |
61 |
static inline void *load_pointer(const struct sk_buff *skb, int k, |
4ec93edb1 [NET] CORE: Fix w... |
62 |
unsigned int size, void *buffer) |
0b05b2a49 [NET]: Consolidat... |
63 64 65 |
{ if (k >= 0) return skb_header_pointer(skb, k, size, buffer); |
f03fb3f45 bpf jit: Make the... |
66 |
return bpf_internal_load_pointer_neg_helper(skb, k, size); |
0b05b2a49 [NET]: Consolidat... |
67 |
} |
1da177e4c Linux-2.6.12-rc2 |
68 |
/** |
43db6d65e socket: sk_filter... |
69 70 71 |
* sk_filter - run a packet through a socket filter * @sk: sock associated with &sk_buff * @skb: buffer to filter |
43db6d65e socket: sk_filter... |
72 73 74 75 76 77 78 79 80 81 82 83 |
* * Run the filter code and then cut skb->data to correct size returned by * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller * than pkt_len we keep whole skb->data. This is the socket level * wrapper to sk_run_filter. It returns 0 if the packet should * be accepted or -EPERM if the packet should be tossed. * */ int sk_filter(struct sock *sk, struct sk_buff *skb) { int err; struct sk_filter *filter; |
c93bdd0e0 netvm: allow skb ... |
84 85 86 87 88 89 90 |
/* * If the skb was allocated from pfmemalloc reserves, only * allow SOCK_MEMALLOC sockets to use it as this socket is * helping free memory */ if (skb_pfmemalloc(skb) && !sock_flag(sk, SOCK_MEMALLOC)) return -ENOMEM; |
43db6d65e socket: sk_filter... |
91 92 93 |
err = security_sock_rcv_skb(sk, skb); if (err) return err; |
80f8f1027 net: filter: dont... |
94 95 |
rcu_read_lock(); filter = rcu_dereference(sk->sk_filter); |
43db6d65e socket: sk_filter... |
96 |
if (filter) { |
0a14842f5 net: filter: Just... |
97 |
unsigned int pkt_len = SK_RUN_FILTER(filter, skb); |
0d7da9ddd net: add __rcu an... |
98 |
|
43db6d65e socket: sk_filter... |
99 100 |
err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; } |
80f8f1027 net: filter: dont... |
101 |
rcu_read_unlock(); |
43db6d65e socket: sk_filter... |
102 103 104 105 106 107 |
return err; } EXPORT_SYMBOL(sk_filter); /** |
2966b66c2 [NET]: more white... |
108 |
* sk_run_filter - run a filter on a socket |
1da177e4c Linux-2.6.12-rc2 |
109 |
* @skb: buffer to run the filter on |
697d0e338 net: fix kernel-d... |
110 |
* @fentry: filter to apply |
1da177e4c Linux-2.6.12-rc2 |
111 112 |
* * Decode and apply filter instructions to the skb->data. |
93aaae2e0 filter: optimize ... |
113 114 115 116 117 |
* Return length to keep, 0 for none. @skb is the data we are * filtering, @filter is the array of filter instructions. * Because all jumps are guaranteed to be before last instruction, * and last instruction guaranteed to be a RET, we dont need to check * flen. (We used to pass to this function the length of filter) |
1da177e4c Linux-2.6.12-rc2 |
118 |
*/ |
62ab08121 filter: constify ... |
119 120 |
unsigned int sk_run_filter(const struct sk_buff *skb, const struct sock_filter *fentry) |
1da177e4c Linux-2.6.12-rc2 |
121 |
{ |
0b05b2a49 [NET]: Consolidat... |
122 |
void *ptr; |
2966b66c2 [NET]: more white... |
123 124 |
u32 A = 0; /* Accumulator */ u32 X = 0; /* Index Register */ |
1da177e4c Linux-2.6.12-rc2 |
125 |
u32 mem[BPF_MEMWORDS]; /* Scratch Memory Store */ |
0b05b2a49 [NET]: Consolidat... |
126 |
u32 tmp; |
1da177e4c Linux-2.6.12-rc2 |
127 |
int k; |
1da177e4c Linux-2.6.12-rc2 |
128 129 130 131 |
/* * Process array of filter instructions. */ |
93aaae2e0 filter: optimize ... |
132 133 134 135 136 137 |
for (;; fentry++) { #if defined(CONFIG_X86_32) #define K (fentry->k) #else const u32 K = fentry->k; #endif |
4ec93edb1 [NET] CORE: Fix w... |
138 |
|
1da177e4c Linux-2.6.12-rc2 |
139 |
switch (fentry->code) { |
01f2f3f6e net: optimize Ber... |
140 |
case BPF_S_ALU_ADD_X: |
1da177e4c Linux-2.6.12-rc2 |
141 142 |
A += X; continue; |
01f2f3f6e net: optimize Ber... |
143 |
case BPF_S_ALU_ADD_K: |
93aaae2e0 filter: optimize ... |
144 |
A += K; |
1da177e4c Linux-2.6.12-rc2 |
145 |
continue; |
01f2f3f6e net: optimize Ber... |
146 |
case BPF_S_ALU_SUB_X: |
1da177e4c Linux-2.6.12-rc2 |
147 148 |
A -= X; continue; |
01f2f3f6e net: optimize Ber... |
149 |
case BPF_S_ALU_SUB_K: |
93aaae2e0 filter: optimize ... |
150 |
A -= K; |
1da177e4c Linux-2.6.12-rc2 |
151 |
continue; |
01f2f3f6e net: optimize Ber... |
152 |
case BPF_S_ALU_MUL_X: |
1da177e4c Linux-2.6.12-rc2 |
153 154 |
A *= X; continue; |
01f2f3f6e net: optimize Ber... |
155 |
case BPF_S_ALU_MUL_K: |
93aaae2e0 filter: optimize ... |
156 |
A *= K; |
1da177e4c Linux-2.6.12-rc2 |
157 |
continue; |
01f2f3f6e net: optimize Ber... |
158 |
case BPF_S_ALU_DIV_X: |
1da177e4c Linux-2.6.12-rc2 |
159 160 161 162 |
if (X == 0) return 0; A /= X; continue; |
01f2f3f6e net: optimize Ber... |
163 |
case BPF_S_ALU_DIV_K: |
c26aed40f filter: use recip... |
164 |
A = reciprocal_divide(A, K); |
1da177e4c Linux-2.6.12-rc2 |
165 |
continue; |
b6069a957 filter: add MOD o... |
166 167 168 169 170 171 172 173 |
case BPF_S_ALU_MOD_X: if (X == 0) return 0; A %= X; continue; case BPF_S_ALU_MOD_K: A %= K; continue; |
01f2f3f6e net: optimize Ber... |
174 |
case BPF_S_ALU_AND_X: |
1da177e4c Linux-2.6.12-rc2 |
175 176 |
A &= X; continue; |
01f2f3f6e net: optimize Ber... |
177 |
case BPF_S_ALU_AND_K: |
93aaae2e0 filter: optimize ... |
178 |
A &= K; |
1da177e4c Linux-2.6.12-rc2 |
179 |
continue; |
01f2f3f6e net: optimize Ber... |
180 |
case BPF_S_ALU_OR_X: |
1da177e4c Linux-2.6.12-rc2 |
181 182 |
A |= X; continue; |
01f2f3f6e net: optimize Ber... |
183 |
case BPF_S_ALU_OR_K: |
93aaae2e0 filter: optimize ... |
184 |
A |= K; |
1da177e4c Linux-2.6.12-rc2 |
185 |
continue; |
9e49e8895 filter: add XOR i... |
186 187 188 189 190 191 192 |
case BPF_S_ANC_ALU_XOR_X: case BPF_S_ALU_XOR_X: A ^= X; continue; case BPF_S_ALU_XOR_K: A ^= K; continue; |
01f2f3f6e net: optimize Ber... |
193 |
case BPF_S_ALU_LSH_X: |
1da177e4c Linux-2.6.12-rc2 |
194 195 |
A <<= X; continue; |
01f2f3f6e net: optimize Ber... |
196 |
case BPF_S_ALU_LSH_K: |
93aaae2e0 filter: optimize ... |
197 |
A <<= K; |
1da177e4c Linux-2.6.12-rc2 |
198 |
continue; |
01f2f3f6e net: optimize Ber... |
199 |
case BPF_S_ALU_RSH_X: |
1da177e4c Linux-2.6.12-rc2 |
200 201 |
A >>= X; continue; |
01f2f3f6e net: optimize Ber... |
202 |
case BPF_S_ALU_RSH_K: |
93aaae2e0 filter: optimize ... |
203 |
A >>= K; |
1da177e4c Linux-2.6.12-rc2 |
204 |
continue; |
01f2f3f6e net: optimize Ber... |
205 |
case BPF_S_ALU_NEG: |
1da177e4c Linux-2.6.12-rc2 |
206 207 |
A = -A; continue; |
01f2f3f6e net: optimize Ber... |
208 |
case BPF_S_JMP_JA: |
93aaae2e0 filter: optimize ... |
209 |
fentry += K; |
1da177e4c Linux-2.6.12-rc2 |
210 |
continue; |
01f2f3f6e net: optimize Ber... |
211 |
case BPF_S_JMP_JGT_K: |
93aaae2e0 filter: optimize ... |
212 |
fentry += (A > K) ? fentry->jt : fentry->jf; |
1da177e4c Linux-2.6.12-rc2 |
213 |
continue; |
01f2f3f6e net: optimize Ber... |
214 |
case BPF_S_JMP_JGE_K: |
93aaae2e0 filter: optimize ... |
215 |
fentry += (A >= K) ? fentry->jt : fentry->jf; |
1da177e4c Linux-2.6.12-rc2 |
216 |
continue; |
01f2f3f6e net: optimize Ber... |
217 |
case BPF_S_JMP_JEQ_K: |
93aaae2e0 filter: optimize ... |
218 |
fentry += (A == K) ? fentry->jt : fentry->jf; |
1da177e4c Linux-2.6.12-rc2 |
219 |
continue; |
01f2f3f6e net: optimize Ber... |
220 |
case BPF_S_JMP_JSET_K: |
93aaae2e0 filter: optimize ... |
221 |
fentry += (A & K) ? fentry->jt : fentry->jf; |
1da177e4c Linux-2.6.12-rc2 |
222 |
continue; |
01f2f3f6e net: optimize Ber... |
223 |
case BPF_S_JMP_JGT_X: |
93aaae2e0 filter: optimize ... |
224 |
fentry += (A > X) ? fentry->jt : fentry->jf; |
1da177e4c Linux-2.6.12-rc2 |
225 |
continue; |
01f2f3f6e net: optimize Ber... |
226 |
case BPF_S_JMP_JGE_X: |
93aaae2e0 filter: optimize ... |
227 |
fentry += (A >= X) ? fentry->jt : fentry->jf; |
1da177e4c Linux-2.6.12-rc2 |
228 |
continue; |
01f2f3f6e net: optimize Ber... |
229 |
case BPF_S_JMP_JEQ_X: |
93aaae2e0 filter: optimize ... |
230 |
fentry += (A == X) ? fentry->jt : fentry->jf; |
1da177e4c Linux-2.6.12-rc2 |
231 |
continue; |
01f2f3f6e net: optimize Ber... |
232 |
case BPF_S_JMP_JSET_X: |
93aaae2e0 filter: optimize ... |
233 |
fentry += (A & X) ? fentry->jt : fentry->jf; |
1da177e4c Linux-2.6.12-rc2 |
234 |
continue; |
01f2f3f6e net: optimize Ber... |
235 |
case BPF_S_LD_W_ABS: |
93aaae2e0 filter: optimize ... |
236 |
k = K; |
e35bedf36 [NET]: Fix whites... |
237 |
load_w: |
0b05b2a49 [NET]: Consolidat... |
238 239 |
ptr = load_pointer(skb, k, 4, &tmp); if (ptr != NULL) { |
d3e2ce3bc net: use get/put_... |
240 |
A = get_unaligned_be32(ptr); |
0b05b2a49 [NET]: Consolidat... |
241 |
continue; |
1da177e4c Linux-2.6.12-rc2 |
242 |
} |
12b16dadb filter: optimize ... |
243 |
return 0; |
01f2f3f6e net: optimize Ber... |
244 |
case BPF_S_LD_H_ABS: |
93aaae2e0 filter: optimize ... |
245 |
k = K; |
e35bedf36 [NET]: Fix whites... |
246 |
load_h: |
0b05b2a49 [NET]: Consolidat... |
247 248 |
ptr = load_pointer(skb, k, 2, &tmp); if (ptr != NULL) { |
d3e2ce3bc net: use get/put_... |
249 |
A = get_unaligned_be16(ptr); |
0b05b2a49 [NET]: Consolidat... |
250 |
continue; |
1da177e4c Linux-2.6.12-rc2 |
251 |
} |
12b16dadb filter: optimize ... |
252 |
return 0; |
01f2f3f6e net: optimize Ber... |
253 |
case BPF_S_LD_B_ABS: |
93aaae2e0 filter: optimize ... |
254 |
k = K; |
1da177e4c Linux-2.6.12-rc2 |
255 |
load_b: |
0b05b2a49 [NET]: Consolidat... |
256 257 258 259 |
ptr = load_pointer(skb, k, 1, &tmp); if (ptr != NULL) { A = *(u8 *)ptr; continue; |
1da177e4c Linux-2.6.12-rc2 |
260 |
} |
12b16dadb filter: optimize ... |
261 |
return 0; |
01f2f3f6e net: optimize Ber... |
262 |
case BPF_S_LD_W_LEN: |
3154e540e [NET]: net/core/f... |
263 |
A = skb->len; |
1da177e4c Linux-2.6.12-rc2 |
264 |
continue; |
01f2f3f6e net: optimize Ber... |
265 |
case BPF_S_LDX_W_LEN: |
3154e540e [NET]: net/core/f... |
266 |
X = skb->len; |
1da177e4c Linux-2.6.12-rc2 |
267 |
continue; |
01f2f3f6e net: optimize Ber... |
268 |
case BPF_S_LD_W_IND: |
93aaae2e0 filter: optimize ... |
269 |
k = X + K; |
1da177e4c Linux-2.6.12-rc2 |
270 |
goto load_w; |
01f2f3f6e net: optimize Ber... |
271 |
case BPF_S_LD_H_IND: |
93aaae2e0 filter: optimize ... |
272 |
k = X + K; |
1da177e4c Linux-2.6.12-rc2 |
273 |
goto load_h; |
01f2f3f6e net: optimize Ber... |
274 |
case BPF_S_LD_B_IND: |
93aaae2e0 filter: optimize ... |
275 |
k = X + K; |
1da177e4c Linux-2.6.12-rc2 |
276 |
goto load_b; |
01f2f3f6e net: optimize Ber... |
277 |
case BPF_S_LDX_B_MSH: |
93aaae2e0 filter: optimize ... |
278 |
ptr = load_pointer(skb, K, 1, &tmp); |
0b05b2a49 [NET]: Consolidat... |
279 280 281 282 283 |
if (ptr != NULL) { X = (*(u8 *)ptr & 0xf) << 2; continue; } return 0; |
01f2f3f6e net: optimize Ber... |
284 |
case BPF_S_LD_IMM: |
93aaae2e0 filter: optimize ... |
285 |
A = K; |
1da177e4c Linux-2.6.12-rc2 |
286 |
continue; |
01f2f3f6e net: optimize Ber... |
287 |
case BPF_S_LDX_IMM: |
93aaae2e0 filter: optimize ... |
288 |
X = K; |
1da177e4c Linux-2.6.12-rc2 |
289 |
continue; |
01f2f3f6e net: optimize Ber... |
290 |
case BPF_S_LD_MEM: |
2d5311e4e filter: add a sec... |
291 |
A = mem[K]; |
1da177e4c Linux-2.6.12-rc2 |
292 |
continue; |
01f2f3f6e net: optimize Ber... |
293 |
case BPF_S_LDX_MEM: |
2d5311e4e filter: add a sec... |
294 |
X = mem[K]; |
1da177e4c Linux-2.6.12-rc2 |
295 |
continue; |
01f2f3f6e net: optimize Ber... |
296 |
case BPF_S_MISC_TAX: |
1da177e4c Linux-2.6.12-rc2 |
297 298 |
X = A; continue; |
01f2f3f6e net: optimize Ber... |
299 |
case BPF_S_MISC_TXA: |
1da177e4c Linux-2.6.12-rc2 |
300 301 |
A = X; continue; |
01f2f3f6e net: optimize Ber... |
302 |
case BPF_S_RET_K: |
93aaae2e0 filter: optimize ... |
303 |
return K; |
01f2f3f6e net: optimize Ber... |
304 |
case BPF_S_RET_A: |
4bad4dc91 [NET]: Change sk_... |
305 |
return A; |
01f2f3f6e net: optimize Ber... |
306 |
case BPF_S_ST: |
93aaae2e0 filter: optimize ... |
307 |
mem[K] = A; |
1da177e4c Linux-2.6.12-rc2 |
308 |
continue; |
01f2f3f6e net: optimize Ber... |
309 |
case BPF_S_STX: |
93aaae2e0 filter: optimize ... |
310 |
mem[K] = X; |
1da177e4c Linux-2.6.12-rc2 |
311 |
continue; |
12b16dadb filter: optimize ... |
312 |
case BPF_S_ANC_PROTOCOL: |
252e33467 [NET] net/core: A... |
313 |
A = ntohs(skb->protocol); |
1da177e4c Linux-2.6.12-rc2 |
314 |
continue; |
12b16dadb filter: optimize ... |
315 |
case BPF_S_ANC_PKTTYPE: |
1da177e4c Linux-2.6.12-rc2 |
316 317 |
A = skb->pkt_type; continue; |
12b16dadb filter: optimize ... |
318 |
case BPF_S_ANC_IFINDEX: |
40eaf9627 net: Socket filte... |
319 320 |
if (!skb->dev) return 0; |
1da177e4c Linux-2.6.12-rc2 |
321 322 |
A = skb->dev->ifindex; continue; |
12b16dadb filter: optimize ... |
323 |
case BPF_S_ANC_MARK: |
7e75f93ed pkt_sched: ingres... |
324 325 |
A = skb->mark; continue; |
12b16dadb filter: optimize ... |
326 |
case BPF_S_ANC_QUEUE: |
d19742fb1 filter: Add SKF_A... |
327 328 |
A = skb->queue_mapping; continue; |
12b16dadb filter: optimize ... |
329 |
case BPF_S_ANC_HATYPE: |
40eaf9627 net: Socket filte... |
330 331 332 333 |
if (!skb->dev) return 0; A = skb->dev->type; continue; |
12b16dadb filter: optimize ... |
334 |
case BPF_S_ANC_RXHASH: |
da2033c28 filter: add SKF_A... |
335 336 |
A = skb->rxhash; continue; |
12b16dadb filter: optimize ... |
337 |
case BPF_S_ANC_CPU: |
da2033c28 filter: add SKF_A... |
338 339 |
A = raw_smp_processor_id(); continue; |
f3335031b net: filter: add ... |
340 341 342 343 344 345 |
case BPF_S_ANC_VLAN_TAG: A = vlan_tx_tag_get(skb); continue; case BPF_S_ANC_VLAN_TAG_PRESENT: A = !!vlan_tx_tag_present(skb); continue; |
3e5289d5e filter: add ANC_P... |
346 347 348 |
case BPF_S_ANC_PAY_OFFSET: A = __skb_get_poff(skb); continue; |
12b16dadb filter: optimize ... |
349 |
case BPF_S_ANC_NLATTR: { |
4738c1db1 [SKFILTER]: Add S... |
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
struct nlattr *nla; if (skb_is_nonlinear(skb)) return 0; if (A > skb->len - sizeof(struct nlattr)) return 0; nla = nla_find((struct nlattr *)&skb->data[A], skb->len - A, X); if (nla) A = (void *)nla - (void *)skb->data; else A = 0; continue; } |
12b16dadb filter: optimize ... |
365 |
case BPF_S_ANC_NLATTR_NEST: { |
d214c7537 filter: add SKF_A... |
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 |
struct nlattr *nla; if (skb_is_nonlinear(skb)) return 0; if (A > skb->len - sizeof(struct nlattr)) return 0; nla = (struct nlattr *)&skb->data[A]; if (nla->nla_len > A - skb->len) return 0; nla = nla_find_nested(nla, X); if (nla) A = (void *)nla - (void *)skb->data; else A = 0; continue; } |
46b325c7e sk_run_filter: ad... |
384 385 386 387 388 |
#ifdef CONFIG_SECCOMP_FILTER case BPF_S_ANC_SECCOMP_LD_W: A = seccomp_bpf_load(fentry->k); continue; #endif |
1da177e4c Linux-2.6.12-rc2 |
389 |
default: |
6c4a5cb21 net: filter: Use ... |
390 391 392 393 |
WARN_RATELIMIT(1, "Unknown code:%u jt:%u tf:%u k:%u ", fentry->code, fentry->jt, fentry->jf, fentry->k); |
1da177e4c Linux-2.6.12-rc2 |
394 395 396 397 398 399 |
return 0; } } return 0; } |
b715631fa socket: sk_filter... |
400 |
EXPORT_SYMBOL(sk_run_filter); |
1da177e4c Linux-2.6.12-rc2 |
401 |
|
2d5311e4e filter: add a sec... |
402 403 404 405 406 407 408 |
/* * Security : * A BPF program is able to use 16 cells of memory to store intermediate * values (check u32 mem[BPF_MEMWORDS] in sk_run_filter()) * As we dont want to clear mem[] array for each packet going through * sk_run_filter(), we check that filter loaded by user never try to read * a cell if not previously written, and we check all branches to be sure |
25985edce Fix common misspe... |
409 |
* a malicious user doesn't try to abuse us. |
2d5311e4e filter: add a sec... |
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 |
*/ static int check_load_and_stores(struct sock_filter *filter, int flen) { u16 *masks, memvalid = 0; /* one bit per cell, 16 cells */ int pc, ret = 0; BUILD_BUG_ON(BPF_MEMWORDS > 16); masks = kmalloc(flen * sizeof(*masks), GFP_KERNEL); if (!masks) return -ENOMEM; memset(masks, 0xff, flen * sizeof(*masks)); for (pc = 0; pc < flen; pc++) { memvalid &= masks[pc]; switch (filter[pc].code) { case BPF_S_ST: case BPF_S_STX: memvalid |= (1 << filter[pc].k); break; case BPF_S_LD_MEM: case BPF_S_LDX_MEM: if (!(memvalid & (1 << filter[pc].k))) { ret = -EINVAL; goto error; } break; case BPF_S_JMP_JA: /* a jump must set masks on target */ masks[pc + 1 + filter[pc].k] &= memvalid; memvalid = ~0; break; case BPF_S_JMP_JEQ_K: case BPF_S_JMP_JEQ_X: case BPF_S_JMP_JGE_K: case BPF_S_JMP_JGE_X: case BPF_S_JMP_JGT_K: case BPF_S_JMP_JGT_X: case BPF_S_JMP_JSET_X: case BPF_S_JMP_JSET_K: /* a jump must set masks on targets */ masks[pc + 1 + filter[pc].jt] &= memvalid; masks[pc + 1 + filter[pc].jf] &= memvalid; memvalid = ~0; break; } } error: kfree(masks); return ret; } |
1da177e4c Linux-2.6.12-rc2 |
461 462 463 464 465 466 467 |
/** * sk_chk_filter - verify socket filter code * @filter: filter to verify * @flen: length of filter * * Check the user's filter code. If we let some ugly * filter code slip through kaboom! The filter must contain |
936998630 [NET]: More instr... |
468 469 |
* no references or jumps that are out of range, no illegal * instructions, and must end with a RET instruction. |
1da177e4c Linux-2.6.12-rc2 |
470 |
* |
7b11f69fb [NET]: Clean up c... |
471 472 473 |
* All jumps are forward as they are not signed. * * Returns 0 if the rule set is legal or -EINVAL if not. |
1da177e4c Linux-2.6.12-rc2 |
474 |
*/ |
4f25af278 filter: use unsig... |
475 |
int sk_chk_filter(struct sock_filter *filter, unsigned int flen) |
1da177e4c Linux-2.6.12-rc2 |
476 |
{ |
cba328fc5 filter: Optimize ... |
477 478 479 480 481 |
/* * Valid instructions are initialized to non-0. * Invalid instructions are initialized to 0. */ static const u8 codes[] = { |
8c1592d68 filter: cleanup c... |
482 483 484 485 486 487 488 |
[BPF_ALU|BPF_ADD|BPF_K] = BPF_S_ALU_ADD_K, [BPF_ALU|BPF_ADD|BPF_X] = BPF_S_ALU_ADD_X, [BPF_ALU|BPF_SUB|BPF_K] = BPF_S_ALU_SUB_K, [BPF_ALU|BPF_SUB|BPF_X] = BPF_S_ALU_SUB_X, [BPF_ALU|BPF_MUL|BPF_K] = BPF_S_ALU_MUL_K, [BPF_ALU|BPF_MUL|BPF_X] = BPF_S_ALU_MUL_X, [BPF_ALU|BPF_DIV|BPF_X] = BPF_S_ALU_DIV_X, |
b6069a957 filter: add MOD o... |
489 490 |
[BPF_ALU|BPF_MOD|BPF_K] = BPF_S_ALU_MOD_K, [BPF_ALU|BPF_MOD|BPF_X] = BPF_S_ALU_MOD_X, |
8c1592d68 filter: cleanup c... |
491 492 493 494 |
[BPF_ALU|BPF_AND|BPF_K] = BPF_S_ALU_AND_K, [BPF_ALU|BPF_AND|BPF_X] = BPF_S_ALU_AND_X, [BPF_ALU|BPF_OR|BPF_K] = BPF_S_ALU_OR_K, [BPF_ALU|BPF_OR|BPF_X] = BPF_S_ALU_OR_X, |
9e49e8895 filter: add XOR i... |
495 496 |
[BPF_ALU|BPF_XOR|BPF_K] = BPF_S_ALU_XOR_K, [BPF_ALU|BPF_XOR|BPF_X] = BPF_S_ALU_XOR_X, |
8c1592d68 filter: cleanup c... |
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 |
[BPF_ALU|BPF_LSH|BPF_K] = BPF_S_ALU_LSH_K, [BPF_ALU|BPF_LSH|BPF_X] = BPF_S_ALU_LSH_X, [BPF_ALU|BPF_RSH|BPF_K] = BPF_S_ALU_RSH_K, [BPF_ALU|BPF_RSH|BPF_X] = BPF_S_ALU_RSH_X, [BPF_ALU|BPF_NEG] = BPF_S_ALU_NEG, [BPF_LD|BPF_W|BPF_ABS] = BPF_S_LD_W_ABS, [BPF_LD|BPF_H|BPF_ABS] = BPF_S_LD_H_ABS, [BPF_LD|BPF_B|BPF_ABS] = BPF_S_LD_B_ABS, [BPF_LD|BPF_W|BPF_LEN] = BPF_S_LD_W_LEN, [BPF_LD|BPF_W|BPF_IND] = BPF_S_LD_W_IND, [BPF_LD|BPF_H|BPF_IND] = BPF_S_LD_H_IND, [BPF_LD|BPF_B|BPF_IND] = BPF_S_LD_B_IND, [BPF_LD|BPF_IMM] = BPF_S_LD_IMM, [BPF_LDX|BPF_W|BPF_LEN] = BPF_S_LDX_W_LEN, [BPF_LDX|BPF_B|BPF_MSH] = BPF_S_LDX_B_MSH, [BPF_LDX|BPF_IMM] = BPF_S_LDX_IMM, [BPF_MISC|BPF_TAX] = BPF_S_MISC_TAX, [BPF_MISC|BPF_TXA] = BPF_S_MISC_TXA, [BPF_RET|BPF_K] = BPF_S_RET_K, [BPF_RET|BPF_A] = BPF_S_RET_A, [BPF_ALU|BPF_DIV|BPF_K] = BPF_S_ALU_DIV_K, [BPF_LD|BPF_MEM] = BPF_S_LD_MEM, [BPF_LDX|BPF_MEM] = BPF_S_LDX_MEM, [BPF_ST] = BPF_S_ST, [BPF_STX] = BPF_S_STX, [BPF_JMP|BPF_JA] = BPF_S_JMP_JA, [BPF_JMP|BPF_JEQ|BPF_K] = BPF_S_JMP_JEQ_K, [BPF_JMP|BPF_JEQ|BPF_X] = BPF_S_JMP_JEQ_X, [BPF_JMP|BPF_JGE|BPF_K] = BPF_S_JMP_JGE_K, [BPF_JMP|BPF_JGE|BPF_X] = BPF_S_JMP_JGE_X, [BPF_JMP|BPF_JGT|BPF_K] = BPF_S_JMP_JGT_K, [BPF_JMP|BPF_JGT|BPF_X] = BPF_S_JMP_JGT_X, [BPF_JMP|BPF_JSET|BPF_K] = BPF_S_JMP_JSET_K, [BPF_JMP|BPF_JSET|BPF_X] = BPF_S_JMP_JSET_X, |
cba328fc5 filter: Optimize ... |
531 |
}; |
1da177e4c Linux-2.6.12-rc2 |
532 |
int pc; |
aa1113d9f net: filter: retu... |
533 |
bool anc_found; |
1da177e4c Linux-2.6.12-rc2 |
534 |
|
1b93ae64c [NET]: Validate s... |
535 |
if (flen == 0 || flen > BPF_MAXINSNS) |
1da177e4c Linux-2.6.12-rc2 |
536 537 538 539 |
return -EINVAL; /* check the filter code now */ for (pc = 0; pc < flen; pc++) { |
cba328fc5 filter: Optimize ... |
540 541 |
struct sock_filter *ftest = &filter[pc]; u16 code = ftest->code; |
936998630 [NET]: More instr... |
542 |
|
cba328fc5 filter: Optimize ... |
543 544 545 |
if (code >= ARRAY_SIZE(codes)) return -EINVAL; code = codes[code]; |
8c1592d68 filter: cleanup c... |
546 |
if (!code) |
cba328fc5 filter: Optimize ... |
547 |
return -EINVAL; |
936998630 [NET]: More instr... |
548 |
/* Some instructions need special checks */ |
cba328fc5 filter: Optimize ... |
549 550 |
switch (code) { case BPF_S_ALU_DIV_K: |
936998630 [NET]: More instr... |
551 552 |
/* check for division by zero */ if (ftest->k == 0) |
1da177e4c Linux-2.6.12-rc2 |
553 |
return -EINVAL; |
c26aed40f filter: use recip... |
554 |
ftest->k = reciprocal_value(ftest->k); |
936998630 [NET]: More instr... |
555 |
break; |
b6069a957 filter: add MOD o... |
556 557 558 559 560 |
case BPF_S_ALU_MOD_K: /* check for division by zero */ if (ftest->k == 0) return -EINVAL; break; |
cba328fc5 filter: Optimize ... |
561 562 563 564 565 |
case BPF_S_LD_MEM: case BPF_S_LDX_MEM: case BPF_S_ST: case BPF_S_STX: /* check for invalid memory addresses */ |
936998630 [NET]: More instr... |
566 567 568 |
if (ftest->k >= BPF_MEMWORDS) return -EINVAL; break; |
cba328fc5 filter: Optimize ... |
569 |
case BPF_S_JMP_JA: |
936998630 [NET]: More instr... |
570 571 572 573 574 |
/* * Note, the large ftest->k might cause loops. * Compare this with conditional jumps below, * where offsets are limited. --ANK (981016) */ |
95c961747 net: cleanup unsi... |
575 |
if (ftest->k >= (unsigned int)(flen-pc-1)) |
936998630 [NET]: More instr... |
576 |
return -EINVAL; |
01f2f3f6e net: optimize Ber... |
577 |
break; |
01f2f3f6e net: optimize Ber... |
578 579 580 581 582 583 584 585 |
case BPF_S_JMP_JEQ_K: case BPF_S_JMP_JEQ_X: case BPF_S_JMP_JGE_K: case BPF_S_JMP_JGE_X: case BPF_S_JMP_JGT_K: case BPF_S_JMP_JGT_X: case BPF_S_JMP_JSET_X: case BPF_S_JMP_JSET_K: |
cba328fc5 filter: Optimize ... |
586 |
/* for conditionals both must be safe */ |
e35bedf36 [NET]: Fix whites... |
587 |
if (pc + ftest->jt + 1 >= flen || |
936998630 [NET]: More instr... |
588 589 |
pc + ftest->jf + 1 >= flen) return -EINVAL; |
cba328fc5 filter: Optimize ... |
590 |
break; |
12b16dadb filter: optimize ... |
591 592 593 |
case BPF_S_LD_W_ABS: case BPF_S_LD_H_ABS: case BPF_S_LD_B_ABS: |
aa1113d9f net: filter: retu... |
594 |
anc_found = false; |
12b16dadb filter: optimize ... |
595 596 |
#define ANCILLARY(CODE) case SKF_AD_OFF + SKF_AD_##CODE: \ code = BPF_S_ANC_##CODE; \ |
aa1113d9f net: filter: retu... |
597 |
anc_found = true; \ |
12b16dadb filter: optimize ... |
598 599 600 601 602 603 604 605 606 607 608 609 |
break switch (ftest->k) { ANCILLARY(PROTOCOL); ANCILLARY(PKTTYPE); ANCILLARY(IFINDEX); ANCILLARY(NLATTR); ANCILLARY(NLATTR_NEST); ANCILLARY(MARK); ANCILLARY(QUEUE); ANCILLARY(HATYPE); ANCILLARY(RXHASH); ANCILLARY(CPU); |
ffe06c17a filter: add XOR o... |
610 |
ANCILLARY(ALU_XOR_X); |
f3335031b net: filter: add ... |
611 612 |
ANCILLARY(VLAN_TAG); ANCILLARY(VLAN_TAG_PRESENT); |
3e5289d5e filter: add ANC_P... |
613 |
ANCILLARY(PAY_OFFSET); |
12b16dadb filter: optimize ... |
614 |
} |
aa1113d9f net: filter: retu... |
615 616 617 618 |
/* ancillary operation unknown or unsupported */ if (anc_found == false && ftest->k >= SKF_AD_OFF) return -EINVAL; |
01f2f3f6e net: optimize Ber... |
619 |
} |
cba328fc5 filter: Optimize ... |
620 |
ftest->code = code; |
01f2f3f6e net: optimize Ber... |
621 |
} |
936998630 [NET]: More instr... |
622 |
|
01f2f3f6e net: optimize Ber... |
623 624 625 626 |
/* last instruction must be a RET code */ switch (filter[flen - 1].code) { case BPF_S_RET_K: case BPF_S_RET_A: |
2d5311e4e filter: add a sec... |
627 |
return check_load_and_stores(filter, flen); |
cba328fc5 filter: Optimize ... |
628 629 |
} return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
630 |
} |
b715631fa socket: sk_filter... |
631 |
EXPORT_SYMBOL(sk_chk_filter); |
1da177e4c Linux-2.6.12-rc2 |
632 633 |
/** |
46bcf14f4 filter: fix sk_fi... |
634 |
* sk_filter_release_rcu - Release a socket filter by rcu_head |
47e958eac [NET]: Fix the ra... |
635 636 |
* @rcu: rcu_head that contains the sk_filter to free */ |
46bcf14f4 filter: fix sk_fi... |
637 |
void sk_filter_release_rcu(struct rcu_head *rcu) |
47e958eac [NET]: Fix the ra... |
638 639 |
{ struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); |
0a14842f5 net: filter: Just... |
640 |
bpf_jit_free(fp); |
46bcf14f4 filter: fix sk_fi... |
641 |
kfree(fp); |
47e958eac [NET]: Fix the ra... |
642 |
} |
46bcf14f4 filter: fix sk_fi... |
643 |
EXPORT_SYMBOL(sk_filter_release_rcu); |
47e958eac [NET]: Fix the ra... |
644 |
|
302d66374 filter: Allow to ... |
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 |
static int __sk_prepare_filter(struct sk_filter *fp) { int err; fp->bpf_func = sk_run_filter; err = sk_chk_filter(fp->insns, fp->len); if (err) return err; bpf_jit_compile(fp); return 0; } /** * sk_unattached_filter_create - create an unattached filter * @fprog: the filter program |
c6c4b97c6 net/core: fix ker... |
662 |
* @pfp: the unattached filter that is created |
302d66374 filter: Allow to ... |
663 |
* |
c6c4b97c6 net/core: fix ker... |
664 |
* Create a filter independent of any socket. We first run some |
302d66374 filter: Allow to ... |
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 |
* sanity checks on it to make sure it does not explode on us later. * If an error occurs or there is insufficient memory for the filter * a negative errno code is returned. On success the return is zero. */ int sk_unattached_filter_create(struct sk_filter **pfp, struct sock_fprog *fprog) { struct sk_filter *fp; unsigned int fsize = sizeof(struct sock_filter) * fprog->len; int err; /* Make sure new filter is there and in the right amounts. */ if (fprog->filter == NULL) return -EINVAL; fp = kmalloc(fsize + sizeof(*fp), GFP_KERNEL); if (!fp) return -ENOMEM; memcpy(fp->insns, fprog->filter, fsize); atomic_set(&fp->refcnt, 1); fp->len = fprog->len; err = __sk_prepare_filter(fp); if (err) goto free_mem; *pfp = fp; return 0; free_mem: kfree(fp); return err; } EXPORT_SYMBOL_GPL(sk_unattached_filter_create); void sk_unattached_filter_destroy(struct sk_filter *fp) { sk_filter_release(fp); } EXPORT_SYMBOL_GPL(sk_unattached_filter_destroy); |
47e958eac [NET]: Fix the ra... |
705 |
/** |
1da177e4c Linux-2.6.12-rc2 |
706 707 708 709 710 711 712 713 714 715 716 |
* sk_attach_filter - attach a socket filter * @fprog: the filter program * @sk: the socket to use * * Attach the user's filter code. We first run some sanity checks on * it to make sure it does not explode on us later. If an error * occurs or there is insufficient memory for the filter a negative * errno code is returned. On success the return is zero. */ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) { |
d3904b739 [NET]: Cleanup th... |
717 |
struct sk_filter *fp, *old_fp; |
1da177e4c Linux-2.6.12-rc2 |
718 719 |
unsigned int fsize = sizeof(struct sock_filter) * fprog->len; int err; |
d59577b6f sk-filter: Add ab... |
720 721 |
if (sock_flag(sk, SOCK_FILTER_LOCKED)) return -EPERM; |
1da177e4c Linux-2.6.12-rc2 |
722 |
/* Make sure new filter is there and in the right amounts. */ |
e35bedf36 [NET]: Fix whites... |
723 724 |
if (fprog->filter == NULL) return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
725 726 727 728 729 |
fp = sock_kmalloc(sk, fsize+sizeof(*fp), GFP_KERNEL); if (!fp) return -ENOMEM; if (copy_from_user(fp->insns, fprog->filter, fsize)) { |
4ec93edb1 [NET] CORE: Fix w... |
730 |
sock_kfree_s(sk, fp, fsize+sizeof(*fp)); |
1da177e4c Linux-2.6.12-rc2 |
731 732 733 734 735 |
return -EFAULT; } atomic_set(&fp->refcnt, 1); fp->len = fprog->len; |
302d66374 filter: Allow to ... |
736 |
err = __sk_prepare_filter(fp); |
d3904b739 [NET]: Cleanup th... |
737 738 739 |
if (err) { sk_filter_uncharge(sk, fp); return err; |
1da177e4c Linux-2.6.12-rc2 |
740 |
} |
f91ff5b9f net: sk_{detach|a... |
741 742 |
old_fp = rcu_dereference_protected(sk->sk_filter, sock_owned_by_user(sk)); |
d3904b739 [NET]: Cleanup th... |
743 |
rcu_assign_pointer(sk->sk_filter, fp); |
d3904b739 [NET]: Cleanup th... |
744 |
|
9b013e05e [NET]: Fix bug in... |
745 |
if (old_fp) |
46bcf14f4 filter: fix sk_fi... |
746 |
sk_filter_uncharge(sk, old_fp); |
d3904b739 [NET]: Cleanup th... |
747 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
748 |
} |
5ff3f0736 net: export attac... |
749 |
EXPORT_SYMBOL_GPL(sk_attach_filter); |
1da177e4c Linux-2.6.12-rc2 |
750 |
|
55b333253 [NET]: Introduce ... |
751 752 753 754 |
int sk_detach_filter(struct sock *sk) { int ret = -ENOENT; struct sk_filter *filter; |
d59577b6f sk-filter: Add ab... |
755 756 |
if (sock_flag(sk, SOCK_FILTER_LOCKED)) return -EPERM; |
f91ff5b9f net: sk_{detach|a... |
757 758 |
filter = rcu_dereference_protected(sk->sk_filter, sock_owned_by_user(sk)); |
55b333253 [NET]: Introduce ... |
759 |
if (filter) { |
a9b3cd7f3 rcu: convert uses... |
760 |
RCU_INIT_POINTER(sk->sk_filter, NULL); |
46bcf14f4 filter: fix sk_fi... |
761 |
sk_filter_uncharge(sk, filter); |
55b333253 [NET]: Introduce ... |
762 763 |
ret = 0; } |
55b333253 [NET]: Introduce ... |
764 765 |
return ret; } |
5ff3f0736 net: export attac... |
766 |
EXPORT_SYMBOL_GPL(sk_detach_filter); |
a8fc92778 sk-filter: Add ab... |
767 |
|
ed13998c3 sock_diag: fix fi... |
768 |
void sk_decode_filter(struct sock_filter *filt, struct sock_filter *to) |
a8fc92778 sk-filter: Add ab... |
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 |
{ static const u16 decodes[] = { [BPF_S_ALU_ADD_K] = BPF_ALU|BPF_ADD|BPF_K, [BPF_S_ALU_ADD_X] = BPF_ALU|BPF_ADD|BPF_X, [BPF_S_ALU_SUB_K] = BPF_ALU|BPF_SUB|BPF_K, [BPF_S_ALU_SUB_X] = BPF_ALU|BPF_SUB|BPF_X, [BPF_S_ALU_MUL_K] = BPF_ALU|BPF_MUL|BPF_K, [BPF_S_ALU_MUL_X] = BPF_ALU|BPF_MUL|BPF_X, [BPF_S_ALU_DIV_X] = BPF_ALU|BPF_DIV|BPF_X, [BPF_S_ALU_MOD_K] = BPF_ALU|BPF_MOD|BPF_K, [BPF_S_ALU_MOD_X] = BPF_ALU|BPF_MOD|BPF_X, [BPF_S_ALU_AND_K] = BPF_ALU|BPF_AND|BPF_K, [BPF_S_ALU_AND_X] = BPF_ALU|BPF_AND|BPF_X, [BPF_S_ALU_OR_K] = BPF_ALU|BPF_OR|BPF_K, [BPF_S_ALU_OR_X] = BPF_ALU|BPF_OR|BPF_X, [BPF_S_ALU_XOR_K] = BPF_ALU|BPF_XOR|BPF_K, [BPF_S_ALU_XOR_X] = BPF_ALU|BPF_XOR|BPF_X, [BPF_S_ALU_LSH_K] = BPF_ALU|BPF_LSH|BPF_K, [BPF_S_ALU_LSH_X] = BPF_ALU|BPF_LSH|BPF_X, [BPF_S_ALU_RSH_K] = BPF_ALU|BPF_RSH|BPF_K, [BPF_S_ALU_RSH_X] = BPF_ALU|BPF_RSH|BPF_X, [BPF_S_ALU_NEG] = BPF_ALU|BPF_NEG, [BPF_S_LD_W_ABS] = BPF_LD|BPF_W|BPF_ABS, [BPF_S_LD_H_ABS] = BPF_LD|BPF_H|BPF_ABS, [BPF_S_LD_B_ABS] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_ANC_PROTOCOL] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_ANC_PKTTYPE] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_ANC_IFINDEX] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_ANC_NLATTR] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_ANC_NLATTR_NEST] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_ANC_MARK] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_ANC_QUEUE] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_ANC_HATYPE] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_ANC_RXHASH] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_ANC_CPU] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_ANC_ALU_XOR_X] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_ANC_SECCOMP_LD_W] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_ANC_VLAN_TAG] = BPF_LD|BPF_B|BPF_ABS, [BPF_S_ANC_VLAN_TAG_PRESENT] = BPF_LD|BPF_B|BPF_ABS, |
3e5289d5e filter: add ANC_P... |
808 |
[BPF_S_ANC_PAY_OFFSET] = BPF_LD|BPF_B|BPF_ABS, |
a8fc92778 sk-filter: Add ab... |
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 |
[BPF_S_LD_W_LEN] = BPF_LD|BPF_W|BPF_LEN, [BPF_S_LD_W_IND] = BPF_LD|BPF_W|BPF_IND, [BPF_S_LD_H_IND] = BPF_LD|BPF_H|BPF_IND, [BPF_S_LD_B_IND] = BPF_LD|BPF_B|BPF_IND, [BPF_S_LD_IMM] = BPF_LD|BPF_IMM, [BPF_S_LDX_W_LEN] = BPF_LDX|BPF_W|BPF_LEN, [BPF_S_LDX_B_MSH] = BPF_LDX|BPF_B|BPF_MSH, [BPF_S_LDX_IMM] = BPF_LDX|BPF_IMM, [BPF_S_MISC_TAX] = BPF_MISC|BPF_TAX, [BPF_S_MISC_TXA] = BPF_MISC|BPF_TXA, [BPF_S_RET_K] = BPF_RET|BPF_K, [BPF_S_RET_A] = BPF_RET|BPF_A, [BPF_S_ALU_DIV_K] = BPF_ALU|BPF_DIV|BPF_K, [BPF_S_LD_MEM] = BPF_LD|BPF_MEM, [BPF_S_LDX_MEM] = BPF_LDX|BPF_MEM, [BPF_S_ST] = BPF_ST, [BPF_S_STX] = BPF_STX, [BPF_S_JMP_JA] = BPF_JMP|BPF_JA, [BPF_S_JMP_JEQ_K] = BPF_JMP|BPF_JEQ|BPF_K, [BPF_S_JMP_JEQ_X] = BPF_JMP|BPF_JEQ|BPF_X, [BPF_S_JMP_JGE_K] = BPF_JMP|BPF_JGE|BPF_K, [BPF_S_JMP_JGE_X] = BPF_JMP|BPF_JGE|BPF_X, [BPF_S_JMP_JGT_K] = BPF_JMP|BPF_JGT|BPF_K, [BPF_S_JMP_JGT_X] = BPF_JMP|BPF_JGT|BPF_X, [BPF_S_JMP_JSET_K] = BPF_JMP|BPF_JSET|BPF_K, [BPF_S_JMP_JSET_X] = BPF_JMP|BPF_JSET|BPF_X, }; u16 code; code = filt->code; to->code = decodes[code]; to->jt = filt->jt; to->jf = filt->jf; if (code == BPF_S_ALU_DIV_K) { /* * When loaded this rule user gave us X, which was * translated into R = r(X). Now we calculate the * RR = r(R) and report it back. If next time this * value is loaded and RRR = r(RR) is calculated * then the R == RRR will be true. * * One exception. X == 1 translates into R == 0 and * we can't calculate RR out of it with r(). */ if (filt->k == 0) to->k = 1; else to->k = reciprocal_value(filt->k); BUG_ON(reciprocal_value(to->k) != filt->k); } else to->k = filt->k; } int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf, unsigned int len) { struct sk_filter *filter; int i, ret; lock_sock(sk); filter = rcu_dereference_protected(sk->sk_filter, sock_owned_by_user(sk)); ret = 0; if (!filter) goto out; ret = filter->len; if (!len) goto out; ret = -EINVAL; if (len < filter->len) goto out; ret = -EFAULT; for (i = 0; i < filter->len; i++) { struct sock_filter fb; sk_decode_filter(&filter->insns[i], &fb); if (copy_to_user(&ubuf[i], &fb, sizeof(fb))) goto out; } ret = filter->len; out: release_sock(sk); return ret; } |