Blame view

net/core/filter.c 15.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
36
37
  #include <linux/skbuff.h>
  #include <net/sock.h>
  #include <linux/errno.h>
  #include <linux/timer.h>
  #include <asm/system.h>
  #include <asm/uaccess.h>
40daafc80   Dmitry Mishin   unaligned access ...
38
  #include <asm/unaligned.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  #include <linux/filter.h>
c26aed40f   Eric Dumazet   filter: use recip...
40
  #include <linux/reciprocal_div.h>
86e4ca66e   David S. Miller   bug.h: Move ratel...
41
  #include <linux/ratelimit.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
  
  /* No hurry in this branch */
4bc65dd8d   Eric Dumazet   filter: use size ...
44
  static void *__load_pointer(const struct sk_buff *skb, int k, unsigned int size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
  {
  	u8 *ptr = NULL;
  
  	if (k >= SKF_NET_OFF)
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
49
  		ptr = skb_network_header(skb) + k - SKF_NET_OFF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  	else if (k >= SKF_LL_OFF)
98e399f82   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
51
  		ptr = skb_mac_header(skb) + k - SKF_LL_OFF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

4bc65dd8d   Eric Dumazet   filter: use size ...
53
  	if (ptr >= skb->head && ptr + size <= skb_tail_pointer(skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
56
  		return ptr;
  	return NULL;
  }
62ab08121   Eric Dumazet   filter: constify ...
57
  static inline void *load_pointer(const struct sk_buff *skb, int k,
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
58
  				 unsigned int size, void *buffer)
0b05b2a49   Patrick McHardy   [NET]: Consolidat...
59
60
61
  {
  	if (k >= 0)
  		return skb_header_pointer(skb, k, size, buffer);
12b16dadb   Eric Dumazet   filter: optimize ...
62
  	return __load_pointer(skb, k, size);
0b05b2a49   Patrick McHardy   [NET]: Consolidat...
63
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  /**
43db6d65e   Stephen Hemminger   socket: sk_filter...
65
66
67
   *	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...
68
69
70
71
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;
  
  	err = security_sock_rcv_skb(sk, skb);
  	if (err)
  		return err;
80f8f1027   Eric Dumazet   net: filter: dont...
84
85
  	rcu_read_lock();
  	filter = rcu_dereference(sk->sk_filter);
43db6d65e   Stephen Hemminger   socket: sk_filter...
86
  	if (filter) {
0a14842f5   Eric Dumazet   net: filter: Just...
87
  		unsigned int pkt_len = SK_RUN_FILTER(filter, skb);
0d7da9ddd   Eric Dumazet   net: add __rcu an...
88

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

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

2d5311e4e   Eric Dumazet   filter: add a sec...
363
364
365
366
367
368
369
  /*
   * 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...
370
   * a malicious user doesn't try to abuse us.
2d5311e4e   Eric Dumazet   filter: add a sec...
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
   */
  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
422
423
424
425
426
427
428
  /**
   *	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...
429
430
   * 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
431
   *
7b11f69fb   Kris Katterjohn   [NET]: Clean up c...
432
433
434
   * 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
435
   */
4f25af278   Dan Carpenter   filter: use unsig...
436
  int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
  {
cba328fc5   Tetsuo Handa   filter: Optimize ...
438
439
440
441
442
  	/*
  	 * Valid instructions are initialized to non-0.
  	 * Invalid instructions are initialized to 0.
  	 */
  	static const u8 codes[] = {
8c1592d68   Eric Dumazet   filter: cleanup c...
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
  		[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,
  		[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,
  		[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 ...
488
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  	int pc;
1b93ae64c   David S. Miller   [NET]: Validate s...
490
  	if (flen == 0 || flen > BPF_MAXINSNS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
493
494
  		return -EINVAL;
  
  	/* check the filter code now */
  	for (pc = 0; pc < flen; pc++) {
cba328fc5   Tetsuo Handa   filter: Optimize ...
495
496
  		struct sock_filter *ftest = &filter[pc];
  		u16 code = ftest->code;
936998630   Kris Katterjohn   [NET]: More instr...
497

cba328fc5   Tetsuo Handa   filter: Optimize ...
498
499
500
  		if (code >= ARRAY_SIZE(codes))
  			return -EINVAL;
  		code = codes[code];
8c1592d68   Eric Dumazet   filter: cleanup c...
501
  		if (!code)
cba328fc5   Tetsuo Handa   filter: Optimize ...
502
  			return -EINVAL;
936998630   Kris Katterjohn   [NET]: More instr...
503
  		/* Some instructions need special checks */
cba328fc5   Tetsuo Handa   filter: Optimize ...
504
505
  		switch (code) {
  		case BPF_S_ALU_DIV_K:
936998630   Kris Katterjohn   [NET]: More instr...
506
507
  			/* check for division by zero */
  			if (ftest->k == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
  				return -EINVAL;
c26aed40f   Eric Dumazet   filter: use recip...
509
  			ftest->k = reciprocal_value(ftest->k);
936998630   Kris Katterjohn   [NET]: More instr...
510
  			break;
cba328fc5   Tetsuo Handa   filter: Optimize ...
511
512
513
514
515
  		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...
516
517
518
  			if (ftest->k >= BPF_MEMWORDS)
  				return -EINVAL;
  			break;
cba328fc5   Tetsuo Handa   filter: Optimize ...
519
  		case BPF_S_JMP_JA:
936998630   Kris Katterjohn   [NET]: More instr...
520
521
522
523
524
525
526
  			/*
  			 * Note, the large ftest->k might cause loops.
  			 * Compare this with conditional jumps below,
  			 * where offsets are limited. --ANK (981016)
  			 */
  			if (ftest->k >= (unsigned)(flen-pc-1))
  				return -EINVAL;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
527
  			break;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
528
529
530
531
532
533
534
535
  		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 ...
536
  			/* for conditionals both must be safe */
e35bedf36   Kris Katterjohn   [NET]: Fix whites...
537
  			if (pc + ftest->jt + 1 >= flen ||
936998630   Kris Katterjohn   [NET]: More instr...
538
539
  			    pc + ftest->jf + 1 >= flen)
  				return -EINVAL;
cba328fc5   Tetsuo Handa   filter: Optimize ...
540
  			break;
12b16dadb   Eric Dumazet   filter: optimize ...
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
  		case BPF_S_LD_W_ABS:
  		case BPF_S_LD_H_ABS:
  		case BPF_S_LD_B_ABS:
  #define ANCILLARY(CODE) case SKF_AD_OFF + SKF_AD_##CODE:	\
  				code = BPF_S_ANC_##CODE;	\
  				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);
  			}
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
559
  		}
cba328fc5   Tetsuo Handa   filter: Optimize ...
560
  		ftest->code = code;
01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
561
  	}
936998630   Kris Katterjohn   [NET]: More instr...
562

01f2f3f6e   Hagen Paul Pfeifer   net: optimize Ber...
563
564
565
566
  	/* 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...
567
  		return check_load_and_stores(filter, flen);
cba328fc5   Tetsuo Handa   filter: Optimize ...
568
569
  	}
  	return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
  }
b715631fa   Stephen Hemminger   socket: sk_filter...
571
  EXPORT_SYMBOL(sk_chk_filter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
573
  
  /**
46bcf14f4   Eric Dumazet   filter: fix sk_fi...
574
   * 	sk_filter_release_rcu - Release a socket filter by rcu_head
47e958eac   Pavel Emelyanov   [NET]: Fix the ra...
575
576
   *	@rcu: rcu_head that contains the sk_filter to free
   */
46bcf14f4   Eric Dumazet   filter: fix sk_fi...
577
  void sk_filter_release_rcu(struct rcu_head *rcu)
47e958eac   Pavel Emelyanov   [NET]: Fix the ra...
578
579
  {
  	struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu);
0a14842f5   Eric Dumazet   net: filter: Just...
580
  	bpf_jit_free(fp);
46bcf14f4   Eric Dumazet   filter: fix sk_fi...
581
  	kfree(fp);
47e958eac   Pavel Emelyanov   [NET]: Fix the ra...
582
  }
46bcf14f4   Eric Dumazet   filter: fix sk_fi...
583
  EXPORT_SYMBOL(sk_filter_release_rcu);
47e958eac   Pavel Emelyanov   [NET]: Fix the ra...
584
585
  
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
587
588
589
590
591
592
593
594
595
596
   *	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...
597
  	struct sk_filter *fp, *old_fp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
599
600
601
  	unsigned int fsize = sizeof(struct sock_filter) * fprog->len;
  	int err;
  
  	/* Make sure new filter is there and in the right amounts. */
e35bedf36   Kris Katterjohn   [NET]: Fix whites...
602
603
  	if (fprog->filter == NULL)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
605
606
607
608
  
  	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...
609
  		sock_kfree_s(sk, fp, fsize+sizeof(*fp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
611
612
613
614
  		return -EFAULT;
  	}
  
  	atomic_set(&fp->refcnt, 1);
  	fp->len = fprog->len;
0a14842f5   Eric Dumazet   net: filter: Just...
615
  	fp->bpf_func = sk_run_filter;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
617
  
  	err = sk_chk_filter(fp->insns, fp->len);
d3904b739   Pavel Emelyanov   [NET]: Cleanup th...
618
619
620
  	if (err) {
  		sk_filter_uncharge(sk, fp);
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
  	}
0a14842f5   Eric Dumazet   net: filter: Just...
622
  	bpf_jit_compile(fp);
f91ff5b9f   Eric Dumazet   net: sk_{detach|a...
623
624
  	old_fp = rcu_dereference_protected(sk->sk_filter,
  					   sock_owned_by_user(sk));
d3904b739   Pavel Emelyanov   [NET]: Cleanup th...
625
  	rcu_assign_pointer(sk->sk_filter, fp);
d3904b739   Pavel Emelyanov   [NET]: Cleanup th...
626

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

55b333253   Pavel Emelyanov   [NET]: Introduce ...
633
634
635
636
  int sk_detach_filter(struct sock *sk)
  {
  	int ret = -ENOENT;
  	struct sk_filter *filter;
f91ff5b9f   Eric Dumazet   net: sk_{detach|a...
637
638
  	filter = rcu_dereference_protected(sk->sk_filter,
  					   sock_owned_by_user(sk));
55b333253   Pavel Emelyanov   [NET]: Introduce ...
639
  	if (filter) {
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
640
  		RCU_INIT_POINTER(sk->sk_filter, NULL);
46bcf14f4   Eric Dumazet   filter: fix sk_fi...
641
  		sk_filter_uncharge(sk, filter);
55b333253   Pavel Emelyanov   [NET]: Introduce ...
642
643
  		ret = 0;
  	}
55b333253   Pavel Emelyanov   [NET]: Introduce ...
644
645
  	return ret;
  }
5ff3f0736   Michael S. Tsirkin   net: export attac...
646
  EXPORT_SYMBOL_GPL(sk_detach_filter);