Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * Packet matching code.
4 : : *
5 : : * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
6 : : * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
7 : : * Copyright (C) 2006-2010 Patrick McHardy <kaber@trash.net>
8 : : */
9 : : #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10 : : #include <linux/cache.h>
11 : : #include <linux/capability.h>
12 : : #include <linux/skbuff.h>
13 : : #include <linux/kmod.h>
14 : : #include <linux/vmalloc.h>
15 : : #include <linux/netdevice.h>
16 : : #include <linux/module.h>
17 : : #include <linux/icmp.h>
18 : : #include <net/ip.h>
19 : : #include <net/compat.h>
20 : : #include <linux/uaccess.h>
21 : : #include <linux/mutex.h>
22 : : #include <linux/proc_fs.h>
23 : : #include <linux/err.h>
24 : : #include <linux/cpumask.h>
25 : :
26 : : #include <linux/netfilter/x_tables.h>
27 : : #include <linux/netfilter_ipv4/ip_tables.h>
28 : : #include <net/netfilter/nf_log.h>
29 : : #include "../../netfilter/xt_repldata.h"
30 : :
31 : : MODULE_LICENSE("GPL");
32 : : MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
33 : : MODULE_DESCRIPTION("IPv4 packet filter");
34 : : MODULE_ALIAS("ipt_icmp");
35 : :
36 : 0 : void *ipt_alloc_initial_table(const struct xt_table *info)
37 : : {
38 : 0 : return xt_alloc_initial_table(ipt, IPT);
39 : : }
40 : : EXPORT_SYMBOL_GPL(ipt_alloc_initial_table);
41 : :
42 : : /* Returns whether matches rule or not. */
43 : : /* Performance critical - called for every packet */
44 : : static inline bool
45 : 0 : ip_packet_match(const struct iphdr *ip,
46 : : const char *indev,
47 : : const char *outdev,
48 : : const struct ipt_ip *ipinfo,
49 : : int isfrag)
50 : : {
51 : : unsigned long ret;
52 : :
53 : 0 : if (NF_INVF(ipinfo, IPT_INV_SRCIP,
54 : 0 : (ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) ||
55 : 0 : NF_INVF(ipinfo, IPT_INV_DSTIP,
56 : : (ip->daddr & ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr))
57 : : return false;
58 : :
59 : 0 : ret = ifname_compare_aligned(indev, ipinfo->iniface, ipinfo->iniface_mask);
60 : :
61 : 0 : if (NF_INVF(ipinfo, IPT_INV_VIA_IN, ret != 0))
62 : : return false;
63 : :
64 : 0 : ret = ifname_compare_aligned(outdev, ipinfo->outiface, ipinfo->outiface_mask);
65 : :
66 : 0 : if (NF_INVF(ipinfo, IPT_INV_VIA_OUT, ret != 0))
67 : : return false;
68 : :
69 : : /* Check specific protocol */
70 : 0 : if (ipinfo->proto &&
71 : 0 : NF_INVF(ipinfo, IPT_INV_PROTO, ip->protocol != ipinfo->proto))
72 : : return false;
73 : :
74 : : /* If we have a fragment rule but the packet is not a fragment
75 : : * then we return zero */
76 : 0 : if (NF_INVF(ipinfo, IPT_INV_FRAG,
77 : : (ipinfo->flags & IPT_F_FRAG) && !isfrag))
78 : : return false;
79 : :
80 : 0 : return true;
81 : : }
82 : :
83 : : static bool
84 : : ip_checkentry(const struct ipt_ip *ip)
85 : : {
86 : 0 : if (ip->flags & ~IPT_F_MASK)
87 : : return false;
88 : 0 : if (ip->invflags & ~IPT_INV_MASK)
89 : : return false;
90 : : return true;
91 : : }
92 : :
93 : : static unsigned int
94 : 0 : ipt_error(struct sk_buff *skb, const struct xt_action_param *par)
95 : : {
96 : 0 : net_info_ratelimited("error: `%s'\n", (const char *)par->targinfo);
97 : :
98 : 0 : return NF_DROP;
99 : : }
100 : :
101 : : /* Performance critical */
102 : : static inline struct ipt_entry *
103 : : get_entry(const void *base, unsigned int offset)
104 : : {
105 : 0 : return (struct ipt_entry *)(base + offset);
106 : : }
107 : :
108 : : /* All zeroes == unconditional rule. */
109 : : /* Mildly perf critical (only if packet tracing is on) */
110 : 0 : static inline bool unconditional(const struct ipt_entry *e)
111 : : {
112 : : static const struct ipt_ip uncond;
113 : :
114 : 0 : return e->target_offset == sizeof(struct ipt_entry) &&
115 : 0 : memcmp(&e->ip, &uncond, sizeof(uncond)) == 0;
116 : : }
117 : :
118 : : /* for const-correctness */
119 : : static inline const struct xt_entry_target *
120 : : ipt_get_target_c(const struct ipt_entry *e)
121 : : {
122 : : return ipt_get_target((struct ipt_entry *)e);
123 : : }
124 : :
125 : : #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
126 : : static const char *const hooknames[] = {
127 : : [NF_INET_PRE_ROUTING] = "PREROUTING",
128 : : [NF_INET_LOCAL_IN] = "INPUT",
129 : : [NF_INET_FORWARD] = "FORWARD",
130 : : [NF_INET_LOCAL_OUT] = "OUTPUT",
131 : : [NF_INET_POST_ROUTING] = "POSTROUTING",
132 : : };
133 : :
134 : : enum nf_ip_trace_comments {
135 : : NF_IP_TRACE_COMMENT_RULE,
136 : : NF_IP_TRACE_COMMENT_RETURN,
137 : : NF_IP_TRACE_COMMENT_POLICY,
138 : : };
139 : :
140 : : static const char *const comments[] = {
141 : : [NF_IP_TRACE_COMMENT_RULE] = "rule",
142 : : [NF_IP_TRACE_COMMENT_RETURN] = "return",
143 : : [NF_IP_TRACE_COMMENT_POLICY] = "policy",
144 : : };
145 : :
146 : : static const struct nf_loginfo trace_loginfo = {
147 : : .type = NF_LOG_TYPE_LOG,
148 : : .u = {
149 : : .log = {
150 : : .level = 4,
151 : : .logflags = NF_LOG_DEFAULT_MASK,
152 : : },
153 : : },
154 : : };
155 : :
156 : : /* Mildly perf critical (only if packet tracing is on) */
157 : : static inline int
158 : 0 : get_chainname_rulenum(const struct ipt_entry *s, const struct ipt_entry *e,
159 : : const char *hookname, const char **chainname,
160 : : const char **comment, unsigned int *rulenum)
161 : : {
162 : : const struct xt_standard_target *t = (void *)ipt_get_target_c(s);
163 : :
164 : 0 : if (strcmp(t->target.u.kernel.target->name, XT_ERROR_TARGET) == 0) {
165 : : /* Head of user chain: ERROR target with chainname */
166 : 0 : *chainname = t->target.data;
167 : 0 : (*rulenum) = 0;
168 : 0 : } else if (s == e) {
169 : 0 : (*rulenum)++;
170 : :
171 : 0 : if (unconditional(s) &&
172 : 0 : strcmp(t->target.u.kernel.target->name,
173 : 0 : XT_STANDARD_TARGET) == 0 &&
174 : 0 : t->verdict < 0) {
175 : : /* Tail of chains: STANDARD target (return/policy) */
176 : 0 : *comment = *chainname == hookname
177 : : ? comments[NF_IP_TRACE_COMMENT_POLICY]
178 : 0 : : comments[NF_IP_TRACE_COMMENT_RETURN];
179 : : }
180 : : return 1;
181 : : } else
182 : 0 : (*rulenum)++;
183 : :
184 : : return 0;
185 : : }
186 : :
187 : 0 : static void trace_packet(struct net *net,
188 : : const struct sk_buff *skb,
189 : : unsigned int hook,
190 : : const struct net_device *in,
191 : : const struct net_device *out,
192 : : const char *tablename,
193 : : const struct xt_table_info *private,
194 : : const struct ipt_entry *e)
195 : : {
196 : : const struct ipt_entry *root;
197 : : const char *hookname, *chainname, *comment;
198 : : const struct ipt_entry *iter;
199 : 0 : unsigned int rulenum = 0;
200 : :
201 : 0 : root = get_entry(private->entries, private->hook_entry[hook]);
202 : :
203 : 0 : hookname = chainname = hooknames[hook];
204 : 0 : comment = comments[NF_IP_TRACE_COMMENT_RULE];
205 : :
206 : 0 : xt_entry_foreach(iter, root, private->size - private->hook_entry[hook])
207 : 0 : if (get_chainname_rulenum(iter, e, hookname,
208 : : &chainname, &comment, &rulenum) != 0)
209 : : break;
210 : :
211 : 0 : nf_log_trace(net, AF_INET, hook, skb, in, out, &trace_loginfo,
212 : : "TRACE: %s:%s:%s:%u ",
213 : : tablename, chainname, comment, rulenum);
214 : 0 : }
215 : : #endif
216 : :
217 : : static inline
218 : : struct ipt_entry *ipt_next_entry(const struct ipt_entry *entry)
219 : : {
220 : 0 : return (void *)entry + entry->next_offset;
221 : : }
222 : :
223 : : /* Returns one of the generic firewall policies, like NF_ACCEPT. */
224 : : unsigned int
225 : 0 : ipt_do_table(struct sk_buff *skb,
226 : : const struct nf_hook_state *state,
227 : : struct xt_table *table)
228 : : {
229 : 0 : unsigned int hook = state->hook;
230 : : static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
231 : : const struct iphdr *ip;
232 : : /* Initializing verdict to NF_DROP keeps gcc happy. */
233 : : unsigned int verdict = NF_DROP;
234 : : const char *indev, *outdev;
235 : : const void *table_base;
236 : : struct ipt_entry *e, **jumpstack;
237 : : unsigned int stackidx, cpu;
238 : : const struct xt_table_info *private;
239 : : struct xt_action_param acpar;
240 : : unsigned int addend;
241 : :
242 : : /* Initialization */
243 : : stackidx = 0;
244 : : ip = ip_hdr(skb);
245 : 0 : indev = state->in ? state->in->name : nulldevname;
246 : 0 : outdev = state->out ? state->out->name : nulldevname;
247 : : /* We handle fragments by dealing with the first fragment as
248 : : * if it was a normal packet. All other fragments are treated
249 : : * normally, except that they will NEVER match rules that ask
250 : : * things we don't know, ie. tcp syn flag or ports). If the
251 : : * rule is also a fragment-specific rule, non-fragments won't
252 : : * match it. */
253 : 0 : acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
254 : 0 : acpar.thoff = ip_hdrlen(skb);
255 : 0 : acpar.hotdrop = false;
256 : 0 : acpar.state = state;
257 : :
258 : 0 : WARN_ON(!(table->valid_hooks & (1 << hook)));
259 : : local_bh_disable();
260 : : addend = xt_write_recseq_begin();
261 : 0 : private = READ_ONCE(table->private); /* Address dependency. */
262 : 0 : cpu = smp_processor_id();
263 : 0 : table_base = private->entries;
264 : 0 : jumpstack = (struct ipt_entry **)private->jumpstack[cpu];
265 : :
266 : : /* Switch to alternate jumpstack if we're being invoked via TEE.
267 : : * TEE issues XT_CONTINUE verdict on original skb so we must not
268 : : * clobber the jumpstack.
269 : : *
270 : : * For recursion via REJECT or SYNPROXY the stack will be clobbered
271 : : * but it is no problem since absolute verdict is issued by these.
272 : : */
273 : 0 : if (static_key_false(&xt_tee_enabled))
274 : 0 : jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated);
275 : :
276 : 0 : e = get_entry(table_base, private->hook_entry[hook]);
277 : :
278 : : do {
279 : : const struct xt_entry_target *t;
280 : : const struct xt_entry_match *ematch;
281 : : struct xt_counters *counter;
282 : :
283 : 0 : WARN_ON(!e);
284 : 0 : if (!ip_packet_match(ip, indev, outdev,
285 : 0 : &e->ip, acpar.fragoff)) {
286 : : no_match:
287 : : e = ipt_next_entry(e);
288 : 0 : continue;
289 : : }
290 : :
291 : 0 : xt_ematch_foreach(ematch, e) {
292 : 0 : acpar.match = ematch->u.kernel.match;
293 : 0 : acpar.matchinfo = ematch->data;
294 : 0 : if (!acpar.match->match(skb, &acpar))
295 : : goto no_match;
296 : : }
297 : :
298 : 0 : counter = xt_get_this_cpu_counter(&e->counters);
299 : 0 : ADD_COUNTER(*counter, skb->len, 1);
300 : :
301 : : t = ipt_get_target_c(e);
302 : 0 : WARN_ON(!t->u.kernel.target);
303 : :
304 : : #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
305 : : /* The packet is traced: log it */
306 : 0 : if (unlikely(skb->nf_trace))
307 : 0 : trace_packet(state->net, skb, hook, state->in,
308 : 0 : state->out, table->name, private, e);
309 : : #endif
310 : : /* Standard target? */
311 : 0 : if (!t->u.kernel.target->target) {
312 : : int v;
313 : :
314 : 0 : v = ((struct xt_standard_target *)t)->verdict;
315 : 0 : if (v < 0) {
316 : : /* Pop from stack? */
317 : 0 : if (v != XT_RETURN) {
318 : 0 : verdict = (unsigned int)(-v) - 1;
319 : 0 : break;
320 : : }
321 : 0 : if (stackidx == 0) {
322 : 0 : e = get_entry(table_base,
323 : : private->underflow[hook]);
324 : : } else {
325 : 0 : e = jumpstack[--stackidx];
326 : : e = ipt_next_entry(e);
327 : : }
328 : 0 : continue;
329 : : }
330 : 0 : if (table_base + v != ipt_next_entry(e) &&
331 : 0 : !(e->ip.flags & IPT_F_GOTO)) {
332 : 0 : if (unlikely(stackidx >= private->stacksize)) {
333 : : verdict = NF_DROP;
334 : : break;
335 : : }
336 : 0 : jumpstack[stackidx++] = e;
337 : : }
338 : :
339 : : e = get_entry(table_base, v);
340 : 0 : continue;
341 : : }
342 : :
343 : 0 : acpar.target = t->u.kernel.target;
344 : 0 : acpar.targinfo = t->data;
345 : :
346 : 0 : verdict = t->u.kernel.target->target(skb, &acpar);
347 : 0 : if (verdict == XT_CONTINUE) {
348 : : /* Target might have changed stuff. */
349 : : ip = ip_hdr(skb);
350 : : e = ipt_next_entry(e);
351 : : } else {
352 : : /* Verdict */
353 : : break;
354 : : }
355 : 0 : } while (!acpar.hotdrop);
356 : :
357 : : xt_write_recseq_end(addend);
358 : : local_bh_enable();
359 : :
360 : 0 : if (acpar.hotdrop)
361 : : return NF_DROP;
362 : 0 : else return verdict;
363 : : }
364 : :
365 : : /* Figures out from what hook each rule can be called: returns 0 if
366 : : there are loops. Puts hook bitmask in comefrom. */
367 : : static int
368 : 0 : mark_source_chains(const struct xt_table_info *newinfo,
369 : : unsigned int valid_hooks, void *entry0,
370 : : unsigned int *offsets)
371 : : {
372 : : unsigned int hook;
373 : :
374 : : /* No recursion; use packet counter to save back ptrs (reset
375 : : to 0 as we leave), and comefrom to save source hook bitmask */
376 : 0 : for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
377 : 0 : unsigned int pos = newinfo->hook_entry[hook];
378 : 0 : struct ipt_entry *e = entry0 + pos;
379 : :
380 : 0 : if (!(valid_hooks & (1 << hook)))
381 : 0 : continue;
382 : :
383 : : /* Set initial back pointer. */
384 : 0 : e->counters.pcnt = pos;
385 : :
386 : : for (;;) {
387 : : const struct xt_standard_target *t
388 : : = (void *)ipt_get_target_c(e);
389 : 0 : int visited = e->comefrom & (1 << hook);
390 : :
391 : 0 : if (e->comefrom & (1 << NF_INET_NUMHOOKS))
392 : : return 0;
393 : :
394 : 0 : e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
395 : :
396 : : /* Unconditional return/END. */
397 : 0 : if ((unconditional(e) &&
398 : : (strcmp(t->target.u.user.name,
399 : 0 : XT_STANDARD_TARGET) == 0) &&
400 : 0 : t->verdict < 0) || visited) {
401 : : unsigned int oldpos, size;
402 : :
403 : : /* Return: backtrack through the last
404 : : big jump. */
405 : : do {
406 : 0 : e->comefrom ^= (1<<NF_INET_NUMHOOKS);
407 : : oldpos = pos;
408 : 0 : pos = e->counters.pcnt;
409 : 0 : e->counters.pcnt = 0;
410 : :
411 : : /* We're at the start. */
412 : 0 : if (pos == oldpos)
413 : : goto next;
414 : :
415 : 0 : e = entry0 + pos;
416 : 0 : } while (oldpos == pos + e->next_offset);
417 : :
418 : : /* Move along one */
419 : : size = e->next_offset;
420 : 0 : e = entry0 + pos + size;
421 : 0 : if (pos + size >= newinfo->size)
422 : : return 0;
423 : 0 : e->counters.pcnt = pos;
424 : 0 : pos += size;
425 : : } else {
426 : 0 : int newpos = t->verdict;
427 : :
428 : 0 : if (strcmp(t->target.u.user.name,
429 : 0 : XT_STANDARD_TARGET) == 0 &&
430 : : newpos >= 0) {
431 : : /* This a jump; chase it. */
432 : 0 : if (!xt_find_jump_offset(offsets, newpos,
433 : : newinfo->number))
434 : : return 0;
435 : : } else {
436 : : /* ... this is a fallthru */
437 : 0 : newpos = pos + e->next_offset;
438 : 0 : if (newpos >= newinfo->size)
439 : : return 0;
440 : : }
441 : 0 : e = entry0 + newpos;
442 : 0 : e->counters.pcnt = pos;
443 : : pos = newpos;
444 : : }
445 : : }
446 : : next: ;
447 : : }
448 : : return 1;
449 : : }
450 : :
451 : 0 : static void cleanup_match(struct xt_entry_match *m, struct net *net)
452 : : {
453 : : struct xt_mtdtor_param par;
454 : :
455 : 0 : par.net = net;
456 : 0 : par.match = m->u.kernel.match;
457 : 0 : par.matchinfo = m->data;
458 : 0 : par.family = NFPROTO_IPV4;
459 : 0 : if (par.match->destroy != NULL)
460 : 0 : par.match->destroy(&par);
461 : 0 : module_put(par.match->me);
462 : 0 : }
463 : :
464 : : static int
465 : 0 : check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
466 : : {
467 : 0 : const struct ipt_ip *ip = par->entryinfo;
468 : :
469 : 0 : par->match = m->u.kernel.match;
470 : 0 : par->matchinfo = m->data;
471 : :
472 : 0 : return xt_check_match(par, m->u.match_size - sizeof(*m),
473 : 0 : ip->proto, ip->invflags & IPT_INV_PROTO);
474 : : }
475 : :
476 : : static int
477 : 0 : find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
478 : : {
479 : : struct xt_match *match;
480 : : int ret;
481 : :
482 : 0 : match = xt_request_find_match(NFPROTO_IPV4, m->u.user.name,
483 : : m->u.user.revision);
484 : 0 : if (IS_ERR(match))
485 : 0 : return PTR_ERR(match);
486 : 0 : m->u.kernel.match = match;
487 : :
488 : 0 : ret = check_match(m, par);
489 : 0 : if (ret)
490 : : goto err;
491 : :
492 : : return 0;
493 : : err:
494 : 0 : module_put(m->u.kernel.match->me);
495 : 0 : return ret;
496 : : }
497 : :
498 : 0 : static int check_target(struct ipt_entry *e, struct net *net, const char *name)
499 : : {
500 : : struct xt_entry_target *t = ipt_get_target(e);
501 : 0 : struct xt_tgchk_param par = {
502 : : .net = net,
503 : : .table = name,
504 : : .entryinfo = e,
505 : 0 : .target = t->u.kernel.target,
506 : 0 : .targinfo = t->data,
507 : 0 : .hook_mask = e->comefrom,
508 : : .family = NFPROTO_IPV4,
509 : : };
510 : :
511 : 0 : return xt_check_target(&par, t->u.target_size - sizeof(*t),
512 : 0 : e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
513 : : }
514 : :
515 : : static int
516 : 0 : find_check_entry(struct ipt_entry *e, struct net *net, const char *name,
517 : : unsigned int size,
518 : : struct xt_percpu_counter_alloc_state *alloc_state)
519 : : {
520 : : struct xt_entry_target *t;
521 : : struct xt_target *target;
522 : : int ret;
523 : : unsigned int j;
524 : : struct xt_mtchk_param mtpar;
525 : : struct xt_entry_match *ematch;
526 : :
527 : 0 : if (!xt_percpu_counter_alloc(alloc_state, &e->counters))
528 : : return -ENOMEM;
529 : :
530 : : j = 0;
531 : 0 : memset(&mtpar, 0, sizeof(mtpar));
532 : 0 : mtpar.net = net;
533 : 0 : mtpar.table = name;
534 : 0 : mtpar.entryinfo = &e->ip;
535 : 0 : mtpar.hook_mask = e->comefrom;
536 : 0 : mtpar.family = NFPROTO_IPV4;
537 : 0 : xt_ematch_foreach(ematch, e) {
538 : 0 : ret = find_check_match(ematch, &mtpar);
539 : 0 : if (ret != 0)
540 : : goto cleanup_matches;
541 : 0 : ++j;
542 : : }
543 : :
544 : : t = ipt_get_target(e);
545 : 0 : target = xt_request_find_target(NFPROTO_IPV4, t->u.user.name,
546 : : t->u.user.revision);
547 : 0 : if (IS_ERR(target)) {
548 : : ret = PTR_ERR(target);
549 : 0 : goto cleanup_matches;
550 : : }
551 : 0 : t->u.kernel.target = target;
552 : :
553 : 0 : ret = check_target(e, net, name);
554 : 0 : if (ret)
555 : : goto err;
556 : :
557 : : return 0;
558 : : err:
559 : 0 : module_put(t->u.kernel.target->me);
560 : : cleanup_matches:
561 : 0 : xt_ematch_foreach(ematch, e) {
562 : 0 : if (j-- == 0)
563 : : break;
564 : 0 : cleanup_match(ematch, net);
565 : : }
566 : :
567 : 0 : xt_percpu_counter_free(&e->counters);
568 : :
569 : 0 : return ret;
570 : : }
571 : :
572 : 0 : static bool check_underflow(const struct ipt_entry *e)
573 : : {
574 : : const struct xt_entry_target *t;
575 : : unsigned int verdict;
576 : :
577 : 0 : if (!unconditional(e))
578 : : return false;
579 : : t = ipt_get_target_c(e);
580 : 0 : if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
581 : : return false;
582 : 0 : verdict = ((struct xt_standard_target *)t)->verdict;
583 : : verdict = -verdict - 1;
584 : 0 : return verdict == NF_DROP || verdict == NF_ACCEPT;
585 : : }
586 : :
587 : : static int
588 : 0 : check_entry_size_and_hooks(struct ipt_entry *e,
589 : : struct xt_table_info *newinfo,
590 : : const unsigned char *base,
591 : : const unsigned char *limit,
592 : : const unsigned int *hook_entries,
593 : : const unsigned int *underflows,
594 : : unsigned int valid_hooks)
595 : : {
596 : : unsigned int h;
597 : : int err;
598 : :
599 : 0 : if ((unsigned long)e % __alignof__(struct ipt_entry) != 0 ||
600 : 0 : (unsigned char *)e + sizeof(struct ipt_entry) >= limit ||
601 : 0 : (unsigned char *)e + e->next_offset > limit)
602 : : return -EINVAL;
603 : :
604 : 0 : if (e->next_offset
605 : : < sizeof(struct ipt_entry) + sizeof(struct xt_entry_target))
606 : : return -EINVAL;
607 : :
608 : 0 : if (!ip_checkentry(&e->ip))
609 : : return -EINVAL;
610 : :
611 : 0 : err = xt_check_entry_offsets(e, e->elems, e->target_offset,
612 : : e->next_offset);
613 : 0 : if (err)
614 : : return err;
615 : :
616 : : /* Check hooks & underflows */
617 : 0 : for (h = 0; h < NF_INET_NUMHOOKS; h++) {
618 : 0 : if (!(valid_hooks & (1 << h)))
619 : 0 : continue;
620 : 0 : if ((unsigned char *)e - base == hook_entries[h])
621 : 0 : newinfo->hook_entry[h] = hook_entries[h];
622 : 0 : if ((unsigned char *)e - base == underflows[h]) {
623 : 0 : if (!check_underflow(e))
624 : : return -EINVAL;
625 : :
626 : 0 : newinfo->underflow[h] = underflows[h];
627 : : }
628 : : }
629 : :
630 : : /* Clear counters and comefrom */
631 : 0 : e->counters = ((struct xt_counters) { 0, 0 });
632 : 0 : e->comefrom = 0;
633 : 0 : return 0;
634 : : }
635 : :
636 : : static void
637 : 0 : cleanup_entry(struct ipt_entry *e, struct net *net)
638 : : {
639 : : struct xt_tgdtor_param par;
640 : : struct xt_entry_target *t;
641 : : struct xt_entry_match *ematch;
642 : :
643 : : /* Cleanup all matches */
644 : 0 : xt_ematch_foreach(ematch, e)
645 : 0 : cleanup_match(ematch, net);
646 : : t = ipt_get_target(e);
647 : :
648 : 0 : par.net = net;
649 : 0 : par.target = t->u.kernel.target;
650 : 0 : par.targinfo = t->data;
651 : 0 : par.family = NFPROTO_IPV4;
652 : 0 : if (par.target->destroy != NULL)
653 : 0 : par.target->destroy(&par);
654 : 0 : module_put(par.target->me);
655 : 0 : xt_percpu_counter_free(&e->counters);
656 : 0 : }
657 : :
658 : : /* Checks and translates the user-supplied table segment (held in
659 : : newinfo) */
660 : : static int
661 : 0 : translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
662 : : const struct ipt_replace *repl)
663 : : {
664 : 0 : struct xt_percpu_counter_alloc_state alloc_state = { 0 };
665 : : struct ipt_entry *iter;
666 : : unsigned int *offsets;
667 : : unsigned int i;
668 : : int ret = 0;
669 : :
670 : 0 : newinfo->size = repl->size;
671 : 0 : newinfo->number = repl->num_entries;
672 : :
673 : : /* Init all hooks to impossible value. */
674 : 0 : for (i = 0; i < NF_INET_NUMHOOKS; i++) {
675 : 0 : newinfo->hook_entry[i] = 0xFFFFFFFF;
676 : 0 : newinfo->underflow[i] = 0xFFFFFFFF;
677 : : }
678 : :
679 : 0 : offsets = xt_alloc_entry_offsets(newinfo->number);
680 : 0 : if (!offsets)
681 : : return -ENOMEM;
682 : : i = 0;
683 : : /* Walk through entries, checking offsets. */
684 : 0 : xt_entry_foreach(iter, entry0, newinfo->size) {
685 : 0 : ret = check_entry_size_and_hooks(iter, newinfo, entry0,
686 : 0 : entry0 + repl->size,
687 : 0 : repl->hook_entry,
688 : 0 : repl->underflow,
689 : : repl->valid_hooks);
690 : 0 : if (ret != 0)
691 : : goto out_free;
692 : 0 : if (i < repl->num_entries)
693 : 0 : offsets[i] = (void *)iter - entry0;
694 : 0 : ++i;
695 : 0 : if (strcmp(ipt_get_target(iter)->u.user.name,
696 : : XT_ERROR_TARGET) == 0)
697 : 0 : ++newinfo->stacksize;
698 : : }
699 : :
700 : : ret = -EINVAL;
701 : 0 : if (i != repl->num_entries)
702 : : goto out_free;
703 : :
704 : 0 : ret = xt_check_table_hooks(newinfo, repl->valid_hooks);
705 : 0 : if (ret)
706 : : goto out_free;
707 : :
708 : 0 : if (!mark_source_chains(newinfo, repl->valid_hooks, entry0, offsets)) {
709 : : ret = -ELOOP;
710 : : goto out_free;
711 : : }
712 : 0 : kvfree(offsets);
713 : :
714 : : /* Finally, each sanity check must pass */
715 : : i = 0;
716 : 0 : xt_entry_foreach(iter, entry0, newinfo->size) {
717 : 0 : ret = find_check_entry(iter, net, repl->name, repl->size,
718 : : &alloc_state);
719 : 0 : if (ret != 0)
720 : : break;
721 : 0 : ++i;
722 : : }
723 : :
724 : 0 : if (ret != 0) {
725 : 0 : xt_entry_foreach(iter, entry0, newinfo->size) {
726 : 0 : if (i-- == 0)
727 : : break;
728 : 0 : cleanup_entry(iter, net);
729 : : }
730 : : return ret;
731 : : }
732 : :
733 : : return ret;
734 : : out_free:
735 : 0 : kvfree(offsets);
736 : 0 : return ret;
737 : : }
738 : :
739 : : static void
740 : 0 : get_counters(const struct xt_table_info *t,
741 : : struct xt_counters counters[])
742 : : {
743 : : struct ipt_entry *iter;
744 : : unsigned int cpu;
745 : : unsigned int i;
746 : :
747 : 0 : for_each_possible_cpu(cpu) {
748 : 0 : seqcount_t *s = &per_cpu(xt_recseq, cpu);
749 : :
750 : : i = 0;
751 : 0 : xt_entry_foreach(iter, t->entries, t->size) {
752 : : struct xt_counters *tmp;
753 : : u64 bcnt, pcnt;
754 : : unsigned int start;
755 : :
756 : 0 : tmp = xt_get_per_cpu_counter(&iter->counters, cpu);
757 : : do {
758 : : start = read_seqcount_begin(s);
759 : 0 : bcnt = tmp->bcnt;
760 : 0 : pcnt = tmp->pcnt;
761 : 0 : } while (read_seqcount_retry(s, start));
762 : :
763 : 0 : ADD_COUNTER(counters[i], bcnt, pcnt);
764 : 0 : ++i; /* macro does multi eval of i */
765 : 0 : cond_resched();
766 : : }
767 : : }
768 : 0 : }
769 : :
770 : 0 : static void get_old_counters(const struct xt_table_info *t,
771 : : struct xt_counters counters[])
772 : : {
773 : : struct ipt_entry *iter;
774 : : unsigned int cpu, i;
775 : :
776 : 0 : for_each_possible_cpu(cpu) {
777 : : i = 0;
778 : 0 : xt_entry_foreach(iter, t->entries, t->size) {
779 : : const struct xt_counters *tmp;
780 : :
781 : 0 : tmp = xt_get_per_cpu_counter(&iter->counters, cpu);
782 : 0 : ADD_COUNTER(counters[i], tmp->bcnt, tmp->pcnt);
783 : 0 : ++i; /* macro does multi eval of i */
784 : : }
785 : :
786 : 0 : cond_resched();
787 : : }
788 : 0 : }
789 : :
790 : 0 : static struct xt_counters *alloc_counters(const struct xt_table *table)
791 : : {
792 : : unsigned int countersize;
793 : : struct xt_counters *counters;
794 : 0 : const struct xt_table_info *private = table->private;
795 : :
796 : : /* We need atomic snapshot of counters: rest doesn't change
797 : : (other than comefrom, which userspace doesn't care
798 : : about). */
799 : 0 : countersize = sizeof(struct xt_counters) * private->number;
800 : 0 : counters = vzalloc(countersize);
801 : :
802 : 0 : if (counters == NULL)
803 : : return ERR_PTR(-ENOMEM);
804 : :
805 : 0 : get_counters(private, counters);
806 : :
807 : 0 : return counters;
808 : : }
809 : :
810 : : static int
811 : 0 : copy_entries_to_user(unsigned int total_size,
812 : : const struct xt_table *table,
813 : : void __user *userptr)
814 : : {
815 : : unsigned int off, num;
816 : : const struct ipt_entry *e;
817 : : struct xt_counters *counters;
818 : 0 : const struct xt_table_info *private = table->private;
819 : : int ret = 0;
820 : : const void *loc_cpu_entry;
821 : :
822 : 0 : counters = alloc_counters(table);
823 : 0 : if (IS_ERR(counters))
824 : 0 : return PTR_ERR(counters);
825 : :
826 : 0 : loc_cpu_entry = private->entries;
827 : :
828 : : /* FIXME: use iterator macros --RR */
829 : : /* ... then go back and fix counters and names */
830 : 0 : for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
831 : : unsigned int i;
832 : : const struct xt_entry_match *m;
833 : : const struct xt_entry_target *t;
834 : :
835 : 0 : e = loc_cpu_entry + off;
836 : 0 : if (copy_to_user(userptr + off, e, sizeof(*e))) {
837 : : ret = -EFAULT;
838 : : goto free_counters;
839 : : }
840 : 0 : if (copy_to_user(userptr + off
841 : 0 : + offsetof(struct ipt_entry, counters),
842 : 0 : &counters[num],
843 : : sizeof(counters[num])) != 0) {
844 : : ret = -EFAULT;
845 : : goto free_counters;
846 : : }
847 : :
848 : 0 : for (i = sizeof(struct ipt_entry);
849 : 0 : i < e->target_offset;
850 : 0 : i += m->u.match_size) {
851 : 0 : m = (void *)e + i;
852 : :
853 : 0 : if (xt_match_to_user(m, userptr + off + i)) {
854 : : ret = -EFAULT;
855 : : goto free_counters;
856 : : }
857 : : }
858 : :
859 : : t = ipt_get_target_c(e);
860 : 0 : if (xt_target_to_user(t, userptr + off + e->target_offset)) {
861 : : ret = -EFAULT;
862 : : goto free_counters;
863 : : }
864 : : }
865 : :
866 : : free_counters:
867 : 0 : vfree(counters);
868 : 0 : return ret;
869 : : }
870 : :
871 : : #ifdef CONFIG_COMPAT
872 : : static void compat_standard_from_user(void *dst, const void *src)
873 : : {
874 : : int v = *(compat_int_t *)src;
875 : :
876 : : if (v > 0)
877 : : v += xt_compat_calc_jump(AF_INET, v);
878 : : memcpy(dst, &v, sizeof(v));
879 : : }
880 : :
881 : : static int compat_standard_to_user(void __user *dst, const void *src)
882 : : {
883 : : compat_int_t cv = *(int *)src;
884 : :
885 : : if (cv > 0)
886 : : cv -= xt_compat_calc_jump(AF_INET, cv);
887 : : return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
888 : : }
889 : :
890 : : static int compat_calc_entry(const struct ipt_entry *e,
891 : : const struct xt_table_info *info,
892 : : const void *base, struct xt_table_info *newinfo)
893 : : {
894 : : const struct xt_entry_match *ematch;
895 : : const struct xt_entry_target *t;
896 : : unsigned int entry_offset;
897 : : int off, i, ret;
898 : :
899 : : off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
900 : : entry_offset = (void *)e - base;
901 : : xt_ematch_foreach(ematch, e)
902 : : off += xt_compat_match_offset(ematch->u.kernel.match);
903 : : t = ipt_get_target_c(e);
904 : : off += xt_compat_target_offset(t->u.kernel.target);
905 : : newinfo->size -= off;
906 : : ret = xt_compat_add_offset(AF_INET, entry_offset, off);
907 : : if (ret)
908 : : return ret;
909 : :
910 : : for (i = 0; i < NF_INET_NUMHOOKS; i++) {
911 : : if (info->hook_entry[i] &&
912 : : (e < (struct ipt_entry *)(base + info->hook_entry[i])))
913 : : newinfo->hook_entry[i] -= off;
914 : : if (info->underflow[i] &&
915 : : (e < (struct ipt_entry *)(base + info->underflow[i])))
916 : : newinfo->underflow[i] -= off;
917 : : }
918 : : return 0;
919 : : }
920 : :
921 : : static int compat_table_info(const struct xt_table_info *info,
922 : : struct xt_table_info *newinfo)
923 : : {
924 : : struct ipt_entry *iter;
925 : : const void *loc_cpu_entry;
926 : : int ret;
927 : :
928 : : if (!newinfo || !info)
929 : : return -EINVAL;
930 : :
931 : : /* we dont care about newinfo->entries */
932 : : memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
933 : : newinfo->initial_entries = 0;
934 : : loc_cpu_entry = info->entries;
935 : : ret = xt_compat_init_offsets(AF_INET, info->number);
936 : : if (ret)
937 : : return ret;
938 : : xt_entry_foreach(iter, loc_cpu_entry, info->size) {
939 : : ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
940 : : if (ret != 0)
941 : : return ret;
942 : : }
943 : : return 0;
944 : : }
945 : : #endif
946 : :
947 : 0 : static int get_info(struct net *net, void __user *user,
948 : : const int *len, int compat)
949 : : {
950 : : char name[XT_TABLE_MAXNAMELEN];
951 : : struct xt_table *t;
952 : : int ret;
953 : :
954 : 0 : if (*len != sizeof(struct ipt_getinfo))
955 : : return -EINVAL;
956 : :
957 : 0 : if (copy_from_user(name, user, sizeof(name)) != 0)
958 : : return -EFAULT;
959 : :
960 : 0 : name[XT_TABLE_MAXNAMELEN-1] = '\0';
961 : : #ifdef CONFIG_COMPAT
962 : : if (compat)
963 : : xt_compat_lock(AF_INET);
964 : : #endif
965 : 0 : t = xt_request_find_table_lock(net, AF_INET, name);
966 : 0 : if (!IS_ERR(t)) {
967 : : struct ipt_getinfo info;
968 : 0 : const struct xt_table_info *private = t->private;
969 : : #ifdef CONFIG_COMPAT
970 : : struct xt_table_info tmp;
971 : :
972 : : if (compat) {
973 : : ret = compat_table_info(private, &tmp);
974 : : xt_compat_flush_offsets(AF_INET);
975 : : private = &tmp;
976 : : }
977 : : #endif
978 : 0 : memset(&info, 0, sizeof(info));
979 : 0 : info.valid_hooks = t->valid_hooks;
980 : 0 : memcpy(info.hook_entry, private->hook_entry,
981 : : sizeof(info.hook_entry));
982 : 0 : memcpy(info.underflow, private->underflow,
983 : : sizeof(info.underflow));
984 : 0 : info.num_entries = private->number;
985 : 0 : info.size = private->size;
986 : 0 : strcpy(info.name, name);
987 : :
988 : 0 : if (copy_to_user(user, &info, *len) != 0)
989 : : ret = -EFAULT;
990 : : else
991 : : ret = 0;
992 : :
993 : 0 : xt_table_unlock(t);
994 : 0 : module_put(t->me);
995 : : } else
996 : : ret = PTR_ERR(t);
997 : : #ifdef CONFIG_COMPAT
998 : : if (compat)
999 : : xt_compat_unlock(AF_INET);
1000 : : #endif
1001 : 0 : return ret;
1002 : : }
1003 : :
1004 : : static int
1005 : 0 : get_entries(struct net *net, struct ipt_get_entries __user *uptr,
1006 : : const int *len)
1007 : : {
1008 : : int ret;
1009 : : struct ipt_get_entries get;
1010 : : struct xt_table *t;
1011 : :
1012 : 0 : if (*len < sizeof(get))
1013 : : return -EINVAL;
1014 : 0 : if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1015 : : return -EFAULT;
1016 : 0 : if (*len != sizeof(struct ipt_get_entries) + get.size)
1017 : : return -EINVAL;
1018 : 0 : get.name[sizeof(get.name) - 1] = '\0';
1019 : :
1020 : 0 : t = xt_find_table_lock(net, AF_INET, get.name);
1021 : 0 : if (!IS_ERR(t)) {
1022 : 0 : const struct xt_table_info *private = t->private;
1023 : 0 : if (get.size == private->size)
1024 : 0 : ret = copy_entries_to_user(private->size,
1025 : 0 : t, uptr->entrytable);
1026 : : else
1027 : : ret = -EAGAIN;
1028 : :
1029 : 0 : module_put(t->me);
1030 : 0 : xt_table_unlock(t);
1031 : : } else
1032 : : ret = PTR_ERR(t);
1033 : :
1034 : 0 : return ret;
1035 : : }
1036 : :
1037 : : static int
1038 : 0 : __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
1039 : : struct xt_table_info *newinfo, unsigned int num_counters,
1040 : : void __user *counters_ptr)
1041 : : {
1042 : : int ret;
1043 : : struct xt_table *t;
1044 : : struct xt_table_info *oldinfo;
1045 : : struct xt_counters *counters;
1046 : : struct ipt_entry *iter;
1047 : :
1048 : 0 : ret = 0;
1049 : 0 : counters = xt_counters_alloc(num_counters);
1050 : 0 : if (!counters) {
1051 : 0 : ret = -ENOMEM;
1052 : 0 : goto out;
1053 : : }
1054 : :
1055 : 0 : t = xt_request_find_table_lock(net, AF_INET, name);
1056 : 0 : if (IS_ERR(t)) {
1057 : 0 : ret = PTR_ERR(t);
1058 : 0 : goto free_newinfo_counters_untrans;
1059 : : }
1060 : :
1061 : : /* You lied! */
1062 : 0 : if (valid_hooks != t->valid_hooks) {
1063 : 0 : ret = -EINVAL;
1064 : 0 : goto put_module;
1065 : : }
1066 : :
1067 : 0 : oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1068 : 0 : if (!oldinfo)
1069 : : goto put_module;
1070 : :
1071 : : /* Update module usage count based on number of rules */
1072 : 0 : if ((oldinfo->number > oldinfo->initial_entries) ||
1073 : 0 : (newinfo->number <= oldinfo->initial_entries))
1074 : 0 : module_put(t->me);
1075 : 0 : if ((oldinfo->number > oldinfo->initial_entries) &&
1076 : 0 : (newinfo->number <= oldinfo->initial_entries))
1077 : 0 : module_put(t->me);
1078 : :
1079 : 0 : xt_table_unlock(t);
1080 : :
1081 : 0 : get_old_counters(oldinfo, counters);
1082 : :
1083 : : /* Decrease module usage counts and free resource */
1084 : 0 : xt_entry_foreach(iter, oldinfo->entries, oldinfo->size)
1085 : 0 : cleanup_entry(iter, net);
1086 : :
1087 : 0 : xt_free_table_info(oldinfo);
1088 : 0 : if (copy_to_user(counters_ptr, counters,
1089 : 0 : sizeof(struct xt_counters) * num_counters) != 0) {
1090 : : /* Silent error, can't fail, new table is already in place */
1091 : 0 : net_warn_ratelimited("iptables: counters copy to user failed while replacing table\n");
1092 : : }
1093 : 0 : vfree(counters);
1094 : 0 : return ret;
1095 : :
1096 : : put_module:
1097 : 0 : module_put(t->me);
1098 : 0 : xt_table_unlock(t);
1099 : : free_newinfo_counters_untrans:
1100 : 0 : vfree(counters);
1101 : : out:
1102 : 0 : return ret;
1103 : : }
1104 : :
1105 : : static int
1106 : 0 : do_replace(struct net *net, const void __user *user, unsigned int len)
1107 : : {
1108 : : int ret;
1109 : : struct ipt_replace tmp;
1110 : : struct xt_table_info *newinfo;
1111 : : void *loc_cpu_entry;
1112 : : struct ipt_entry *iter;
1113 : :
1114 : 0 : if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1115 : : return -EFAULT;
1116 : :
1117 : : /* overflow check */
1118 : 0 : if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1119 : : return -ENOMEM;
1120 : 0 : if (tmp.num_counters == 0)
1121 : : return -EINVAL;
1122 : :
1123 : 0 : tmp.name[sizeof(tmp.name)-1] = 0;
1124 : :
1125 : 0 : newinfo = xt_alloc_table_info(tmp.size);
1126 : 0 : if (!newinfo)
1127 : : return -ENOMEM;
1128 : :
1129 : 0 : loc_cpu_entry = newinfo->entries;
1130 : 0 : if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1131 : 0 : tmp.size) != 0) {
1132 : : ret = -EFAULT;
1133 : : goto free_newinfo;
1134 : : }
1135 : :
1136 : 0 : ret = translate_table(net, newinfo, loc_cpu_entry, &tmp);
1137 : 0 : if (ret != 0)
1138 : : goto free_newinfo;
1139 : :
1140 : 0 : ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1141 : 0 : tmp.num_counters, tmp.counters);
1142 : 0 : if (ret)
1143 : : goto free_newinfo_untrans;
1144 : : return 0;
1145 : :
1146 : : free_newinfo_untrans:
1147 : 0 : xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1148 : 0 : cleanup_entry(iter, net);
1149 : : free_newinfo:
1150 : 0 : xt_free_table_info(newinfo);
1151 : 0 : return ret;
1152 : : }
1153 : :
1154 : : static int
1155 : 0 : do_add_counters(struct net *net, const void __user *user,
1156 : : unsigned int len, int compat)
1157 : : {
1158 : : unsigned int i;
1159 : : struct xt_counters_info tmp;
1160 : : struct xt_counters *paddc;
1161 : : struct xt_table *t;
1162 : : const struct xt_table_info *private;
1163 : : int ret = 0;
1164 : : struct ipt_entry *iter;
1165 : : unsigned int addend;
1166 : :
1167 : 0 : paddc = xt_copy_counters_from_user(user, len, &tmp, compat);
1168 : 0 : if (IS_ERR(paddc))
1169 : 0 : return PTR_ERR(paddc);
1170 : :
1171 : 0 : t = xt_find_table_lock(net, AF_INET, tmp.name);
1172 : 0 : if (IS_ERR(t)) {
1173 : : ret = PTR_ERR(t);
1174 : 0 : goto free;
1175 : : }
1176 : :
1177 : : local_bh_disable();
1178 : 0 : private = t->private;
1179 : 0 : if (private->number != tmp.num_counters) {
1180 : : ret = -EINVAL;
1181 : : goto unlock_up_free;
1182 : : }
1183 : :
1184 : : i = 0;
1185 : : addend = xt_write_recseq_begin();
1186 : 0 : xt_entry_foreach(iter, private->entries, private->size) {
1187 : : struct xt_counters *tmp;
1188 : :
1189 : 0 : tmp = xt_get_this_cpu_counter(&iter->counters);
1190 : 0 : ADD_COUNTER(*tmp, paddc[i].bcnt, paddc[i].pcnt);
1191 : 0 : ++i;
1192 : : }
1193 : : xt_write_recseq_end(addend);
1194 : : unlock_up_free:
1195 : : local_bh_enable();
1196 : 0 : xt_table_unlock(t);
1197 : 0 : module_put(t->me);
1198 : : free:
1199 : 0 : vfree(paddc);
1200 : :
1201 : 0 : return ret;
1202 : : }
1203 : :
1204 : : #ifdef CONFIG_COMPAT
1205 : : struct compat_ipt_replace {
1206 : : char name[XT_TABLE_MAXNAMELEN];
1207 : : u32 valid_hooks;
1208 : : u32 num_entries;
1209 : : u32 size;
1210 : : u32 hook_entry[NF_INET_NUMHOOKS];
1211 : : u32 underflow[NF_INET_NUMHOOKS];
1212 : : u32 num_counters;
1213 : : compat_uptr_t counters; /* struct xt_counters * */
1214 : : struct compat_ipt_entry entries[0];
1215 : : };
1216 : :
1217 : : static int
1218 : : compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr,
1219 : : unsigned int *size, struct xt_counters *counters,
1220 : : unsigned int i)
1221 : : {
1222 : : struct xt_entry_target *t;
1223 : : struct compat_ipt_entry __user *ce;
1224 : : u_int16_t target_offset, next_offset;
1225 : : compat_uint_t origsize;
1226 : : const struct xt_entry_match *ematch;
1227 : : int ret = 0;
1228 : :
1229 : : origsize = *size;
1230 : : ce = *dstptr;
1231 : : if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 ||
1232 : : copy_to_user(&ce->counters, &counters[i],
1233 : : sizeof(counters[i])) != 0)
1234 : : return -EFAULT;
1235 : :
1236 : : *dstptr += sizeof(struct compat_ipt_entry);
1237 : : *size -= sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1238 : :
1239 : : xt_ematch_foreach(ematch, e) {
1240 : : ret = xt_compat_match_to_user(ematch, dstptr, size);
1241 : : if (ret != 0)
1242 : : return ret;
1243 : : }
1244 : : target_offset = e->target_offset - (origsize - *size);
1245 : : t = ipt_get_target(e);
1246 : : ret = xt_compat_target_to_user(t, dstptr, size);
1247 : : if (ret)
1248 : : return ret;
1249 : : next_offset = e->next_offset - (origsize - *size);
1250 : : if (put_user(target_offset, &ce->target_offset) != 0 ||
1251 : : put_user(next_offset, &ce->next_offset) != 0)
1252 : : return -EFAULT;
1253 : : return 0;
1254 : : }
1255 : :
1256 : : static int
1257 : : compat_find_calc_match(struct xt_entry_match *m,
1258 : : const struct ipt_ip *ip,
1259 : : int *size)
1260 : : {
1261 : : struct xt_match *match;
1262 : :
1263 : : match = xt_request_find_match(NFPROTO_IPV4, m->u.user.name,
1264 : : m->u.user.revision);
1265 : : if (IS_ERR(match))
1266 : : return PTR_ERR(match);
1267 : :
1268 : : m->u.kernel.match = match;
1269 : : *size += xt_compat_match_offset(match);
1270 : : return 0;
1271 : : }
1272 : :
1273 : : static void compat_release_entry(struct compat_ipt_entry *e)
1274 : : {
1275 : : struct xt_entry_target *t;
1276 : : struct xt_entry_match *ematch;
1277 : :
1278 : : /* Cleanup all matches */
1279 : : xt_ematch_foreach(ematch, e)
1280 : : module_put(ematch->u.kernel.match->me);
1281 : : t = compat_ipt_get_target(e);
1282 : : module_put(t->u.kernel.target->me);
1283 : : }
1284 : :
1285 : : static int
1286 : : check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
1287 : : struct xt_table_info *newinfo,
1288 : : unsigned int *size,
1289 : : const unsigned char *base,
1290 : : const unsigned char *limit)
1291 : : {
1292 : : struct xt_entry_match *ematch;
1293 : : struct xt_entry_target *t;
1294 : : struct xt_target *target;
1295 : : unsigned int entry_offset;
1296 : : unsigned int j;
1297 : : int ret, off;
1298 : :
1299 : : if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0 ||
1300 : : (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit ||
1301 : : (unsigned char *)e + e->next_offset > limit)
1302 : : return -EINVAL;
1303 : :
1304 : : if (e->next_offset < sizeof(struct compat_ipt_entry) +
1305 : : sizeof(struct compat_xt_entry_target))
1306 : : return -EINVAL;
1307 : :
1308 : : if (!ip_checkentry(&e->ip))
1309 : : return -EINVAL;
1310 : :
1311 : : ret = xt_compat_check_entry_offsets(e, e->elems,
1312 : : e->target_offset, e->next_offset);
1313 : : if (ret)
1314 : : return ret;
1315 : :
1316 : : off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1317 : : entry_offset = (void *)e - (void *)base;
1318 : : j = 0;
1319 : : xt_ematch_foreach(ematch, e) {
1320 : : ret = compat_find_calc_match(ematch, &e->ip, &off);
1321 : : if (ret != 0)
1322 : : goto release_matches;
1323 : : ++j;
1324 : : }
1325 : :
1326 : : t = compat_ipt_get_target(e);
1327 : : target = xt_request_find_target(NFPROTO_IPV4, t->u.user.name,
1328 : : t->u.user.revision);
1329 : : if (IS_ERR(target)) {
1330 : : ret = PTR_ERR(target);
1331 : : goto release_matches;
1332 : : }
1333 : : t->u.kernel.target = target;
1334 : :
1335 : : off += xt_compat_target_offset(target);
1336 : : *size += off;
1337 : : ret = xt_compat_add_offset(AF_INET, entry_offset, off);
1338 : : if (ret)
1339 : : goto out;
1340 : :
1341 : : return 0;
1342 : :
1343 : : out:
1344 : : module_put(t->u.kernel.target->me);
1345 : : release_matches:
1346 : : xt_ematch_foreach(ematch, e) {
1347 : : if (j-- == 0)
1348 : : break;
1349 : : module_put(ematch->u.kernel.match->me);
1350 : : }
1351 : : return ret;
1352 : : }
1353 : :
1354 : : static void
1355 : : compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr,
1356 : : unsigned int *size,
1357 : : struct xt_table_info *newinfo, unsigned char *base)
1358 : : {
1359 : : struct xt_entry_target *t;
1360 : : struct ipt_entry *de;
1361 : : unsigned int origsize;
1362 : : int h;
1363 : : struct xt_entry_match *ematch;
1364 : :
1365 : : origsize = *size;
1366 : : de = *dstptr;
1367 : : memcpy(de, e, sizeof(struct ipt_entry));
1368 : : memcpy(&de->counters, &e->counters, sizeof(e->counters));
1369 : :
1370 : : *dstptr += sizeof(struct ipt_entry);
1371 : : *size += sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
1372 : :
1373 : : xt_ematch_foreach(ematch, e)
1374 : : xt_compat_match_from_user(ematch, dstptr, size);
1375 : :
1376 : : de->target_offset = e->target_offset - (origsize - *size);
1377 : : t = compat_ipt_get_target(e);
1378 : : xt_compat_target_from_user(t, dstptr, size);
1379 : :
1380 : : de->next_offset = e->next_offset - (origsize - *size);
1381 : :
1382 : : for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1383 : : if ((unsigned char *)de - base < newinfo->hook_entry[h])
1384 : : newinfo->hook_entry[h] -= origsize - *size;
1385 : : if ((unsigned char *)de - base < newinfo->underflow[h])
1386 : : newinfo->underflow[h] -= origsize - *size;
1387 : : }
1388 : : }
1389 : :
1390 : : static int
1391 : : translate_compat_table(struct net *net,
1392 : : struct xt_table_info **pinfo,
1393 : : void **pentry0,
1394 : : const struct compat_ipt_replace *compatr)
1395 : : {
1396 : : unsigned int i, j;
1397 : : struct xt_table_info *newinfo, *info;
1398 : : void *pos, *entry0, *entry1;
1399 : : struct compat_ipt_entry *iter0;
1400 : : struct ipt_replace repl;
1401 : : unsigned int size;
1402 : : int ret;
1403 : :
1404 : : info = *pinfo;
1405 : : entry0 = *pentry0;
1406 : : size = compatr->size;
1407 : : info->number = compatr->num_entries;
1408 : :
1409 : : j = 0;
1410 : : xt_compat_lock(AF_INET);
1411 : : ret = xt_compat_init_offsets(AF_INET, compatr->num_entries);
1412 : : if (ret)
1413 : : goto out_unlock;
1414 : : /* Walk through entries, checking offsets. */
1415 : : xt_entry_foreach(iter0, entry0, compatr->size) {
1416 : : ret = check_compat_entry_size_and_hooks(iter0, info, &size,
1417 : : entry0,
1418 : : entry0 + compatr->size);
1419 : : if (ret != 0)
1420 : : goto out_unlock;
1421 : : ++j;
1422 : : }
1423 : :
1424 : : ret = -EINVAL;
1425 : : if (j != compatr->num_entries)
1426 : : goto out_unlock;
1427 : :
1428 : : ret = -ENOMEM;
1429 : : newinfo = xt_alloc_table_info(size);
1430 : : if (!newinfo)
1431 : : goto out_unlock;
1432 : :
1433 : : newinfo->number = compatr->num_entries;
1434 : : for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1435 : : newinfo->hook_entry[i] = compatr->hook_entry[i];
1436 : : newinfo->underflow[i] = compatr->underflow[i];
1437 : : }
1438 : : entry1 = newinfo->entries;
1439 : : pos = entry1;
1440 : : size = compatr->size;
1441 : : xt_entry_foreach(iter0, entry0, compatr->size)
1442 : : compat_copy_entry_from_user(iter0, &pos, &size,
1443 : : newinfo, entry1);
1444 : :
1445 : : /* all module references in entry0 are now gone.
1446 : : * entry1/newinfo contains a 64bit ruleset that looks exactly as
1447 : : * generated by 64bit userspace.
1448 : : *
1449 : : * Call standard translate_table() to validate all hook_entrys,
1450 : : * underflows, check for loops, etc.
1451 : : */
1452 : : xt_compat_flush_offsets(AF_INET);
1453 : : xt_compat_unlock(AF_INET);
1454 : :
1455 : : memcpy(&repl, compatr, sizeof(*compatr));
1456 : :
1457 : : for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1458 : : repl.hook_entry[i] = newinfo->hook_entry[i];
1459 : : repl.underflow[i] = newinfo->underflow[i];
1460 : : }
1461 : :
1462 : : repl.num_counters = 0;
1463 : : repl.counters = NULL;
1464 : : repl.size = newinfo->size;
1465 : : ret = translate_table(net, newinfo, entry1, &repl);
1466 : : if (ret)
1467 : : goto free_newinfo;
1468 : :
1469 : : *pinfo = newinfo;
1470 : : *pentry0 = entry1;
1471 : : xt_free_table_info(info);
1472 : : return 0;
1473 : :
1474 : : free_newinfo:
1475 : : xt_free_table_info(newinfo);
1476 : : return ret;
1477 : : out_unlock:
1478 : : xt_compat_flush_offsets(AF_INET);
1479 : : xt_compat_unlock(AF_INET);
1480 : : xt_entry_foreach(iter0, entry0, compatr->size) {
1481 : : if (j-- == 0)
1482 : : break;
1483 : : compat_release_entry(iter0);
1484 : : }
1485 : : return ret;
1486 : : }
1487 : :
1488 : : static int
1489 : : compat_do_replace(struct net *net, void __user *user, unsigned int len)
1490 : : {
1491 : : int ret;
1492 : : struct compat_ipt_replace tmp;
1493 : : struct xt_table_info *newinfo;
1494 : : void *loc_cpu_entry;
1495 : : struct ipt_entry *iter;
1496 : :
1497 : : if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1498 : : return -EFAULT;
1499 : :
1500 : : /* overflow check */
1501 : : if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1502 : : return -ENOMEM;
1503 : : if (tmp.num_counters == 0)
1504 : : return -EINVAL;
1505 : :
1506 : : tmp.name[sizeof(tmp.name)-1] = 0;
1507 : :
1508 : : newinfo = xt_alloc_table_info(tmp.size);
1509 : : if (!newinfo)
1510 : : return -ENOMEM;
1511 : :
1512 : : loc_cpu_entry = newinfo->entries;
1513 : : if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1514 : : tmp.size) != 0) {
1515 : : ret = -EFAULT;
1516 : : goto free_newinfo;
1517 : : }
1518 : :
1519 : : ret = translate_compat_table(net, &newinfo, &loc_cpu_entry, &tmp);
1520 : : if (ret != 0)
1521 : : goto free_newinfo;
1522 : :
1523 : : ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1524 : : tmp.num_counters, compat_ptr(tmp.counters));
1525 : : if (ret)
1526 : : goto free_newinfo_untrans;
1527 : : return 0;
1528 : :
1529 : : free_newinfo_untrans:
1530 : : xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1531 : : cleanup_entry(iter, net);
1532 : : free_newinfo:
1533 : : xt_free_table_info(newinfo);
1534 : : return ret;
1535 : : }
1536 : :
1537 : : static int
1538 : : compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user,
1539 : : unsigned int len)
1540 : : {
1541 : : int ret;
1542 : :
1543 : : if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1544 : : return -EPERM;
1545 : :
1546 : : switch (cmd) {
1547 : : case IPT_SO_SET_REPLACE:
1548 : : ret = compat_do_replace(sock_net(sk), user, len);
1549 : : break;
1550 : :
1551 : : case IPT_SO_SET_ADD_COUNTERS:
1552 : : ret = do_add_counters(sock_net(sk), user, len, 1);
1553 : : break;
1554 : :
1555 : : default:
1556 : : ret = -EINVAL;
1557 : : }
1558 : :
1559 : : return ret;
1560 : : }
1561 : :
1562 : : struct compat_ipt_get_entries {
1563 : : char name[XT_TABLE_MAXNAMELEN];
1564 : : compat_uint_t size;
1565 : : struct compat_ipt_entry entrytable[0];
1566 : : };
1567 : :
1568 : : static int
1569 : : compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1570 : : void __user *userptr)
1571 : : {
1572 : : struct xt_counters *counters;
1573 : : const struct xt_table_info *private = table->private;
1574 : : void __user *pos;
1575 : : unsigned int size;
1576 : : int ret = 0;
1577 : : unsigned int i = 0;
1578 : : struct ipt_entry *iter;
1579 : :
1580 : : counters = alloc_counters(table);
1581 : : if (IS_ERR(counters))
1582 : : return PTR_ERR(counters);
1583 : :
1584 : : pos = userptr;
1585 : : size = total_size;
1586 : : xt_entry_foreach(iter, private->entries, total_size) {
1587 : : ret = compat_copy_entry_to_user(iter, &pos,
1588 : : &size, counters, i++);
1589 : : if (ret != 0)
1590 : : break;
1591 : : }
1592 : :
1593 : : vfree(counters);
1594 : : return ret;
1595 : : }
1596 : :
1597 : : static int
1598 : : compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr,
1599 : : int *len)
1600 : : {
1601 : : int ret;
1602 : : struct compat_ipt_get_entries get;
1603 : : struct xt_table *t;
1604 : :
1605 : : if (*len < sizeof(get))
1606 : : return -EINVAL;
1607 : :
1608 : : if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1609 : : return -EFAULT;
1610 : :
1611 : : if (*len != sizeof(struct compat_ipt_get_entries) + get.size)
1612 : : return -EINVAL;
1613 : :
1614 : : get.name[sizeof(get.name) - 1] = '\0';
1615 : :
1616 : : xt_compat_lock(AF_INET);
1617 : : t = xt_find_table_lock(net, AF_INET, get.name);
1618 : : if (!IS_ERR(t)) {
1619 : : const struct xt_table_info *private = t->private;
1620 : : struct xt_table_info info;
1621 : : ret = compat_table_info(private, &info);
1622 : : if (!ret && get.size == info.size)
1623 : : ret = compat_copy_entries_to_user(private->size,
1624 : : t, uptr->entrytable);
1625 : : else if (!ret)
1626 : : ret = -EAGAIN;
1627 : :
1628 : : xt_compat_flush_offsets(AF_INET);
1629 : : module_put(t->me);
1630 : : xt_table_unlock(t);
1631 : : } else
1632 : : ret = PTR_ERR(t);
1633 : :
1634 : : xt_compat_unlock(AF_INET);
1635 : : return ret;
1636 : : }
1637 : :
1638 : : static int do_ipt_get_ctl(struct sock *, int, void __user *, int *);
1639 : :
1640 : : static int
1641 : : compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1642 : : {
1643 : : int ret;
1644 : :
1645 : : if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1646 : : return -EPERM;
1647 : :
1648 : : switch (cmd) {
1649 : : case IPT_SO_GET_INFO:
1650 : : ret = get_info(sock_net(sk), user, len, 1);
1651 : : break;
1652 : : case IPT_SO_GET_ENTRIES:
1653 : : ret = compat_get_entries(sock_net(sk), user, len);
1654 : : break;
1655 : : default:
1656 : : ret = do_ipt_get_ctl(sk, cmd, user, len);
1657 : : }
1658 : : return ret;
1659 : : }
1660 : : #endif
1661 : :
1662 : : static int
1663 : 0 : do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1664 : : {
1665 : : int ret;
1666 : :
1667 : 0 : if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1668 : : return -EPERM;
1669 : :
1670 : 0 : switch (cmd) {
1671 : : case IPT_SO_SET_REPLACE:
1672 : 0 : ret = do_replace(sock_net(sk), user, len);
1673 : 0 : break;
1674 : :
1675 : : case IPT_SO_SET_ADD_COUNTERS:
1676 : 0 : ret = do_add_counters(sock_net(sk), user, len, 0);
1677 : 0 : break;
1678 : :
1679 : : default:
1680 : : ret = -EINVAL;
1681 : : }
1682 : :
1683 : 0 : return ret;
1684 : : }
1685 : :
1686 : : static int
1687 : 0 : do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1688 : : {
1689 : : int ret;
1690 : :
1691 : 0 : if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1692 : : return -EPERM;
1693 : :
1694 : 0 : switch (cmd) {
1695 : : case IPT_SO_GET_INFO:
1696 : 0 : ret = get_info(sock_net(sk), user, len, 0);
1697 : 0 : break;
1698 : :
1699 : : case IPT_SO_GET_ENTRIES:
1700 : 0 : ret = get_entries(sock_net(sk), user, len);
1701 : 0 : break;
1702 : :
1703 : : case IPT_SO_GET_REVISION_MATCH:
1704 : : case IPT_SO_GET_REVISION_TARGET: {
1705 : : struct xt_get_revision rev;
1706 : : int target;
1707 : :
1708 : 0 : if (*len != sizeof(rev)) {
1709 : 0 : ret = -EINVAL;
1710 : 0 : break;
1711 : : }
1712 : 0 : if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1713 : 0 : ret = -EFAULT;
1714 : 0 : break;
1715 : : }
1716 : 0 : rev.name[sizeof(rev.name)-1] = 0;
1717 : :
1718 : 0 : if (cmd == IPT_SO_GET_REVISION_TARGET)
1719 : : target = 1;
1720 : : else
1721 : : target = 0;
1722 : :
1723 : 0 : try_then_request_module(xt_find_revision(AF_INET, rev.name,
1724 : : rev.revision,
1725 : : target, &ret),
1726 : : "ipt_%s", rev.name);
1727 : : break;
1728 : : }
1729 : :
1730 : : default:
1731 : 0 : ret = -EINVAL;
1732 : : }
1733 : :
1734 : 0 : return ret;
1735 : : }
1736 : :
1737 : 0 : static void __ipt_unregister_table(struct net *net, struct xt_table *table)
1738 : : {
1739 : : struct xt_table_info *private;
1740 : : void *loc_cpu_entry;
1741 : 0 : struct module *table_owner = table->me;
1742 : : struct ipt_entry *iter;
1743 : :
1744 : 0 : private = xt_unregister_table(table);
1745 : :
1746 : : /* Decrease module usage counts and free resources */
1747 : 0 : loc_cpu_entry = private->entries;
1748 : 0 : xt_entry_foreach(iter, loc_cpu_entry, private->size)
1749 : 0 : cleanup_entry(iter, net);
1750 : 0 : if (private->number > private->initial_entries)
1751 : 0 : module_put(table_owner);
1752 : 0 : xt_free_table_info(private);
1753 : 0 : }
1754 : :
1755 : 0 : int ipt_register_table(struct net *net, const struct xt_table *table,
1756 : : const struct ipt_replace *repl,
1757 : : const struct nf_hook_ops *ops, struct xt_table **res)
1758 : : {
1759 : : int ret;
1760 : : struct xt_table_info *newinfo;
1761 : 0 : struct xt_table_info bootstrap = {0};
1762 : : void *loc_cpu_entry;
1763 : : struct xt_table *new_table;
1764 : :
1765 : 0 : newinfo = xt_alloc_table_info(repl->size);
1766 : 0 : if (!newinfo)
1767 : : return -ENOMEM;
1768 : :
1769 : 0 : loc_cpu_entry = newinfo->entries;
1770 : 0 : memcpy(loc_cpu_entry, repl->entries, repl->size);
1771 : :
1772 : 0 : ret = translate_table(net, newinfo, loc_cpu_entry, repl);
1773 : 0 : if (ret != 0)
1774 : : goto out_free;
1775 : :
1776 : 0 : new_table = xt_register_table(net, table, &bootstrap, newinfo);
1777 : 0 : if (IS_ERR(new_table)) {
1778 : : ret = PTR_ERR(new_table);
1779 : 0 : goto out_free;
1780 : : }
1781 : :
1782 : : /* set res now, will see skbs right after nf_register_net_hooks */
1783 : : WRITE_ONCE(*res, new_table);
1784 : 0 : if (!ops)
1785 : : return 0;
1786 : :
1787 : 0 : ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
1788 : 0 : if (ret != 0) {
1789 : 0 : __ipt_unregister_table(net, new_table);
1790 : 0 : *res = NULL;
1791 : : }
1792 : :
1793 : 0 : return ret;
1794 : :
1795 : : out_free:
1796 : 0 : xt_free_table_info(newinfo);
1797 : 0 : return ret;
1798 : : }
1799 : :
1800 : 0 : void ipt_unregister_table(struct net *net, struct xt_table *table,
1801 : : const struct nf_hook_ops *ops)
1802 : : {
1803 : 0 : if (ops)
1804 : 0 : nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
1805 : 0 : __ipt_unregister_table(net, table);
1806 : 0 : }
1807 : :
1808 : : /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1809 : : static inline bool
1810 : : icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1811 : : u_int8_t type, u_int8_t code,
1812 : : bool invert)
1813 : : {
1814 : 0 : return ((test_type == 0xFF) ||
1815 : 0 : (type == test_type && code >= min_code && code <= max_code))
1816 : 0 : ^ invert;
1817 : : }
1818 : :
1819 : : static bool
1820 : 0 : icmp_match(const struct sk_buff *skb, struct xt_action_param *par)
1821 : : {
1822 : : const struct icmphdr *ic;
1823 : : struct icmphdr _icmph;
1824 : 0 : const struct ipt_icmp *icmpinfo = par->matchinfo;
1825 : :
1826 : : /* Must not be a fragment. */
1827 : 0 : if (par->fragoff != 0)
1828 : : return false;
1829 : :
1830 : 0 : ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
1831 : 0 : if (ic == NULL) {
1832 : : /* We've been asked to examine this packet, and we
1833 : : * can't. Hence, no choice but to drop.
1834 : : */
1835 : 0 : par->hotdrop = true;
1836 : 0 : return false;
1837 : : }
1838 : :
1839 : 0 : return icmp_type_code_match(icmpinfo->type,
1840 : : icmpinfo->code[0],
1841 : : icmpinfo->code[1],
1842 : : ic->type, ic->code,
1843 : 0 : !!(icmpinfo->invflags&IPT_ICMP_INV));
1844 : : }
1845 : :
1846 : 0 : static int icmp_checkentry(const struct xt_mtchk_param *par)
1847 : : {
1848 : 0 : const struct ipt_icmp *icmpinfo = par->matchinfo;
1849 : :
1850 : : /* Must specify no unknown invflags */
1851 : 0 : return (icmpinfo->invflags & ~IPT_ICMP_INV) ? -EINVAL : 0;
1852 : : }
1853 : :
1854 : : static struct xt_target ipt_builtin_tg[] __read_mostly = {
1855 : : {
1856 : : .name = XT_STANDARD_TARGET,
1857 : : .targetsize = sizeof(int),
1858 : : .family = NFPROTO_IPV4,
1859 : : #ifdef CONFIG_COMPAT
1860 : : .compatsize = sizeof(compat_int_t),
1861 : : .compat_from_user = compat_standard_from_user,
1862 : : .compat_to_user = compat_standard_to_user,
1863 : : #endif
1864 : : },
1865 : : {
1866 : : .name = XT_ERROR_TARGET,
1867 : : .target = ipt_error,
1868 : : .targetsize = XT_FUNCTION_MAXNAMELEN,
1869 : : .family = NFPROTO_IPV4,
1870 : : },
1871 : : };
1872 : :
1873 : : static struct nf_sockopt_ops ipt_sockopts = {
1874 : : .pf = PF_INET,
1875 : : .set_optmin = IPT_BASE_CTL,
1876 : : .set_optmax = IPT_SO_SET_MAX+1,
1877 : : .set = do_ipt_set_ctl,
1878 : : #ifdef CONFIG_COMPAT
1879 : : .compat_set = compat_do_ipt_set_ctl,
1880 : : #endif
1881 : : .get_optmin = IPT_BASE_CTL,
1882 : : .get_optmax = IPT_SO_GET_MAX+1,
1883 : : .get = do_ipt_get_ctl,
1884 : : #ifdef CONFIG_COMPAT
1885 : : .compat_get = compat_do_ipt_get_ctl,
1886 : : #endif
1887 : : .owner = THIS_MODULE,
1888 : : };
1889 : :
1890 : : static struct xt_match ipt_builtin_mt[] __read_mostly = {
1891 : : {
1892 : : .name = "icmp",
1893 : : .match = icmp_match,
1894 : : .matchsize = sizeof(struct ipt_icmp),
1895 : : .checkentry = icmp_checkentry,
1896 : : .proto = IPPROTO_ICMP,
1897 : : .family = NFPROTO_IPV4,
1898 : : .me = THIS_MODULE,
1899 : : },
1900 : : };
1901 : :
1902 : 3 : static int __net_init ip_tables_net_init(struct net *net)
1903 : : {
1904 : 3 : return xt_proto_init(net, NFPROTO_IPV4);
1905 : : }
1906 : :
1907 : 1 : static void __net_exit ip_tables_net_exit(struct net *net)
1908 : : {
1909 : 1 : xt_proto_fini(net, NFPROTO_IPV4);
1910 : 1 : }
1911 : :
1912 : : static struct pernet_operations ip_tables_net_ops = {
1913 : : .init = ip_tables_net_init,
1914 : : .exit = ip_tables_net_exit,
1915 : : };
1916 : :
1917 : 3 : static int __init ip_tables_init(void)
1918 : : {
1919 : : int ret;
1920 : :
1921 : 3 : ret = register_pernet_subsys(&ip_tables_net_ops);
1922 : 3 : if (ret < 0)
1923 : : goto err1;
1924 : :
1925 : : /* No one else will be downing sem now, so we won't sleep */
1926 : 3 : ret = xt_register_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg));
1927 : 3 : if (ret < 0)
1928 : : goto err2;
1929 : 3 : ret = xt_register_matches(ipt_builtin_mt, ARRAY_SIZE(ipt_builtin_mt));
1930 : 3 : if (ret < 0)
1931 : : goto err4;
1932 : :
1933 : : /* Register setsockopt */
1934 : 3 : ret = nf_register_sockopt(&ipt_sockopts);
1935 : 3 : if (ret < 0)
1936 : : goto err5;
1937 : :
1938 : : return 0;
1939 : :
1940 : : err5:
1941 : 0 : xt_unregister_matches(ipt_builtin_mt, ARRAY_SIZE(ipt_builtin_mt));
1942 : : err4:
1943 : 0 : xt_unregister_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg));
1944 : : err2:
1945 : 0 : unregister_pernet_subsys(&ip_tables_net_ops);
1946 : : err1:
1947 : 0 : return ret;
1948 : : }
1949 : :
1950 : 0 : static void __exit ip_tables_fini(void)
1951 : : {
1952 : 0 : nf_unregister_sockopt(&ipt_sockopts);
1953 : :
1954 : 0 : xt_unregister_matches(ipt_builtin_mt, ARRAY_SIZE(ipt_builtin_mt));
1955 : 0 : xt_unregister_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg));
1956 : 0 : unregister_pernet_subsys(&ip_tables_net_ops);
1957 : 0 : }
1958 : :
1959 : : EXPORT_SYMBOL(ipt_register_table);
1960 : : EXPORT_SYMBOL(ipt_unregister_table);
1961 : : EXPORT_SYMBOL(ipt_do_table);
1962 : : module_init(ip_tables_init);
1963 : : module_exit(ip_tables_fini);
|