Blame view

net/core/filter.c 22.7 KB
1da177e4c   Linus Torvalds   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   Kris Katterjohn   [NET]: More instr...
16
   * Kris Katterjohn - Added many additional checks in sk_chk_filter()
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
   */
  
  #include <linux/module.h>
  #include <linux/types.h>
1da177e4c   Linus Torvalds   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   Tejun Heo   include cleanup: ...
28
  #include <linux/gfp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
  #include <net/ip.h>
  #include <net/protocol.h>
4738c1db1   Patrick McHardy   [SKFILTER]: Add S...
31
  #include <net/netlink.h>
1da177e4c   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
36
  #include <asm/uaccess.h>
40daafc80   Dmitry Mishin   unaligned access ...
37
  #include <asm/unaligned.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  #include <linux/filter.h>
c26aed40f   Eric Dumazet   filter: use recip...
39
  #include <linux/reciprocal_div.h>
86e4ca66e   David S. Miller   bug.h: Move ratel...
40
  #include <linux/ratelimit.h>
46b325c7e   Will Drewry   sk_run_filter: ad...
41
  #include <linux/seccomp.h>
f3335031b   Eric Dumazet   net: filter: add ...
42
  #include <linux/if_vlan.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43

f03fb3f45   Jan Seiffert   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   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
  {
  	u8 *ptr = NULL;
  
  	if (k >= SKF_NET_OFF)
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
53
  		ptr = skb_network_header(skb) + k - SKF_NET_OFF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  	else if (k >= SKF_LL_OFF)
98e399f82   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
55
  		ptr = skb_mac_header(skb) + k - SKF_LL_OFF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56

4bc65dd8d   Eric Dumazet   filter: use size ...
57
  	if (ptr >= skb->head && ptr + size <= skb_tail_pointer(skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
  		return ptr;
  	return NULL;
  }
62ab08121   Eric Dumazet   filter: constify ...
61
  static inline void *load_pointer(const struct sk_buff *skb, int k,
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
62
  				 unsigned int size, void *buffer)
0b05b2a49   Patrick McHardy   [NET]: Consolidat...
63
64
65
  {
  	if (k >= 0)
  		return skb_header_pointer(skb, k, size, buffer);
f03fb3f45   Jan Seiffert   bpf jit: Make the...
66
  	return bpf_internal_load_pointer_neg_helper(skb, k, size);
0b05b2a49   Patrick McHardy   [NET]: Consolidat...
67
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
  /**
43db6d65e   Stephen Hemminger   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   Stephen Hemminger   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   Mel Gorman   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   Stephen Hemminger   socket: sk_filter...
91
92
93
  	err = security_sock_rcv_skb(sk, skb);
  	if (err)
  		return err;
80f8f1027   Eric Dumazet   net: filter: dont...
94
95
  	rcu_read_lock();
  	filter = rcu_dereference(sk->sk_filter);
43db6d65e   Stephen Hemminger   socket: sk_filter...
96
  	if (filter) {
0a14842f5   Eric Dumazet   net: filter: Just...
97
  		unsigned int pkt_len = SK_RUN_FILTER(filter, skb);
0d7da9ddd   Eric Dumazet   net: add __rcu an...
98

43db6d65e   Stephen Hemminger   socket: sk_filter...
99
100
  		err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM;
  	}
80f8f1027   Eric Dumazet   net: filter: dont...
101
  	rcu_read_unlock();
43db6d65e   Stephen Hemminger   socket: sk_filter...
102
103
104
105
106
107
  
  	return err;
  }
  EXPORT_SYMBOL(sk_filter);
  
  /**
2966b66c2   Kris Katterjohn   [NET]: more white...
108
   *	sk_run_filter - run a filter on a socket
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
   *	@skb: buffer to run the filter on
697d0e338   Randy Dunlap   net: fix kernel-d...
110
   *	@fentry: filter to apply
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
   *
   * Decode and apply filter instructions to the skb->data.
93aaae2e0   Eric Dumazet   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   Linus Torvalds   Linux-2.6.12-rc2
118
   */
62ab08121   Eric Dumazet   filter: constify ...
119
120
  unsigned int sk_run_filter(const struct sk_buff *skb,
  			   const struct sock_filter *fentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  {
0b05b2a49   Patrick McHardy   [NET]: Consolidat...
122
  	void *ptr;
2966b66c2   Kris Katterjohn   [NET]: more white...
123
124
  	u32 A = 0;			/* Accumulator */
  	u32 X = 0;			/* Index Register */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  	u32 mem[BPF_MEMWORDS];		/* Scratch Memory Store */
0b05b2a49   Patrick McHardy   [NET]: Consolidat...
126
  	u32 tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
  	int k;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
131
  
  	/*
  	 * Process array of filter instructions.
  	 */
93aaae2e0   Eric Dumazet   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   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
138

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  		switch (fentry->code) {
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
140
  		case BPF_S_ALU_ADD_X:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
  			A += X;
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
143
  		case BPF_S_ALU_ADD_K:
93aaae2e0   Eric Dumazet   filter: optimize ...
144
  			A += K;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
146
  		case BPF_S_ALU_SUB_X:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
  			A -= X;
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
149
  		case BPF_S_ALU_SUB_K:
93aaae2e0   Eric Dumazet   filter: optimize ...
150
  			A -= K;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
152
  		case BPF_S_ALU_MUL_X:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
  			A *= X;
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
155
  		case BPF_S_ALU_MUL_K:
93aaae2e0   Eric Dumazet   filter: optimize ...
156
  			A *= K;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
158
  		case BPF_S_ALU_DIV_X:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
161
162
  			if (X == 0)
  				return 0;
  			A /= X;
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
163
  		case BPF_S_ALU_DIV_K:
c26aed40f   Eric Dumazet   filter: use recip...
164
  			A = reciprocal_divide(A, K);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  			continue;
b6069a957   Eric Dumazet   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   Hagen Paul Pfeifer   net: optimize Ber...
174
  		case BPF_S_ALU_AND_X:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
  			A &= X;
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
177
  		case BPF_S_ALU_AND_K:
93aaae2e0   Eric Dumazet   filter: optimize ...
178
  			A &= K;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
180
  		case BPF_S_ALU_OR_X:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
  			A |= X;
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
183
  		case BPF_S_ALU_OR_K:
93aaae2e0   Eric Dumazet   filter: optimize ...
184
  			A |= K;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  			continue;
9e49e8895   Daniel Borkmann   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   Hagen Paul Pfeifer   net: optimize Ber...
193
  		case BPF_S_ALU_LSH_X:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
  			A <<= X;
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
196
  		case BPF_S_ALU_LSH_K:
93aaae2e0   Eric Dumazet   filter: optimize ...
197
  			A <<= K;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
199
  		case BPF_S_ALU_RSH_X:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
  			A >>= X;
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
202
  		case BPF_S_ALU_RSH_K:
93aaae2e0   Eric Dumazet   filter: optimize ...
203
  			A >>= K;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
205
  		case BPF_S_ALU_NEG:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
207
  			A = -A;
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
208
  		case BPF_S_JMP_JA:
93aaae2e0   Eric Dumazet   filter: optimize ...
209
  			fentry += K;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
211
  		case BPF_S_JMP_JGT_K:
93aaae2e0   Eric Dumazet   filter: optimize ...
212
  			fentry += (A > K) ? fentry->jt : fentry->jf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
214
  		case BPF_S_JMP_JGE_K:
93aaae2e0   Eric Dumazet   filter: optimize ...
215
  			fentry += (A >= K) ? fentry->jt : fentry->jf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
217
  		case BPF_S_JMP_JEQ_K:
93aaae2e0   Eric Dumazet   filter: optimize ...
218
  			fentry += (A == K) ? fentry->jt : fentry->jf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
220
  		case BPF_S_JMP_JSET_K:
93aaae2e0   Eric Dumazet   filter: optimize ...
221
  			fentry += (A & K) ? fentry->jt : fentry->jf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
223
  		case BPF_S_JMP_JGT_X:
93aaae2e0   Eric Dumazet   filter: optimize ...
224
  			fentry += (A > X) ? fentry->jt : fentry->jf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
226
  		case BPF_S_JMP_JGE_X:
93aaae2e0   Eric Dumazet   filter: optimize ...
227
  			fentry += (A >= X) ? fentry->jt : fentry->jf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
229
  		case BPF_S_JMP_JEQ_X:
93aaae2e0   Eric Dumazet   filter: optimize ...
230
  			fentry += (A == X) ? fentry->jt : fentry->jf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
232
  		case BPF_S_JMP_JSET_X:
93aaae2e0   Eric Dumazet   filter: optimize ...
233
  			fentry += (A & X) ? fentry->jt : fentry->jf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
235
  		case BPF_S_LD_W_ABS:
93aaae2e0   Eric Dumazet   filter: optimize ...
236
  			k = K;
e35bedf36   Kris Katterjohn   [NET]: Fix whites...
237
  load_w:
0b05b2a49   Patrick McHardy   [NET]: Consolidat...
238
239
  			ptr = load_pointer(skb, k, 4, &tmp);
  			if (ptr != NULL) {
d3e2ce3bc   Harvey Harrison   net: use get/put_...
240
  				A = get_unaligned_be32(ptr);
0b05b2a49   Patrick McHardy   [NET]: Consolidat...
241
  				continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
  			}
12b16dadb   Eric Dumazet   filter: optimize ...
243
  			return 0;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
244
  		case BPF_S_LD_H_ABS:
93aaae2e0   Eric Dumazet   filter: optimize ...
245
  			k = K;
e35bedf36   Kris Katterjohn   [NET]: Fix whites...
246
  load_h:
0b05b2a49   Patrick McHardy   [NET]: Consolidat...
247
248
  			ptr = load_pointer(skb, k, 2, &tmp);
  			if (ptr != NULL) {
d3e2ce3bc   Harvey Harrison   net: use get/put_...
249
  				A = get_unaligned_be16(ptr);
0b05b2a49   Patrick McHardy   [NET]: Consolidat...
250
  				continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  			}
12b16dadb   Eric Dumazet   filter: optimize ...
252
  			return 0;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
253
  		case BPF_S_LD_B_ABS:
93aaae2e0   Eric Dumazet   filter: optimize ...
254
  			k = K;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  load_b:
0b05b2a49   Patrick McHardy   [NET]: Consolidat...
256
257
258
259
  			ptr = load_pointer(skb, k, 1, &tmp);
  			if (ptr != NULL) {
  				A = *(u8 *)ptr;
  				continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
  			}
12b16dadb   Eric Dumazet   filter: optimize ...
261
  			return 0;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
262
  		case BPF_S_LD_W_LEN:
3154e540e   Patrick McHardy   [NET]: net/core/f...
263
  			A = skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
265
  		case BPF_S_LDX_W_LEN:
3154e540e   Patrick McHardy   [NET]: net/core/f...
266
  			X = skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
268
  		case BPF_S_LD_W_IND:
93aaae2e0   Eric Dumazet   filter: optimize ...
269
  			k = X + K;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
  			goto load_w;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
271
  		case BPF_S_LD_H_IND:
93aaae2e0   Eric Dumazet   filter: optimize ...
272
  			k = X + K;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
  			goto load_h;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
274
  		case BPF_S_LD_B_IND:
93aaae2e0   Eric Dumazet   filter: optimize ...
275
  			k = X + K;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  			goto load_b;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
277
  		case BPF_S_LDX_B_MSH:
93aaae2e0   Eric Dumazet   filter: optimize ...
278
  			ptr = load_pointer(skb, K, 1, &tmp);
0b05b2a49   Patrick McHardy   [NET]: Consolidat...
279
280
281
282
283
  			if (ptr != NULL) {
  				X = (*(u8 *)ptr & 0xf) << 2;
  				continue;
  			}
  			return 0;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
284
  		case BPF_S_LD_IMM:
93aaae2e0   Eric Dumazet   filter: optimize ...
285
  			A = K;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
287
  		case BPF_S_LDX_IMM:
93aaae2e0   Eric Dumazet   filter: optimize ...
288
  			X = K;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
290
  		case BPF_S_LD_MEM:
2d5311e4e   Eric Dumazet   filter: add a sec...
291
  			A = mem[K];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
293
  		case BPF_S_LDX_MEM:
2d5311e4e   Eric Dumazet   filter: add a sec...
294
  			X = mem[K];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
296
  		case BPF_S_MISC_TAX:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
  			X = A;
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
299
  		case BPF_S_MISC_TXA:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
  			A = X;
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
302
  		case BPF_S_RET_K:
93aaae2e0   Eric Dumazet   filter: optimize ...
303
  			return K;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
304
  		case BPF_S_RET_A:
4bad4dc91   Kris Katterjohn   [NET]: Change sk_...
305
  			return A;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
306
  		case BPF_S_ST:
93aaae2e0   Eric Dumazet   filter: optimize ...
307
  			mem[K] = A;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  			continue;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
309
  		case BPF_S_STX:
93aaae2e0   Eric Dumazet   filter: optimize ...
310
  			mem[K] = X;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
  			continue;
12b16dadb   Eric Dumazet   filter: optimize ...
312
  		case BPF_S_ANC_PROTOCOL:
252e33467   Al Viro   [NET] net/core: A...
313
  			A = ntohs(skb->protocol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  			continue;
12b16dadb   Eric Dumazet   filter: optimize ...
315
  		case BPF_S_ANC_PKTTYPE:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
  			A = skb->pkt_type;
  			continue;
12b16dadb   Eric Dumazet   filter: optimize ...
318
  		case BPF_S_ANC_IFINDEX:
40eaf9627   Paul LeoNerd Evans   net: Socket filte...
319
320
  			if (!skb->dev)
  				return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
322
  			A = skb->dev->ifindex;
  			continue;
12b16dadb   Eric Dumazet   filter: optimize ...
323
  		case BPF_S_ANC_MARK:
7e75f93ed   jamal   pkt_sched: ingres...
324
325
  			A = skb->mark;
  			continue;
12b16dadb   Eric Dumazet   filter: optimize ...
326
  		case BPF_S_ANC_QUEUE:
d19742fb1   Eric Dumazet   filter: Add SKF_A...
327
328
  			A = skb->queue_mapping;
  			continue;
12b16dadb   Eric Dumazet   filter: optimize ...
329
  		case BPF_S_ANC_HATYPE:
40eaf9627   Paul LeoNerd Evans   net: Socket filte...
330
331
332
333
  			if (!skb->dev)
  				return 0;
  			A = skb->dev->type;
  			continue;
12b16dadb   Eric Dumazet   filter: optimize ...
334
  		case BPF_S_ANC_RXHASH:
da2033c28   Eric Dumazet   filter: add SKF_A...
335
336
  			A = skb->rxhash;
  			continue;
12b16dadb   Eric Dumazet   filter: optimize ...
337
  		case BPF_S_ANC_CPU:
da2033c28   Eric Dumazet   filter: add SKF_A...
338
339
  			A = raw_smp_processor_id();
  			continue;
f3335031b   Eric Dumazet   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   Daniel Borkmann   filter: add ANC_P...
346
347
348
  		case BPF_S_ANC_PAY_OFFSET:
  			A = __skb_get_poff(skb);
  			continue;
12b16dadb   Eric Dumazet   filter: optimize ...
349
  		case BPF_S_ANC_NLATTR: {
4738c1db1   Patrick McHardy   [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   Eric Dumazet   filter: optimize ...
365
  		case BPF_S_ANC_NLATTR_NEST: {
d214c7537   Pablo Neira Ayuso   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   Will Drewry   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   Linus Torvalds   Linux-2.6.12-rc2
389
  		default:
6c4a5cb21   Joe Perches   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   Linus Torvalds   Linux-2.6.12-rc2
394
395
396
397
398
399
  			return 0;
  		}
  	}
  
  	return 0;
  }
b715631fa   Stephen Hemminger   socket: sk_filter...
400
  EXPORT_SYMBOL(sk_run_filter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401

2d5311e4e   Eric Dumazet   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   Lucas De Marchi   Fix common misspe...
409
   * a malicious user doesn't try to abuse us.
2d5311e4e   Eric Dumazet   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   Linus Torvalds   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   Kris Katterjohn   [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   Linus Torvalds   Linux-2.6.12-rc2
470
   *
7b11f69fb   Kris Katterjohn   [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   Linus Torvalds   Linux-2.6.12-rc2
474
   */
4f25af278   Dan Carpenter   filter: use unsig...
475
  int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
  {
cba328fc5   Tetsuo Handa   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   Eric Dumazet   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   Eric Dumazet   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   Eric Dumazet   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   Daniel Borkmann   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   Eric Dumazet   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   Tetsuo Handa   filter: Optimize ...
531
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
  	int pc;
aa1113d9f   Daniel Borkmann   net: filter: retu...
533
  	bool anc_found;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534

1b93ae64c   David S. Miller   [NET]: Validate s...
535
  	if (flen == 0 || flen > BPF_MAXINSNS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
537
538
539
  		return -EINVAL;
  
  	/* check the filter code now */
  	for (pc = 0; pc < flen; pc++) {
cba328fc5   Tetsuo Handa   filter: Optimize ...
540
541
  		struct sock_filter *ftest = &filter[pc];
  		u16 code = ftest->code;
936998630   Kris Katterjohn   [NET]: More instr...
542

cba328fc5   Tetsuo Handa   filter: Optimize ...
543
544
545
  		if (code >= ARRAY_SIZE(codes))
  			return -EINVAL;
  		code = codes[code];
8c1592d68   Eric Dumazet   filter: cleanup c...
546
  		if (!code)
cba328fc5   Tetsuo Handa   filter: Optimize ...
547
  			return -EINVAL;
936998630   Kris Katterjohn   [NET]: More instr...
548
  		/* Some instructions need special checks */
cba328fc5   Tetsuo Handa   filter: Optimize ...
549
550
  		switch (code) {
  		case BPF_S_ALU_DIV_K:
936998630   Kris Katterjohn   [NET]: More instr...
551
552
  			/* check for division by zero */
  			if (ftest->k == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  				return -EINVAL;
c26aed40f   Eric Dumazet   filter: use recip...
554
  			ftest->k = reciprocal_value(ftest->k);
936998630   Kris Katterjohn   [NET]: More instr...
555
  			break;
b6069a957   Eric Dumazet   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   Tetsuo Handa   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   Kris Katterjohn   [NET]: More instr...
566
567
568
  			if (ftest->k >= BPF_MEMWORDS)
  				return -EINVAL;
  			break;
cba328fc5   Tetsuo Handa   filter: Optimize ...
569
  		case BPF_S_JMP_JA:
936998630   Kris Katterjohn   [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   Eric Dumazet   net: cleanup unsi...
575
  			if (ftest->k >= (unsigned int)(flen-pc-1))
936998630   Kris Katterjohn   [NET]: More instr...
576
  				return -EINVAL;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
577
  			break;
01f2f3f6e   Hagen Paul Pfeifer   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   Tetsuo Handa   filter: Optimize ...
586
  			/* for conditionals both must be safe */
e35bedf36   Kris Katterjohn   [NET]: Fix whites...
587
  			if (pc + ftest->jt + 1 >= flen ||
936998630   Kris Katterjohn   [NET]: More instr...
588
589
  			    pc + ftest->jf + 1 >= flen)
  				return -EINVAL;
cba328fc5   Tetsuo Handa   filter: Optimize ...
590
  			break;
12b16dadb   Eric Dumazet   filter: optimize ...
591
592
593
  		case BPF_S_LD_W_ABS:
  		case BPF_S_LD_H_ABS:
  		case BPF_S_LD_B_ABS:
aa1113d9f   Daniel Borkmann   net: filter: retu...
594
  			anc_found = false;
12b16dadb   Eric Dumazet   filter: optimize ...
595
596
  #define ANCILLARY(CODE) case SKF_AD_OFF + SKF_AD_##CODE:	\
  				code = BPF_S_ANC_##CODE;	\
aa1113d9f   Daniel Borkmann   net: filter: retu...
597
  				anc_found = true;		\
12b16dadb   Eric Dumazet   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   Jiri Pirko   filter: add XOR o...
610
  			ANCILLARY(ALU_XOR_X);
f3335031b   Eric Dumazet   net: filter: add ...
611
612
  			ANCILLARY(VLAN_TAG);
  			ANCILLARY(VLAN_TAG_PRESENT);
3e5289d5e   Daniel Borkmann   filter: add ANC_P...
613
  			ANCILLARY(PAY_OFFSET);
12b16dadb   Eric Dumazet   filter: optimize ...
614
  			}
aa1113d9f   Daniel Borkmann   net: filter: retu...
615
616
617
618
  
  			/* ancillary operation unknown or unsupported */
  			if (anc_found == false && ftest->k >= SKF_AD_OFF)
  				return -EINVAL;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
619
  		}
cba328fc5   Tetsuo Handa   filter: Optimize ...
620
  		ftest->code = code;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
621
  	}
936998630   Kris Katterjohn   [NET]: More instr...
622

01f2f3f6e   Hagen Paul Pfeifer   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   Eric Dumazet   filter: add a sec...
627
  		return check_load_and_stores(filter, flen);
cba328fc5   Tetsuo Handa   filter: Optimize ...
628
629
  	}
  	return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
  }
b715631fa   Stephen Hemminger   socket: sk_filter...
631
  EXPORT_SYMBOL(sk_chk_filter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
633
  
  /**
46bcf14f4   Eric Dumazet   filter: fix sk_fi...
634
   * 	sk_filter_release_rcu - Release a socket filter by rcu_head
47e958eac   Pavel Emelyanov   [NET]: Fix the ra...
635
636
   *	@rcu: rcu_head that contains the sk_filter to free
   */
46bcf14f4   Eric Dumazet   filter: fix sk_fi...
637
  void sk_filter_release_rcu(struct rcu_head *rcu)
47e958eac   Pavel Emelyanov   [NET]: Fix the ra...
638
639
  {
  	struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu);
0a14842f5   Eric Dumazet   net: filter: Just...
640
  	bpf_jit_free(fp);
46bcf14f4   Eric Dumazet   filter: fix sk_fi...
641
  	kfree(fp);
47e958eac   Pavel Emelyanov   [NET]: Fix the ra...
642
  }
46bcf14f4   Eric Dumazet   filter: fix sk_fi...
643
  EXPORT_SYMBOL(sk_filter_release_rcu);
47e958eac   Pavel Emelyanov   [NET]: Fix the ra...
644

302d66374   Jiri Pirko   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   Randy Dunlap   net/core: fix ker...
662
   *	@pfp: the unattached filter that is created
302d66374   Jiri Pirko   filter: Allow to ...
663
   *
c6c4b97c6   Randy Dunlap   net/core: fix ker...
664
   * Create a filter independent of any socket. We first run some
302d66374   Jiri Pirko   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   Pavel Emelyanov   [NET]: Fix the ra...
705
  /**
1da177e4c   Linus Torvalds   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   Pavel Emelyanov   [NET]: Cleanup th...
717
  	struct sk_filter *fp, *old_fp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
719
  	unsigned int fsize = sizeof(struct sock_filter) * fprog->len;
  	int err;
d59577b6f   Vincent Bernat   sk-filter: Add ab...
720
721
  	if (sock_flag(sk, SOCK_FILTER_LOCKED))
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
  	/* Make sure new filter is there and in the right amounts. */
e35bedf36   Kris Katterjohn   [NET]: Fix whites...
723
724
  	if (fprog->filter == NULL)
  		return -EINVAL;
1da177e4c   Linus Torvalds   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   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
730
  		sock_kfree_s(sk, fp, fsize+sizeof(*fp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
733
734
735
  		return -EFAULT;
  	}
  
  	atomic_set(&fp->refcnt, 1);
  	fp->len = fprog->len;
302d66374   Jiri Pirko   filter: Allow to ...
736
  	err = __sk_prepare_filter(fp);
d3904b739   Pavel Emelyanov   [NET]: Cleanup th...
737
738
739
  	if (err) {
  		sk_filter_uncharge(sk, fp);
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
  	}
f91ff5b9f   Eric Dumazet   net: sk_{detach|a...
741
742
  	old_fp = rcu_dereference_protected(sk->sk_filter,
  					   sock_owned_by_user(sk));
d3904b739   Pavel Emelyanov   [NET]: Cleanup th...
743
  	rcu_assign_pointer(sk->sk_filter, fp);
d3904b739   Pavel Emelyanov   [NET]: Cleanup th...
744

9b013e05e   Olof Johansson   [NET]: Fix bug in...
745
  	if (old_fp)
46bcf14f4   Eric Dumazet   filter: fix sk_fi...
746
  		sk_filter_uncharge(sk, old_fp);
d3904b739   Pavel Emelyanov   [NET]: Cleanup th...
747
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
  }
5ff3f0736   Michael S. Tsirkin   net: export attac...
749
  EXPORT_SYMBOL_GPL(sk_attach_filter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750

55b333253   Pavel Emelyanov   [NET]: Introduce ...
751
752
753
754
  int sk_detach_filter(struct sock *sk)
  {
  	int ret = -ENOENT;
  	struct sk_filter *filter;
d59577b6f   Vincent Bernat   sk-filter: Add ab...
755
756
  	if (sock_flag(sk, SOCK_FILTER_LOCKED))
  		return -EPERM;
f91ff5b9f   Eric Dumazet   net: sk_{detach|a...
757
758
  	filter = rcu_dereference_protected(sk->sk_filter,
  					   sock_owned_by_user(sk));
55b333253   Pavel Emelyanov   [NET]: Introduce ...
759
  	if (filter) {
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
760
  		RCU_INIT_POINTER(sk->sk_filter, NULL);
46bcf14f4   Eric Dumazet   filter: fix sk_fi...
761
  		sk_filter_uncharge(sk, filter);
55b333253   Pavel Emelyanov   [NET]: Introduce ...
762
763
  		ret = 0;
  	}
55b333253   Pavel Emelyanov   [NET]: Introduce ...
764
765
  	return ret;
  }
5ff3f0736   Michael S. Tsirkin   net: export attac...
766
  EXPORT_SYMBOL_GPL(sk_detach_filter);
a8fc92778   Pavel Emelyanov   sk-filter: Add ab...
767

ed13998c3   Nicolas Dichtel   sock_diag: fix fi...
768
  void sk_decode_filter(struct sock_filter *filt, struct sock_filter *to)
a8fc92778   Pavel Emelyanov   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   Daniel Borkmann   filter: add ANC_P...
808
  		[BPF_S_ANC_PAY_OFFSET]	= BPF_LD|BPF_B|BPF_ABS,
a8fc92778   Pavel Emelyanov   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;
  }