~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv4/netfilter/arp_tables.c

Version: ~ [ linux-5.12-rc7 ] ~ [ linux-5.11.13 ] ~ [ linux-5.10.29 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.111 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.186 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.230 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.266 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.266 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Packet matching code for ARP packets.
  3  *
  4  * Based heavily, if not almost entirely, upon ip_tables.c framework.
  5  *
  6  * Some ARP specific bits are:
  7  *
  8  * Copyright (C) 2002 David S. Miller (davem@redhat.com)
  9  * Copyright (C) 2006-2009 Patrick McHardy <kaber@trash.net>
 10  *
 11  */
 12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 13 #include <linux/kernel.h>
 14 #include <linux/skbuff.h>
 15 #include <linux/netdevice.h>
 16 #include <linux/capability.h>
 17 #include <linux/if_arp.h>
 18 #include <linux/kmod.h>
 19 #include <linux/vmalloc.h>
 20 #include <linux/proc_fs.h>
 21 #include <linux/module.h>
 22 #include <linux/init.h>
 23 #include <linux/mutex.h>
 24 #include <linux/err.h>
 25 #include <net/compat.h>
 26 #include <net/sock.h>
 27 #include <asm/uaccess.h>
 28 
 29 #include <linux/netfilter/x_tables.h>
 30 #include <linux/netfilter_arp/arp_tables.h>
 31 #include "../../netfilter/xt_repldata.h"
 32 
 33 MODULE_LICENSE("GPL");
 34 MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
 35 MODULE_DESCRIPTION("arptables core");
 36 
 37 void *arpt_alloc_initial_table(const struct xt_table *info)
 38 {
 39         return xt_alloc_initial_table(arpt, ARPT);
 40 }
 41 EXPORT_SYMBOL_GPL(arpt_alloc_initial_table);
 42 
 43 static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
 44                                       const char *hdr_addr, int len)
 45 {
 46         int i, ret;
 47 
 48         if (len > ARPT_DEV_ADDR_LEN_MAX)
 49                 len = ARPT_DEV_ADDR_LEN_MAX;
 50 
 51         ret = 0;
 52         for (i = 0; i < len; i++)
 53                 ret |= (hdr_addr[i] ^ ap->addr[i]) & ap->mask[i];
 54 
 55         return ret != 0;
 56 }
 57 
 58 /*
 59  * Unfortunately, _b and _mask are not aligned to an int (or long int)
 60  * Some arches dont care, unrolling the loop is a win on them.
 61  * For other arches, we only have a 16bit alignement.
 62  */
 63 static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask)
 64 {
 65 #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
 66         unsigned long ret = ifname_compare_aligned(_a, _b, _mask);
 67 #else
 68         unsigned long ret = 0;
 69         const u16 *a = (const u16 *)_a;
 70         const u16 *b = (const u16 *)_b;
 71         const u16 *mask = (const u16 *)_mask;
 72         int i;
 73 
 74         for (i = 0; i < IFNAMSIZ/sizeof(u16); i++)
 75                 ret |= (a[i] ^ b[i]) & mask[i];
 76 #endif
 77         return ret;
 78 }
 79 
 80 /* Returns whether packet matches rule or not. */
 81 static inline int arp_packet_match(const struct arphdr *arphdr,
 82                                    struct net_device *dev,
 83                                    const char *indev,
 84                                    const char *outdev,
 85                                    const struct arpt_arp *arpinfo)
 86 {
 87         const char *arpptr = (char *)(arphdr + 1);
 88         const char *src_devaddr, *tgt_devaddr;
 89         __be32 src_ipaddr, tgt_ipaddr;
 90         long ret;
 91 
 92 #define FWINV(bool, invflg) ((bool) ^ !!(arpinfo->invflags & (invflg)))
 93 
 94         if (FWINV((arphdr->ar_op & arpinfo->arpop_mask) != arpinfo->arpop,
 95                   ARPT_INV_ARPOP))
 96                 return 0;
 97 
 98         if (FWINV((arphdr->ar_hrd & arpinfo->arhrd_mask) != arpinfo->arhrd,
 99                   ARPT_INV_ARPHRD))
100                 return 0;
101 
102         if (FWINV((arphdr->ar_pro & arpinfo->arpro_mask) != arpinfo->arpro,
103                   ARPT_INV_ARPPRO))
104                 return 0;
105 
106         if (FWINV((arphdr->ar_hln & arpinfo->arhln_mask) != arpinfo->arhln,
107                   ARPT_INV_ARPHLN))
108                 return 0;
109 
110         src_devaddr = arpptr;
111         arpptr += dev->addr_len;
112         memcpy(&src_ipaddr, arpptr, sizeof(u32));
113         arpptr += sizeof(u32);
114         tgt_devaddr = arpptr;
115         arpptr += dev->addr_len;
116         memcpy(&tgt_ipaddr, arpptr, sizeof(u32));
117 
118         if (FWINV(arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, dev->addr_len),
119                   ARPT_INV_SRCDEVADDR) ||
120             FWINV(arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, dev->addr_len),
121                   ARPT_INV_TGTDEVADDR))
122                 return 0;
123 
124         if (FWINV((src_ipaddr & arpinfo->smsk.s_addr) != arpinfo->src.s_addr,
125                   ARPT_INV_SRCIP) ||
126             FWINV(((tgt_ipaddr & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr),
127                   ARPT_INV_TGTIP))
128                 return 0;
129 
130         /* Look for ifname matches.  */
131         ret = ifname_compare(indev, arpinfo->iniface, arpinfo->iniface_mask);
132 
133         if (FWINV(ret != 0, ARPT_INV_VIA_IN))
134                 return 0;
135 
136         ret = ifname_compare(outdev, arpinfo->outiface, arpinfo->outiface_mask);
137 
138         if (FWINV(ret != 0, ARPT_INV_VIA_OUT))
139                 return 0;
140 
141         return 1;
142 #undef FWINV
143 }
144 
145 static inline int arp_checkentry(const struct arpt_arp *arp)
146 {
147         if (arp->flags & ~ARPT_F_MASK)
148                 return 0;
149         if (arp->invflags & ~ARPT_INV_MASK)
150                 return 0;
151 
152         return 1;
153 }
154 
155 static unsigned int
156 arpt_error(struct sk_buff *skb, const struct xt_action_param *par)
157 {
158         net_err_ratelimited("arp_tables: error: '%s'\n",
159                             (const char *)par->targinfo);
160 
161         return NF_DROP;
162 }
163 
164 static inline const struct xt_entry_target *
165 arpt_get_target_c(const struct arpt_entry *e)
166 {
167         return arpt_get_target((struct arpt_entry *)e);
168 }
169 
170 static inline struct arpt_entry *
171 get_entry(const void *base, unsigned int offset)
172 {
173         return (struct arpt_entry *)(base + offset);
174 }
175 
176 static inline
177 struct arpt_entry *arpt_next_entry(const struct arpt_entry *entry)
178 {
179         return (void *)entry + entry->next_offset;
180 }
181 
182 unsigned int arpt_do_table(struct sk_buff *skb,
183                            const struct nf_hook_state *state,
184                            struct xt_table *table)
185 {
186         unsigned int hook = state->hook;
187         static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
188         unsigned int verdict = NF_DROP;
189         const struct arphdr *arp;
190         struct arpt_entry *e, **jumpstack;
191         const char *indev, *outdev;
192         const void *table_base;
193         unsigned int cpu, stackidx = 0;
194         const struct xt_table_info *private;
195         struct xt_action_param acpar;
196         unsigned int addend;
197 
198         if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
199                 return NF_DROP;
200 
201         indev = state->in ? state->in->name : nulldevname;
202         outdev = state->out ? state->out->name : nulldevname;
203 
204         local_bh_disable();
205         addend = xt_write_recseq_begin();
206         private = table->private;
207         cpu     = smp_processor_id();
208         /*
209          * Ensure we load private-> members after we've fetched the base
210          * pointer.
211          */
212         smp_read_barrier_depends();
213         table_base = private->entries;
214         jumpstack  = (struct arpt_entry **)private->jumpstack[cpu];
215 
216         /* No TEE support for arptables, so no need to switch to alternate
217          * stack.  All targets that reenter must return absolute verdicts.
218          */
219         e = get_entry(table_base, private->hook_entry[hook]);
220 
221         acpar.net     = state->net;
222         acpar.in      = state->in;
223         acpar.out     = state->out;
224         acpar.hooknum = hook;
225         acpar.family  = NFPROTO_ARP;
226         acpar.hotdrop = false;
227 
228         arp = arp_hdr(skb);
229         do {
230                 const struct xt_entry_target *t;
231                 struct xt_counters *counter;
232 
233                 if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) {
234                         e = arpt_next_entry(e);
235                         continue;
236                 }
237 
238                 counter = xt_get_this_cpu_counter(&e->counters);
239                 ADD_COUNTER(*counter, arp_hdr_len(skb->dev), 1);
240 
241                 t = arpt_get_target_c(e);
242 
243                 /* Standard target? */
244                 if (!t->u.kernel.target->target) {
245                         int v;
246 
247                         v = ((struct xt_standard_target *)t)->verdict;
248                         if (v < 0) {
249                                 /* Pop from stack? */
250                                 if (v != XT_RETURN) {
251                                         verdict = (unsigned int)(-v) - 1;
252                                         break;
253                                 }
254                                 if (stackidx == 0) {
255                                         e = get_entry(table_base,
256                                                       private->underflow[hook]);
257                                 } else {
258                                         e = jumpstack[--stackidx];
259                                         e = arpt_next_entry(e);
260                                 }
261                                 continue;
262                         }
263                         if (table_base + v
264                             != arpt_next_entry(e)) {
265                                 jumpstack[stackidx++] = e;
266                         }
267 
268                         e = get_entry(table_base, v);
269                         continue;
270                 }
271 
272                 acpar.target   = t->u.kernel.target;
273                 acpar.targinfo = t->data;
274                 verdict = t->u.kernel.target->target(skb, &acpar);
275 
276                 /* Target might have changed stuff. */
277                 arp = arp_hdr(skb);
278 
279                 if (verdict == XT_CONTINUE)
280                         e = arpt_next_entry(e);
281                 else
282                         /* Verdict */
283                         break;
284         } while (!acpar.hotdrop);
285         xt_write_recseq_end(addend);
286         local_bh_enable();
287 
288         if (acpar.hotdrop)
289                 return NF_DROP;
290         else
291                 return verdict;
292 }
293 
294 /* All zeroes == unconditional rule. */
295 static inline bool unconditional(const struct arpt_entry *e)
296 {
297         static const struct arpt_arp uncond;
298 
299         return e->target_offset == sizeof(struct arpt_entry) &&
300                memcmp(&e->arp, &uncond, sizeof(uncond)) == 0;
301 }
302 
303 static bool find_jump_target(const struct xt_table_info *t,
304                              const struct arpt_entry *target)
305 {
306         struct arpt_entry *iter;
307 
308         xt_entry_foreach(iter, t->entries, t->size) {
309                  if (iter == target)
310                         return true;
311         }
312         return false;
313 }
314 
315 /* Figures out from what hook each rule can be called: returns 0 if
316  * there are loops.  Puts hook bitmask in comefrom.
317  */
318 static int mark_source_chains(const struct xt_table_info *newinfo,
319                               unsigned int valid_hooks, void *entry0)
320 {
321         unsigned int hook;
322 
323         /* No recursion; use packet counter to save back ptrs (reset
324          * to 0 as we leave), and comefrom to save source hook bitmask.
325          */
326         for (hook = 0; hook < NF_ARP_NUMHOOKS; hook++) {
327                 unsigned int pos = newinfo->hook_entry[hook];
328                 struct arpt_entry *e
329                         = (struct arpt_entry *)(entry0 + pos);
330 
331                 if (!(valid_hooks & (1 << hook)))
332                         continue;
333 
334                 /* Set initial back pointer. */
335                 e->counters.pcnt = pos;
336 
337                 for (;;) {
338                         const struct xt_standard_target *t
339                                 = (void *)arpt_get_target_c(e);
340                         int visited = e->comefrom & (1 << hook);
341 
342                         if (e->comefrom & (1 << NF_ARP_NUMHOOKS))
343                                 return 0;
344 
345                         e->comefrom
346                                 |= ((1 << hook) | (1 << NF_ARP_NUMHOOKS));
347 
348                         /* Unconditional return/END. */
349                         if ((unconditional(e) &&
350                              (strcmp(t->target.u.user.name,
351                                      XT_STANDARD_TARGET) == 0) &&
352                              t->verdict < 0) || visited) {
353                                 unsigned int oldpos, size;
354 
355                                 if ((strcmp(t->target.u.user.name,
356                                             XT_STANDARD_TARGET) == 0) &&
357                                     t->verdict < -NF_MAX_VERDICT - 1)
358                                         return 0;
359 
360                                 /* Return: backtrack through the last
361                                  * big jump.
362                                  */
363                                 do {
364                                         e->comefrom ^= (1<<NF_ARP_NUMHOOKS);
365                                         oldpos = pos;
366                                         pos = e->counters.pcnt;
367                                         e->counters.pcnt = 0;
368 
369                                         /* We're at the start. */
370                                         if (pos == oldpos)
371                                                 goto next;
372 
373                                         e = (struct arpt_entry *)
374                                                 (entry0 + pos);
375                                 } while (oldpos == pos + e->next_offset);
376 
377                                 /* Move along one */
378                                 size = e->next_offset;
379                                 e = (struct arpt_entry *)
380                                         (entry0 + pos + size);
381                                 if (pos + size >= newinfo->size)
382                                         return 0;
383                                 e->counters.pcnt = pos;
384                                 pos += size;
385                         } else {
386                                 int newpos = t->verdict;
387 
388                                 if (strcmp(t->target.u.user.name,
389                                            XT_STANDARD_TARGET) == 0 &&
390                                     newpos >= 0) {
391                                         /* This a jump; chase it. */
392                                         e = (struct arpt_entry *)
393                                                 (entry0 + newpos);
394                                         if (!find_jump_target(newinfo, e))
395                                                 return 0;
396                                 } else {
397                                         /* ... this is a fallthru */
398                                         newpos = pos + e->next_offset;
399                                         if (newpos >= newinfo->size)
400                                                 return 0;
401                                 }
402                                 e = (struct arpt_entry *)
403                                         (entry0 + newpos);
404                                 e->counters.pcnt = pos;
405                                 pos = newpos;
406                         }
407                 }
408 next:           ;
409         }
410         return 1;
411 }
412 
413 static inline int check_target(struct arpt_entry *e, const char *name)
414 {
415         struct xt_entry_target *t = arpt_get_target(e);
416         struct xt_tgchk_param par = {
417                 .table     = name,
418                 .entryinfo = e,
419                 .target    = t->u.kernel.target,
420                 .targinfo  = t->data,
421                 .hook_mask = e->comefrom,
422                 .family    = NFPROTO_ARP,
423         };
424 
425         return xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false);
426 }
427 
428 static inline int
429 find_check_entry(struct arpt_entry *e, const char *name, unsigned int size)
430 {
431         struct xt_entry_target *t;
432         struct xt_target *target;
433         unsigned long pcnt;
434         int ret;
435 
436         pcnt = xt_percpu_counter_alloc();
437         if (IS_ERR_VALUE(pcnt))
438                 return -ENOMEM;
439         e->counters.pcnt = pcnt;
440 
441         t = arpt_get_target(e);
442         target = xt_request_find_target(NFPROTO_ARP, t->u.user.name,
443                                         t->u.user.revision);
444         if (IS_ERR(target)) {
445                 ret = PTR_ERR(target);
446                 goto out;
447         }
448         t->u.kernel.target = target;
449 
450         ret = check_target(e, name);
451         if (ret)
452                 goto err;
453         return 0;
454 err:
455         module_put(t->u.kernel.target->me);
456 out:
457         xt_percpu_counter_free(e->counters.pcnt);
458 
459         return ret;
460 }
461 
462 static bool check_underflow(const struct arpt_entry *e)
463 {
464         const struct xt_entry_target *t;
465         unsigned int verdict;
466 
467         if (!unconditional(e))
468                 return false;
469         t = arpt_get_target_c(e);
470         if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
471                 return false;
472         verdict = ((struct xt_standard_target *)t)->verdict;
473         verdict = -verdict - 1;
474         return verdict == NF_DROP || verdict == NF_ACCEPT;
475 }
476 
477 static inline int check_entry_size_and_hooks(struct arpt_entry *e,
478                                              struct xt_table_info *newinfo,
479                                              const unsigned char *base,
480                                              const unsigned char *limit,
481                                              const unsigned int *hook_entries,
482                                              const unsigned int *underflows,
483                                              unsigned int valid_hooks)
484 {
485         unsigned int h;
486         int err;
487 
488         if ((unsigned long)e % __alignof__(struct arpt_entry) != 0 ||
489             (unsigned char *)e + sizeof(struct arpt_entry) >= limit ||
490             (unsigned char *)e + e->next_offset > limit)
491                 return -EINVAL;
492 
493         if (e->next_offset
494             < sizeof(struct arpt_entry) + sizeof(struct xt_entry_target))
495                 return -EINVAL;
496 
497         if (!arp_checkentry(&e->arp))
498                 return -EINVAL;
499 
500         err = xt_check_entry_offsets(e, e->elems, e->target_offset,
501                                      e->next_offset);
502         if (err)
503                 return err;
504 
505         /* Check hooks & underflows */
506         for (h = 0; h < NF_ARP_NUMHOOKS; h++) {
507                 if (!(valid_hooks & (1 << h)))
508                         continue;
509                 if ((unsigned char *)e - base == hook_entries[h])
510                         newinfo->hook_entry[h] = hook_entries[h];
511                 if ((unsigned char *)e - base == underflows[h]) {
512                         if (!check_underflow(e))
513                                 return -EINVAL;
514 
515                         newinfo->underflow[h] = underflows[h];
516                 }
517         }
518 
519         /* Clear counters and comefrom */
520         e->counters = ((struct xt_counters) { 0, 0 });
521         e->comefrom = 0;
522         return 0;
523 }
524 
525 static inline void cleanup_entry(struct arpt_entry *e)
526 {
527         struct xt_tgdtor_param par;
528         struct xt_entry_target *t;
529 
530         t = arpt_get_target(e);
531         par.target   = t->u.kernel.target;
532         par.targinfo = t->data;
533         par.family   = NFPROTO_ARP;
534         if (par.target->destroy != NULL)
535                 par.target->destroy(&par);
536         module_put(par.target->me);
537         xt_percpu_counter_free(e->counters.pcnt);
538 }
539 
540 /* Checks and translates the user-supplied table segment (held in
541  * newinfo).
542  */
543 static int translate_table(struct xt_table_info *newinfo, void *entry0,
544                            const struct arpt_replace *repl)
545 {
546         struct arpt_entry *iter;
547         unsigned int i;
548         int ret = 0;
549 
550         newinfo->size = repl->size;
551         newinfo->number = repl->num_entries;
552 
553         /* Init all hooks to impossible value. */
554         for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
555                 newinfo->hook_entry[i] = 0xFFFFFFFF;
556                 newinfo->underflow[i] = 0xFFFFFFFF;
557         }
558 
559         i = 0;
560 
561         /* Walk through entries, checking offsets. */
562         xt_entry_foreach(iter, entry0, newinfo->size) {
563                 ret = check_entry_size_and_hooks(iter, newinfo, entry0,
564                                                  entry0 + repl->size,
565                                                  repl->hook_entry,
566                                                  repl->underflow,
567                                                  repl->valid_hooks);
568                 if (ret != 0)
569                         break;
570                 ++i;
571                 if (strcmp(arpt_get_target(iter)->u.user.name,
572                     XT_ERROR_TARGET) == 0)
573                         ++newinfo->stacksize;
574         }
575         if (ret != 0)
576                 return ret;
577 
578         if (i != repl->num_entries)
579                 return -EINVAL;
580 
581         /* Check hooks all assigned */
582         for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
583                 /* Only hooks which are valid */
584                 if (!(repl->valid_hooks & (1 << i)))
585                         continue;
586                 if (newinfo->hook_entry[i] == 0xFFFFFFFF)
587                         return -EINVAL;
588                 if (newinfo->underflow[i] == 0xFFFFFFFF)
589                         return -EINVAL;
590         }
591 
592         if (!mark_source_chains(newinfo, repl->valid_hooks, entry0))
593                 return -ELOOP;
594 
595         /* Finally, each sanity check must pass */
596         i = 0;
597         xt_entry_foreach(iter, entry0, newinfo->size) {
598                 ret = find_check_entry(iter, repl->name, repl->size);
599                 if (ret != 0)
600                         break;
601                 ++i;
602         }
603 
604         if (ret != 0) {
605                 xt_entry_foreach(iter, entry0, newinfo->size) {
606                         if (i-- == 0)
607                                 break;
608                         cleanup_entry(iter);
609                 }
610                 return ret;
611         }
612 
613         return ret;
614 }
615 
616 static void get_counters(const struct xt_table_info *t,
617                          struct xt_counters counters[])
618 {
619         struct arpt_entry *iter;
620         unsigned int cpu;
621         unsigned int i;
622 
623         for_each_possible_cpu(cpu) {
624                 seqcount_t *s = &per_cpu(xt_recseq, cpu);
625 
626                 i = 0;
627                 xt_entry_foreach(iter, t->entries, t->size) {
628                         struct xt_counters *tmp;
629                         u64 bcnt, pcnt;
630                         unsigned int start;
631 
632                         tmp = xt_get_per_cpu_counter(&iter->counters, cpu);
633                         do {
634                                 start = read_seqcount_begin(s);
635                                 bcnt = tmp->bcnt;
636                                 pcnt = tmp->pcnt;
637                         } while (read_seqcount_retry(s, start));
638 
639                         ADD_COUNTER(counters[i], bcnt, pcnt);
640                         ++i;
641                 }
642         }
643 }
644 
645 static struct xt_counters *alloc_counters(const struct xt_table *table)
646 {
647         unsigned int countersize;
648         struct xt_counters *counters;
649         const struct xt_table_info *private = table->private;
650 
651         /* We need atomic snapshot of counters: rest doesn't change
652          * (other than comefrom, which userspace doesn't care
653          * about).
654          */
655         countersize = sizeof(struct xt_counters) * private->number;
656         counters = vzalloc(countersize);
657 
658         if (counters == NULL)
659                 return ERR_PTR(-ENOMEM);
660 
661         get_counters(private, counters);
662 
663         return counters;
664 }
665 
666 static int copy_entries_to_user(unsigned int total_size,
667                                 const struct xt_table *table,
668                                 void __user *userptr)
669 {
670         unsigned int off, num;
671         const struct arpt_entry *e;
672         struct xt_counters *counters;
673         struct xt_table_info *private = table->private;
674         int ret = 0;
675         void *loc_cpu_entry;
676 
677         counters = alloc_counters(table);
678         if (IS_ERR(counters))
679                 return PTR_ERR(counters);
680 
681         loc_cpu_entry = private->entries;
682         /* ... then copy entire thing ... */
683         if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
684                 ret = -EFAULT;
685                 goto free_counters;
686         }
687 
688         /* FIXME: use iterator macros --RR */
689         /* ... then go back and fix counters and names */
690         for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
691                 const struct xt_entry_target *t;
692 
693                 e = (struct arpt_entry *)(loc_cpu_entry + off);
694                 if (copy_to_user(userptr + off
695                                  + offsetof(struct arpt_entry, counters),
696                                  &counters[num],
697                                  sizeof(counters[num])) != 0) {
698                         ret = -EFAULT;
699                         goto free_counters;
700                 }
701 
702                 t = arpt_get_target_c(e);
703                 if (copy_to_user(userptr + off + e->target_offset
704                                  + offsetof(struct xt_entry_target,
705                                             u.user.name),
706                                  t->u.kernel.target->name,
707                                  strlen(t->u.kernel.target->name)+1) != 0) {
708                         ret = -EFAULT;
709                         goto free_counters;
710                 }
711         }
712 
713  free_counters:
714         vfree(counters);
715         return ret;
716 }
717 
718 #ifdef CONFIG_COMPAT
719 static void compat_standard_from_user(void *dst, const void *src)
720 {
721         int v = *(compat_int_t *)src;
722 
723         if (v > 0)
724                 v += xt_compat_calc_jump(NFPROTO_ARP, v);
725         memcpy(dst, &v, sizeof(v));
726 }
727 
728 static int compat_standard_to_user(void __user *dst, const void *src)
729 {
730         compat_int_t cv = *(int *)src;
731 
732         if (cv > 0)
733                 cv -= xt_compat_calc_jump(NFPROTO_ARP, cv);
734         return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
735 }
736 
737 static int compat_calc_entry(const struct arpt_entry *e,
738                              const struct xt_table_info *info,
739                              const void *base, struct xt_table_info *newinfo)
740 {
741         const struct xt_entry_target *t;
742         unsigned int entry_offset;
743         int off, i, ret;
744 
745         off = sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
746         entry_offset = (void *)e - base;
747 
748         t = arpt_get_target_c(e);
749         off += xt_compat_target_offset(t->u.kernel.target);
750         newinfo->size -= off;
751         ret = xt_compat_add_offset(NFPROTO_ARP, entry_offset, off);
752         if (ret)
753                 return ret;
754 
755         for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
756                 if (info->hook_entry[i] &&
757                     (e < (struct arpt_entry *)(base + info->hook_entry[i])))
758                         newinfo->hook_entry[i] -= off;
759                 if (info->underflow[i] &&
760                     (e < (struct arpt_entry *)(base + info->underflow[i])))
761                         newinfo->underflow[i] -= off;
762         }
763         return 0;
764 }
765 
766 static int compat_table_info(const struct xt_table_info *info,
767                              struct xt_table_info *newinfo)
768 {
769         struct arpt_entry *iter;
770         const void *loc_cpu_entry;
771         int ret;
772 
773         if (!newinfo || !info)
774                 return -EINVAL;
775 
776         /* we dont care about newinfo->entries */
777         memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
778         newinfo->initial_entries = 0;
779         loc_cpu_entry = info->entries;
780         xt_compat_init_offsets(NFPROTO_ARP, info->number);
781         xt_entry_foreach(iter, loc_cpu_entry, info->size) {
782                 ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
783                 if (ret != 0)
784                         return ret;
785         }
786         return 0;
787 }
788 #endif
789 
790 static int get_info(struct net *net, void __user *user,
791                     const int *len, int compat)
792 {
793         char name[XT_TABLE_MAXNAMELEN];
794         struct xt_table *t;
795         int ret;
796 
797         if (*len != sizeof(struct arpt_getinfo))
798                 return -EINVAL;
799 
800         if (copy_from_user(name, user, sizeof(name)) != 0)
801                 return -EFAULT;
802 
803         name[XT_TABLE_MAXNAMELEN-1] = '\0';
804 #ifdef CONFIG_COMPAT
805         if (compat)
806                 xt_compat_lock(NFPROTO_ARP);
807 #endif
808         t = try_then_request_module(xt_find_table_lock(net, NFPROTO_ARP, name),
809                                     "arptable_%s", name);
810         if (!IS_ERR_OR_NULL(t)) {
811                 struct arpt_getinfo info;
812                 const struct xt_table_info *private = t->private;
813 #ifdef CONFIG_COMPAT
814                 struct xt_table_info tmp;
815 
816                 if (compat) {
817                         ret = compat_table_info(private, &tmp);
818                         xt_compat_flush_offsets(NFPROTO_ARP);
819                         private = &tmp;
820                 }
821 #endif
822                 memset(&info, 0, sizeof(info));
823                 info.valid_hooks = t->valid_hooks;
824                 memcpy(info.hook_entry, private->hook_entry,
825                        sizeof(info.hook_entry));
826                 memcpy(info.underflow, private->underflow,
827                        sizeof(info.underflow));
828                 info.num_entries = private->number;
829                 info.size = private->size;
830                 strcpy(info.name, name);
831 
832                 if (copy_to_user(user, &info, *len) != 0)
833                         ret = -EFAULT;
834                 else
835                         ret = 0;
836                 xt_table_unlock(t);
837                 module_put(t->me);
838         } else
839                 ret = t ? PTR_ERR(t) : -ENOENT;
840 #ifdef CONFIG_COMPAT
841         if (compat)
842                 xt_compat_unlock(NFPROTO_ARP);
843 #endif
844         return ret;
845 }
846 
847 static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
848                        const int *len)
849 {
850         int ret;
851         struct arpt_get_entries get;
852         struct xt_table *t;
853 
854         if (*len < sizeof(get))
855                 return -EINVAL;
856         if (copy_from_user(&get, uptr, sizeof(get)) != 0)
857                 return -EFAULT;
858         if (*len != sizeof(struct arpt_get_entries) + get.size)
859                 return -EINVAL;
860 
861         get.name[sizeof(get.name) - 1] = '\0';
862 
863         t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
864         if (!IS_ERR_OR_NULL(t)) {
865                 const struct xt_table_info *private = t->private;
866 
867                 if (get.size == private->size)
868                         ret = copy_entries_to_user(private->size,
869                                                    t, uptr->entrytable);
870                 else
871                         ret = -EAGAIN;
872 
873                 module_put(t->me);
874                 xt_table_unlock(t);
875         } else
876                 ret = t ? PTR_ERR(t) : -ENOENT;
877 
878         return ret;
879 }
880 
881 static int __do_replace(struct net *net, const char *name,
882                         unsigned int valid_hooks,
883                         struct xt_table_info *newinfo,
884                         unsigned int num_counters,
885                         void __user *counters_ptr)
886 {
887         int ret;
888         struct xt_table *t;
889         struct xt_table_info *oldinfo;
890         struct xt_counters *counters;
891         void *loc_cpu_old_entry;
892         struct arpt_entry *iter;
893 
894         ret = 0;
895         counters = vzalloc(num_counters * sizeof(struct xt_counters));
896         if (!counters) {
897                 ret = -ENOMEM;
898                 goto out;
899         }
900 
901         t = try_then_request_module(xt_find_table_lock(net, NFPROTO_ARP, name),
902                                     "arptable_%s", name);
903         if (IS_ERR_OR_NULL(t)) {
904                 ret = t ? PTR_ERR(t) : -ENOENT;
905                 goto free_newinfo_counters_untrans;
906         }
907 
908         /* You lied! */
909         if (valid_hooks != t->valid_hooks) {
910                 ret = -EINVAL;
911                 goto put_module;
912         }
913 
914         oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
915         if (!oldinfo)
916                 goto put_module;
917 
918         /* Update module usage count based on number of rules */
919         if ((oldinfo->number > oldinfo->initial_entries) ||
920             (newinfo->number <= oldinfo->initial_entries))
921                 module_put(t->me);
922         if ((oldinfo->number > oldinfo->initial_entries) &&
923             (newinfo->number <= oldinfo->initial_entries))
924                 module_put(t->me);
925 
926         /* Get the old counters, and synchronize with replace */
927         get_counters(oldinfo, counters);
928 
929         /* Decrease module usage counts and free resource */
930         loc_cpu_old_entry = oldinfo->entries;
931         xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size)
932                 cleanup_entry(iter);
933 
934         xt_free_table_info(oldinfo);
935         if (copy_to_user(counters_ptr, counters,
936                          sizeof(struct xt_counters) * num_counters) != 0) {
937                 /* Silent error, can't fail, new table is already in place */
938                 net_warn_ratelimited("arptables: counters copy to user failed while replacing table\n");
939         }
940         vfree(counters);
941         xt_table_unlock(t);
942         return ret;
943 
944  put_module:
945         module_put(t->me);
946         xt_table_unlock(t);
947  free_newinfo_counters_untrans:
948         vfree(counters);
949  out:
950         return ret;
951 }
952 
953 static int do_replace(struct net *net, const void __user *user,
954                       unsigned int len)
955 {
956         int ret;
957         struct arpt_replace tmp;
958         struct xt_table_info *newinfo;
959         void *loc_cpu_entry;
960         struct arpt_entry *iter;
961 
962         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
963                 return -EFAULT;
964 
965         /* overflow check */
966         if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
967                 return -ENOMEM;
968         if (tmp.num_counters == 0)
969                 return -EINVAL;
970 
971         tmp.name[sizeof(tmp.name)-1] = 0;
972 
973         newinfo = xt_alloc_table_info(tmp.size);
974         if (!newinfo)
975                 return -ENOMEM;
976 
977         loc_cpu_entry = newinfo->entries;
978         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
979                            tmp.size) != 0) {
980                 ret = -EFAULT;
981                 goto free_newinfo;
982         }
983 
984         ret = translate_table(newinfo, loc_cpu_entry, &tmp);
985         if (ret != 0)
986                 goto free_newinfo;
987 
988         ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
989                            tmp.num_counters, tmp.counters);
990         if (ret)
991                 goto free_newinfo_untrans;
992         return 0;
993 
994  free_newinfo_untrans:
995         xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
996                 cleanup_entry(iter);
997  free_newinfo:
998         xt_free_table_info(newinfo);
999         return ret;
1000 }
1001 
1002 static int do_add_counters(struct net *net, const void __user *user,
1003                            unsigned int len, int compat)
1004 {
1005         unsigned int i;
1006         struct xt_counters_info tmp;
1007         struct xt_counters *paddc;
1008         struct xt_table *t;
1009         const struct xt_table_info *private;
1010         int ret = 0;
1011         struct arpt_entry *iter;
1012         unsigned int addend;
1013 
1014         paddc = xt_copy_counters_from_user(user, len, &tmp, compat);
1015         if (IS_ERR(paddc))
1016                 return PTR_ERR(paddc);
1017 
1018         t = xt_find_table_lock(net, NFPROTO_ARP, tmp.name);
1019         if (IS_ERR_OR_NULL(t)) {
1020                 ret = t ? PTR_ERR(t) : -ENOENT;
1021                 goto free;
1022         }
1023 
1024         local_bh_disable();
1025         private = t->private;
1026         if (private->number != tmp.num_counters) {
1027                 ret = -EINVAL;
1028                 goto unlock_up_free;
1029         }
1030 
1031         i = 0;
1032 
1033         addend = xt_write_recseq_begin();
1034         xt_entry_foreach(iter,  private->entries, private->size) {
1035                 struct xt_counters *tmp;
1036 
1037                 tmp = xt_get_this_cpu_counter(&iter->counters);
1038                 ADD_COUNTER(*tmp, paddc[i].bcnt, paddc[i].pcnt);
1039                 ++i;
1040         }
1041         xt_write_recseq_end(addend);
1042  unlock_up_free:
1043         local_bh_enable();
1044         xt_table_unlock(t);
1045         module_put(t->me);
1046  free:
1047         vfree(paddc);
1048 
1049         return ret;
1050 }
1051 
1052 #ifdef CONFIG_COMPAT
1053 struct compat_arpt_replace {
1054         char                            name[XT_TABLE_MAXNAMELEN];
1055         u32                             valid_hooks;
1056         u32                             num_entries;
1057         u32                             size;
1058         u32                             hook_entry[NF_ARP_NUMHOOKS];
1059         u32                             underflow[NF_ARP_NUMHOOKS];
1060         u32                             num_counters;
1061         compat_uptr_t                   counters;
1062         struct compat_arpt_entry        entries[0];
1063 };
1064 
1065 static inline void compat_release_entry(struct compat_arpt_entry *e)
1066 {
1067         struct xt_entry_target *t;
1068 
1069         t = compat_arpt_get_target(e);
1070         module_put(t->u.kernel.target->me);
1071 }
1072 
1073 static int
1074 check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
1075                                   struct xt_table_info *newinfo,
1076                                   unsigned int *size,
1077                                   const unsigned char *base,
1078                                   const unsigned char *limit)
1079 {
1080         struct xt_entry_target *t;
1081         struct xt_target *target;
1082         unsigned int entry_offset;
1083         int ret, off;
1084 
1085         if ((unsigned long)e % __alignof__(struct compat_arpt_entry) != 0 ||
1086             (unsigned char *)e + sizeof(struct compat_arpt_entry) >= limit ||
1087             (unsigned char *)e + e->next_offset > limit)
1088                 return -EINVAL;
1089 
1090         if (e->next_offset < sizeof(struct compat_arpt_entry) +
1091                              sizeof(struct compat_xt_entry_target))
1092                 return -EINVAL;
1093 
1094         if (!arp_checkentry(&e->arp))
1095                 return -EINVAL;
1096 
1097         ret = xt_compat_check_entry_offsets(e, e->elems, e->target_offset,
1098                                             e->next_offset);
1099         if (ret)
1100                 return ret;
1101 
1102         off = sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
1103         entry_offset = (void *)e - (void *)base;
1104 
1105         t = compat_arpt_get_target(e);
1106         target = xt_request_find_target(NFPROTO_ARP, t->u.user.name,
1107                                         t->u.user.revision);
1108         if (IS_ERR(target)) {
1109                 ret = PTR_ERR(target);
1110                 goto out;
1111         }
1112         t->u.kernel.target = target;
1113 
1114         off += xt_compat_target_offset(target);
1115         *size += off;
1116         ret = xt_compat_add_offset(NFPROTO_ARP, entry_offset, off);
1117         if (ret)
1118                 goto release_target;
1119 
1120         return 0;
1121 
1122 release_target:
1123         module_put(t->u.kernel.target->me);
1124 out:
1125         return ret;
1126 }
1127 
1128 static void
1129 compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr,
1130                             unsigned int *size,
1131                             struct xt_table_info *newinfo, unsigned char *base)
1132 {
1133         struct xt_entry_target *t;
1134         struct xt_target *target;
1135         struct arpt_entry *de;
1136         unsigned int origsize;
1137         int h;
1138 
1139         origsize = *size;
1140         de = (struct arpt_entry *)*dstptr;
1141         memcpy(de, e, sizeof(struct arpt_entry));
1142         memcpy(&de->counters, &e->counters, sizeof(e->counters));
1143 
1144         *dstptr += sizeof(struct arpt_entry);
1145         *size += sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
1146 
1147         de->target_offset = e->target_offset - (origsize - *size);
1148         t = compat_arpt_get_target(e);
1149         target = t->u.kernel.target;
1150         xt_compat_target_from_user(t, dstptr, size);
1151 
1152         de->next_offset = e->next_offset - (origsize - *size);
1153         for (h = 0; h < NF_ARP_NUMHOOKS; h++) {
1154                 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1155                         newinfo->hook_entry[h] -= origsize - *size;
1156                 if ((unsigned char *)de - base < newinfo->underflow[h])
1157                         newinfo->underflow[h] -= origsize - *size;
1158         }
1159 }
1160 
1161 static int translate_compat_table(struct xt_table_info **pinfo,
1162                                   void **pentry0,
1163                                   const struct compat_arpt_replace *compatr)
1164 {
1165         unsigned int i, j;
1166         struct xt_table_info *newinfo, *info;
1167         void *pos, *entry0, *entry1;
1168         struct compat_arpt_entry *iter0;
1169         struct arpt_replace repl;
1170         unsigned int size;
1171         int ret = 0;
1172 
1173         info = *pinfo;
1174         entry0 = *pentry0;
1175         size = compatr->size;
1176         info->number = compatr->num_entries;
1177 
1178         j = 0;
1179         xt_compat_lock(NFPROTO_ARP);
1180         xt_compat_init_offsets(NFPROTO_ARP, compatr->num_entries);
1181         /* Walk through entries, checking offsets. */
1182         xt_entry_foreach(iter0, entry0, compatr->size) {
1183                 ret = check_compat_entry_size_and_hooks(iter0, info, &size,
1184                                                         entry0,
1185                                                         entry0 + compatr->size);
1186                 if (ret != 0)
1187                         goto out_unlock;
1188                 ++j;
1189         }
1190 
1191         ret = -EINVAL;
1192         if (j != compatr->num_entries)
1193                 goto out_unlock;
1194 
1195         ret = -ENOMEM;
1196         newinfo = xt_alloc_table_info(size);
1197         if (!newinfo)
1198                 goto out_unlock;
1199 
1200         newinfo->number = compatr->num_entries;
1201         for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
1202                 newinfo->hook_entry[i] = info->hook_entry[i];
1203                 newinfo->underflow[i] = info->underflow[i];
1204         }
1205         entry1 = newinfo->entries;
1206         pos = entry1;
1207         size = compatr->size;
1208         xt_entry_foreach(iter0, entry0, compatr->size)
1209                 compat_copy_entry_from_user(iter0, &pos, &size,
1210                                             newinfo, entry1);
1211 
1212         /* all module references in entry0 are now gone */
1213 
1214         xt_compat_flush_offsets(NFPROTO_ARP);
1215         xt_compat_unlock(NFPROTO_ARP);
1216 
1217         memcpy(&repl, compatr, sizeof(*compatr));
1218 
1219         for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
1220                 repl.hook_entry[i] = newinfo->hook_entry[i];
1221                 repl.underflow[i] = newinfo->underflow[i];
1222         }
1223 
1224         repl.num_counters = 0;
1225         repl.counters = NULL;
1226         repl.size = newinfo->size;
1227         ret = translate_table(newinfo, entry1, &repl);
1228         if (ret)
1229                 goto free_newinfo;
1230 
1231         *pinfo = newinfo;
1232         *pentry0 = entry1;
1233         xt_free_table_info(info);
1234         return 0;
1235 
1236 free_newinfo:
1237         xt_free_table_info(newinfo);
1238         return ret;
1239 out_unlock:
1240         xt_compat_flush_offsets(NFPROTO_ARP);
1241         xt_compat_unlock(NFPROTO_ARP);
1242         xt_entry_foreach(iter0, entry0, compatr->size) {
1243                 if (j-- == 0)
1244                         break;
1245                 compat_release_entry(iter0);
1246         }
1247         return ret;
1248 }
1249 
1250 static int compat_do_replace(struct net *net, void __user *user,
1251                              unsigned int len)
1252 {
1253         int ret;
1254         struct compat_arpt_replace tmp;
1255         struct xt_table_info *newinfo;
1256         void *loc_cpu_entry;
1257         struct arpt_entry *iter;
1258 
1259         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1260                 return -EFAULT;
1261 
1262         /* overflow check */
1263         if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1264                 return -ENOMEM;
1265         if (tmp.num_counters == 0)
1266                 return -EINVAL;
1267 
1268         tmp.name[sizeof(tmp.name)-1] = 0;
1269 
1270         newinfo = xt_alloc_table_info(tmp.size);
1271         if (!newinfo)
1272                 return -ENOMEM;
1273 
1274         loc_cpu_entry = newinfo->entries;
1275         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp), tmp.size) != 0) {
1276                 ret = -EFAULT;
1277                 goto free_newinfo;
1278         }
1279 
1280         ret = translate_compat_table(&newinfo, &loc_cpu_entry, &tmp);
1281         if (ret != 0)
1282                 goto free_newinfo;
1283 
1284         ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1285                            tmp.num_counters, compat_ptr(tmp.counters));
1286         if (ret)
1287                 goto free_newinfo_untrans;
1288         return 0;
1289 
1290  free_newinfo_untrans:
1291         xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1292                 cleanup_entry(iter);
1293  free_newinfo:
1294         xt_free_table_info(newinfo);
1295         return ret;
1296 }
1297 
1298 static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user,
1299                                   unsigned int len)
1300 {
1301         int ret;
1302 
1303         if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1304                 return -EPERM;
1305 
1306         switch (cmd) {
1307         case ARPT_SO_SET_REPLACE:
1308                 ret = compat_do_replace(sock_net(sk), user, len);
1309                 break;
1310 
1311         case ARPT_SO_SET_ADD_COUNTERS:
1312                 ret = do_add_counters(sock_net(sk), user, len, 1);
1313                 break;
1314 
1315         default:
1316                 ret = -EINVAL;
1317         }
1318 
1319         return ret;
1320 }
1321 
1322 static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr,
1323                                      compat_uint_t *size,
1324                                      struct xt_counters *counters,
1325                                      unsigned int i)
1326 {
1327         struct xt_entry_target *t;
1328         struct compat_arpt_entry __user *ce;
1329         u_int16_t target_offset, next_offset;
1330         compat_uint_t origsize;
1331         int ret;
1332 
1333         origsize = *size;
1334         ce = (struct compat_arpt_entry __user *)*dstptr;
1335         if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 ||
1336             copy_to_user(&ce->counters, &counters[i],
1337             sizeof(counters[i])) != 0)
1338                 return -EFAULT;
1339 
1340         *dstptr += sizeof(struct compat_arpt_entry);
1341         *size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
1342 
1343         target_offset = e->target_offset - (origsize - *size);
1344 
1345         t = arpt_get_target(e);
1346         ret = xt_compat_target_to_user(t, dstptr, size);
1347         if (ret)
1348                 return ret;
1349         next_offset = e->next_offset - (origsize - *size);
1350         if (put_user(target_offset, &ce->target_offset) != 0 ||
1351             put_user(next_offset, &ce->next_offset) != 0)
1352                 return -EFAULT;
1353         return 0;
1354 }
1355 
1356 static int compat_copy_entries_to_user(unsigned int total_size,
1357                                        struct xt_table *table,
1358                                        void __user *userptr)
1359 {
1360         struct xt_counters *counters;
1361         const struct xt_table_info *private = table->private;
1362         void __user *pos;
1363         unsigned int size;
1364         int ret = 0;
1365         unsigned int i = 0;
1366         struct arpt_entry *iter;
1367 
1368         counters = alloc_counters(table);
1369         if (IS_ERR(counters))
1370                 return PTR_ERR(counters);
1371 
1372         pos = userptr;
1373         size = total_size;
1374         xt_entry_foreach(iter, private->entries, total_size) {
1375                 ret = compat_copy_entry_to_user(iter, &pos,
1376                                                 &size, counters, i++);
1377                 if (ret != 0)
1378                         break;
1379         }
1380         vfree(counters);
1381         return ret;
1382 }
1383 
1384 struct compat_arpt_get_entries {
1385         char name[XT_TABLE_MAXNAMELEN];
1386         compat_uint_t size;
1387         struct compat_arpt_entry entrytable[0];
1388 };
1389 
1390 static int compat_get_entries(struct net *net,
1391                               struct compat_arpt_get_entries __user *uptr,
1392                               int *len)
1393 {
1394         int ret;
1395         struct compat_arpt_get_entries get;
1396         struct xt_table *t;
1397 
1398         if (*len < sizeof(get))
1399                 return -EINVAL;
1400         if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1401                 return -EFAULT;
1402         if (*len != sizeof(struct compat_arpt_get_entries) + get.size)
1403                 return -EINVAL;
1404 
1405         get.name[sizeof(get.name) - 1] = '\0';
1406 
1407         xt_compat_lock(NFPROTO_ARP);
1408         t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
1409         if (!IS_ERR_OR_NULL(t)) {
1410                 const struct xt_table_info *private = t->private;
1411                 struct xt_table_info info;
1412 
1413                 ret = compat_table_info(private, &info);
1414                 if (!ret && get.size == info.size) {
1415                         ret = compat_copy_entries_to_user(private->size,
1416                                                           t, uptr->entrytable);
1417                 } else if (!ret)
1418                         ret = -EAGAIN;
1419 
1420                 xt_compat_flush_offsets(NFPROTO_ARP);
1421                 module_put(t->me);
1422                 xt_table_unlock(t);
1423         } else
1424                 ret = t ? PTR_ERR(t) : -ENOENT;
1425 
1426         xt_compat_unlock(NFPROTO_ARP);
1427         return ret;
1428 }
1429 
1430 static int do_arpt_get_ctl(struct sock *, int, void __user *, int *);
1431 
1432 static int compat_do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user,
1433                                   int *len)
1434 {
1435         int ret;
1436 
1437         if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1438                 return -EPERM;
1439 
1440         switch (cmd) {
1441         case ARPT_SO_GET_INFO:
1442                 ret = get_info(sock_net(sk), user, len, 1);
1443                 break;
1444         case ARPT_SO_GET_ENTRIES:
1445                 ret = compat_get_entries(sock_net(sk), user, len);
1446                 break;
1447         default:
1448                 ret = do_arpt_get_ctl(sk, cmd, user, len);
1449         }
1450         return ret;
1451 }
1452 #endif
1453 
1454 static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1455 {
1456         int ret;
1457 
1458         if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1459                 return -EPERM;
1460 
1461         switch (cmd) {
1462         case ARPT_SO_SET_REPLACE:
1463                 ret = do_replace(sock_net(sk), user, len);
1464                 break;
1465 
1466         case ARPT_SO_SET_ADD_COUNTERS:
1467                 ret = do_add_counters(sock_net(sk), user, len, 0);
1468                 break;
1469 
1470         default:
1471                 ret = -EINVAL;
1472         }
1473 
1474         return ret;
1475 }
1476 
1477 static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1478 {
1479         int ret;
1480 
1481         if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1482                 return -EPERM;
1483 
1484         switch (cmd) {
1485         case ARPT_SO_GET_INFO:
1486                 ret = get_info(sock_net(sk), user, len, 0);
1487                 break;
1488 
1489         case ARPT_SO_GET_ENTRIES:
1490                 ret = get_entries(sock_net(sk), user, len);
1491                 break;
1492 
1493         case ARPT_SO_GET_REVISION_TARGET: {
1494                 struct xt_get_revision rev;
1495 
1496                 if (*len != sizeof(rev)) {
1497                         ret = -EINVAL;
1498                         break;
1499                 }
1500                 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1501                         ret = -EFAULT;
1502                         break;
1503                 }
1504                 rev.name[sizeof(rev.name)-1] = 0;
1505 
1506                 try_then_request_module(xt_find_revision(NFPROTO_ARP, rev.name,
1507                                                          rev.revision, 1, &ret),
1508                                         "arpt_%s", rev.name);
1509                 break;
1510         }
1511 
1512         default:
1513                 ret = -EINVAL;
1514         }
1515 
1516         return ret;
1517 }
1518 
1519 static void __arpt_unregister_table(struct xt_table *table)
1520 {
1521         struct xt_table_info *private;
1522         void *loc_cpu_entry;
1523         struct module *table_owner = table->me;
1524         struct arpt_entry *iter;
1525 
1526         private = xt_unregister_table(table);
1527 
1528         /* Decrease module usage counts and free resources */
1529         loc_cpu_entry = private->entries;
1530         xt_entry_foreach(iter, loc_cpu_entry, private->size)
1531                 cleanup_entry(iter);
1532         if (private->number > private->initial_entries)
1533                 module_put(table_owner);
1534         xt_free_table_info(private);
1535 }
1536 
1537 int arpt_register_table(struct net *net,
1538                         const struct xt_table *table,
1539                         const struct arpt_replace *repl,
1540                         const struct nf_hook_ops *ops,
1541                         struct xt_table **res)
1542 {
1543         int ret;
1544         struct xt_table_info *newinfo;
1545         struct xt_table_info bootstrap = {0};
1546         void *loc_cpu_entry;
1547         struct xt_table *new_table;
1548 
1549         newinfo = xt_alloc_table_info(repl->size);
1550         if (!newinfo)
1551                 return -ENOMEM;
1552 
1553         loc_cpu_entry = newinfo->entries;
1554         memcpy(loc_cpu_entry, repl->entries, repl->size);
1555 
1556         ret = translate_table(newinfo, loc_cpu_entry, repl);
1557         if (ret != 0)
1558                 goto out_free;
1559 
1560         new_table = xt_register_table(net, table, &bootstrap, newinfo);
1561         if (IS_ERR(new_table)) {
1562                 ret = PTR_ERR(new_table);
1563                 goto out_free;
1564         }
1565 
1566         /* set res now, will see skbs right after nf_register_net_hooks */
1567         WRITE_ONCE(*res, new_table);
1568 
1569         ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
1570         if (ret != 0) {
1571                 __arpt_unregister_table(new_table);
1572                 *res = NULL;
1573         }
1574 
1575         return ret;
1576 
1577 out_free:
1578         xt_free_table_info(newinfo);
1579         return ret;
1580 }
1581 
1582 void arpt_unregister_table(struct net *net, struct xt_table *table,
1583                            const struct nf_hook_ops *ops)
1584 {
1585         nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
1586         __arpt_unregister_table(table);
1587 }
1588 
1589 /* The built-in targets: standard (NULL) and error. */
1590 static struct xt_target arpt_builtin_tg[] __read_mostly = {
1591         {
1592                 .name             = XT_STANDARD_TARGET,
1593                 .targetsize       = sizeof(int),
1594                 .family           = NFPROTO_ARP,
1595 #ifdef CONFIG_COMPAT
1596                 .compatsize       = sizeof(compat_int_t),
1597                 .compat_from_user = compat_standard_from_user,
1598                 .compat_to_user   = compat_standard_to_user,
1599 #endif
1600         },
1601         {
1602                 .name             = XT_ERROR_TARGET,
1603                 .target           = arpt_error,
1604                 .targetsize       = XT_FUNCTION_MAXNAMELEN,
1605                 .family           = NFPROTO_ARP,
1606         },
1607 };
1608 
1609 static struct nf_sockopt_ops arpt_sockopts = {
1610         .pf             = PF_INET,
1611         .set_optmin     = ARPT_BASE_CTL,
1612         .set_optmax     = ARPT_SO_SET_MAX+1,
1613         .set            = do_arpt_set_ctl,
1614 #ifdef CONFIG_COMPAT
1615         .compat_set     = compat_do_arpt_set_ctl,
1616 #endif
1617         .get_optmin     = ARPT_BASE_CTL,
1618         .get_optmax     = ARPT_SO_GET_MAX+1,
1619         .get            = do_arpt_get_ctl,
1620 #ifdef CONFIG_COMPAT
1621         .compat_get     = compat_do_arpt_get_ctl,
1622 #endif
1623         .owner          = THIS_MODULE,
1624 };
1625 
1626 static int __net_init arp_tables_net_init(struct net *net)
1627 {
1628         return xt_proto_init(net, NFPROTO_ARP);
1629 }
1630 
1631 static void __net_exit arp_tables_net_exit(struct net *net)
1632 {
1633         xt_proto_fini(net, NFPROTO_ARP);
1634 }
1635 
1636 static struct pernet_operations arp_tables_net_ops = {
1637         .init = arp_tables_net_init,
1638         .exit = arp_tables_net_exit,
1639 };
1640 
1641 static int __init arp_tables_init(void)
1642 {
1643         int ret;
1644 
1645         ret = register_pernet_subsys(&arp_tables_net_ops);
1646         if (ret < 0)
1647                 goto err1;
1648 
1649         /* No one else will be downing sem now, so we won't sleep */
1650         ret = xt_register_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg));
1651         if (ret < 0)
1652                 goto err2;
1653 
1654         /* Register setsockopt */
1655         ret = nf_register_sockopt(&arpt_sockopts);
1656         if (ret < 0)
1657                 goto err4;
1658 
1659         pr_info("arp_tables: (C) 2002 David S. Miller\n");
1660         return 0;
1661 
1662 err4:
1663         xt_unregister_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg));
1664 err2:
1665         unregister_pernet_subsys(&arp_tables_net_ops);
1666 err1:
1667         return ret;
1668 }
1669 
1670 static void __exit arp_tables_fini(void)
1671 {
1672         nf_unregister_sockopt(&arpt_sockopts);
1673         xt_unregister_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg));
1674         unregister_pernet_subsys(&arp_tables_net_ops);
1675 }
1676 
1677 EXPORT_SYMBOL(arpt_register_table);
1678 EXPORT_SYMBOL(arpt_unregister_table);
1679 EXPORT_SYMBOL(arpt_do_table);
1680 
1681 module_init(arp_tables_init);
1682 module_exit(arp_tables_fini);
1683 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp