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