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 = READ_ONCE(table->private); /* Address dependency. */
 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 inline int check_target(struct arpt_entry *e, const char *name)
 388{
 389        struct xt_entry_target *t = arpt_get_target(e);
 390        struct xt_tgchk_param par = {
 391                .table     = name,
 392                .entryinfo = e,
 393                .target    = t->u.kernel.target,
 394                .targinfo  = t->data,
 395                .hook_mask = e->comefrom,
 396                .family    = NFPROTO_ARP,
 397        };
 398
 399        return xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false);
 400}
 401
 402static inline int
 403find_check_entry(struct arpt_entry *e, const char *name, unsigned int size,
 404                 struct xt_percpu_counter_alloc_state *alloc_state)
 405{
 406        struct xt_entry_target *t;
 407        struct xt_target *target;
 408        int ret;
 409
 410        if (!xt_percpu_counter_alloc(alloc_state, &e->counters))
 411                return -ENOMEM;
 412
 413        t = arpt_get_target(e);
 414        target = xt_request_find_target(NFPROTO_ARP, t->u.user.name,
 415                                        t->u.user.revision);
 416        if (IS_ERR(target)) {
 417                ret = PTR_ERR(target);
 418                goto out;
 419        }
 420        t->u.kernel.target = target;
 421
 422        ret = check_target(e, name);
 423        if (ret)
 424                goto err;
 425        return 0;
 426err:
 427        module_put(t->u.kernel.target->me);
 428out:
 429        xt_percpu_counter_free(&e->counters);
 430
 431        return ret;
 432}
 433
 434static bool check_underflow(const struct arpt_entry *e)
 435{
 436        const struct xt_entry_target *t;
 437        unsigned int verdict;
 438
 439        if (!unconditional(e))
 440                return false;
 441        t = arpt_get_target_c(e);
 442        if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
 443                return false;
 444        verdict = ((struct xt_standard_target *)t)->verdict;
 445        verdict = -verdict - 1;
 446        return verdict == NF_DROP || verdict == NF_ACCEPT;
 447}
 448
 449static inline int check_entry_size_and_hooks(struct arpt_entry *e,
 450                                             struct xt_table_info *newinfo,
 451                                             const unsigned char *base,
 452                                             const unsigned char *limit,
 453                                             const unsigned int *hook_entries,
 454                                             const unsigned int *underflows,
 455                                             unsigned int valid_hooks)
 456{
 457        unsigned int h;
 458        int err;
 459
 460        if ((unsigned long)e % __alignof__(struct arpt_entry) != 0 ||
 461            (unsigned char *)e + sizeof(struct arpt_entry) >= limit ||
 462            (unsigned char *)e + e->next_offset > limit)
 463                return -EINVAL;
 464
 465        if (e->next_offset
 466            < sizeof(struct arpt_entry) + sizeof(struct xt_entry_target))
 467                return -EINVAL;
 468
 469        if (!arp_checkentry(&e->arp))
 470                return -EINVAL;
 471
 472        err = xt_check_entry_offsets(e, e->elems, e->target_offset,
 473                                     e->next_offset);
 474        if (err)
 475                return err;
 476
 477        /* Check hooks & underflows */
 478        for (h = 0; h < NF_ARP_NUMHOOKS; h++) {
 479                if (!(valid_hooks & (1 << h)))
 480                        continue;
 481                if ((unsigned char *)e - base == hook_entries[h])
 482                        newinfo->hook_entry[h] = hook_entries[h];
 483                if ((unsigned char *)e - base == underflows[h]) {
 484                        if (!check_underflow(e))
 485                                return -EINVAL;
 486
 487                        newinfo->underflow[h] = underflows[h];
 488                }
 489        }
 490
 491        /* Clear counters and comefrom */
 492        e->counters = ((struct xt_counters) { 0, 0 });
 493        e->comefrom = 0;
 494        return 0;
 495}
 496
 497static inline void cleanup_entry(struct arpt_entry *e)
 498{
 499        struct xt_tgdtor_param par;
 500        struct xt_entry_target *t;
 501
 502        t = arpt_get_target(e);
 503        par.target   = t->u.kernel.target;
 504        par.targinfo = t->data;
 505        par.family   = NFPROTO_ARP;
 506        if (par.target->destroy != NULL)
 507                par.target->destroy(&par);
 508        module_put(par.target->me);
 509        xt_percpu_counter_free(&e->counters);
 510}
 511
 512/* Checks and translates the user-supplied table segment (held in
 513 * newinfo).
 514 */
 515static int translate_table(struct xt_table_info *newinfo, void *entry0,
 516                           const struct arpt_replace *repl)
 517{
 518        struct xt_percpu_counter_alloc_state alloc_state = { 0 };
 519        struct arpt_entry *iter;
 520        unsigned int *offsets;
 521        unsigned int i;
 522        int ret = 0;
 523
 524        newinfo->size = repl->size;
 525        newinfo->number = repl->num_entries;
 526
 527        /* Init all hooks to impossible value. */
 528        for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
 529                newinfo->hook_entry[i] = 0xFFFFFFFF;
 530                newinfo->underflow[i] = 0xFFFFFFFF;
 531        }
 532
 533        offsets = xt_alloc_entry_offsets(newinfo->number);
 534        if (!offsets)
 535                return -ENOMEM;
 536        i = 0;
 537
 538        /* Walk through entries, checking offsets. */
 539        xt_entry_foreach(iter, entry0, newinfo->size) {
 540                ret = check_entry_size_and_hooks(iter, newinfo, entry0,
 541                                                 entry0 + repl->size,
 542                                                 repl->hook_entry,
 543                                                 repl->underflow,
 544                                                 repl->valid_hooks);
 545                if (ret != 0)
 546                        goto out_free;
 547                if (i < repl->num_entries)
 548                        offsets[i] = (void *)iter - entry0;
 549                ++i;
 550                if (strcmp(arpt_get_target(iter)->u.user.name,
 551                    XT_ERROR_TARGET) == 0)
 552                        ++newinfo->stacksize;
 553        }
 554
 555        ret = -EINVAL;
 556        if (i != repl->num_entries)
 557                goto out_free;
 558
 559        ret = xt_check_table_hooks(newinfo, repl->valid_hooks);
 560        if (ret)
 561                goto out_free;
 562
 563        if (!mark_source_chains(newinfo, repl->valid_hooks, entry0, offsets)) {
 564                ret = -ELOOP;
 565                goto out_free;
 566        }
 567        kvfree(offsets);
 568
 569        /* Finally, each sanity check must pass */
 570        i = 0;
 571        xt_entry_foreach(iter, entry0, newinfo->size) {
 572                ret = find_check_entry(iter, repl->name, repl->size,
 573                                       &alloc_state);
 574                if (ret != 0)
 575                        break;
 576                ++i;
 577        }
 578
 579        if (ret != 0) {
 580                xt_entry_foreach(iter, entry0, newinfo->size) {
 581                        if (i-- == 0)
 582                                break;
 583                        cleanup_entry(iter);
 584                }
 585                return ret;
 586        }
 587
 588        return ret;
 589 out_free:
 590        kvfree(offsets);
 591        return ret;
 592}
 593
 594static void get_counters(const struct xt_table_info *t,
 595                         struct xt_counters counters[])
 596{
 597        struct arpt_entry *iter;
 598        unsigned int cpu;
 599        unsigned int i;
 600
 601        for_each_possible_cpu(cpu) {
 602                seqcount_t *s = &per_cpu(xt_recseq, cpu);
 603
 604                i = 0;
 605                xt_entry_foreach(iter, t->entries, t->size) {
 606                        struct xt_counters *tmp;
 607                        u64 bcnt, pcnt;
 608                        unsigned int start;
 609
 610                        tmp = xt_get_per_cpu_counter(&iter->counters, cpu);
 611                        do {
 612                                start = read_seqcount_begin(s);
 613                                bcnt = tmp->bcnt;
 614                                pcnt = tmp->pcnt;
 615                        } while (read_seqcount_retry(s, start));
 616
 617                        ADD_COUNTER(counters[i], bcnt, pcnt);
 618                        ++i;
 619                        cond_resched();
 620                }
 621        }
 622}
 623
 624static void get_old_counters(const struct xt_table_info *t,
 625                             struct xt_counters counters[])
 626{
 627        struct arpt_entry *iter;
 628        unsigned int cpu, i;
 629
 630        for_each_possible_cpu(cpu) {
 631                i = 0;
 632                xt_entry_foreach(iter, t->entries, t->size) {
 633                        struct xt_counters *tmp;
 634
 635                        tmp = xt_get_per_cpu_counter(&iter->counters, cpu);
 636                        ADD_COUNTER(counters[i], tmp->bcnt, tmp->pcnt);
 637                        ++i;
 638                }
 639                cond_resched();
 640        }
 641}
 642
 643static struct xt_counters *alloc_counters(const struct xt_table *table)
 644{
 645        unsigned int countersize;
 646        struct xt_counters *counters;
 647        const struct xt_table_info *private = table->private;
 648
 649        /* We need atomic snapshot of counters: rest doesn't change
 650         * (other than comefrom, which userspace doesn't care
 651         * about).
 652         */
 653        countersize = sizeof(struct xt_counters) * private->number;
 654        counters = vzalloc(countersize);
 655
 656        if (counters == NULL)
 657                return ERR_PTR(-ENOMEM);
 658
 659        get_counters(private, counters);
 660
 661        return counters;
 662}
 663
 664static int copy_entries_to_user(unsigned int total_size,
 665                                const struct xt_table *table,
 666                                void __user *userptr)
 667{
 668        unsigned int off, num;
 669        const struct arpt_entry *e;
 670        struct xt_counters *counters;
 671        struct xt_table_info *private = table->private;
 672        int ret = 0;
 673        void *loc_cpu_entry;
 674
 675        counters = alloc_counters(table);
 676        if (IS_ERR(counters))
 677                return PTR_ERR(counters);
 678
 679        loc_cpu_entry = private->entries;
 680
 681        /* FIXME: use iterator macros --RR */
 682        /* ... then go back and fix counters and names */
 683        for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
 684                const struct xt_entry_target *t;
 685
 686                e = loc_cpu_entry + off;
 687                if (copy_to_user(userptr + off, e, sizeof(*e))) {
 688                        ret = -EFAULT;
 689                        goto free_counters;
 690                }
 691                if (copy_to_user(userptr + off
 692                                 + offsetof(struct arpt_entry, counters),
 693                                 &counters[num],
 694                                 sizeof(counters[num])) != 0) {
 695                        ret = -EFAULT;
 696                        goto free_counters;
 697                }
 698
 699                t = arpt_get_target_c(e);
 700                if (xt_target_to_user(t, userptr + off + e->target_offset)) {
 701                        ret = -EFAULT;
 702                        goto free_counters;
 703                }
 704        }
 705
 706 free_counters:
 707        vfree(counters);
 708        return ret;
 709}
 710
 711#ifdef CONFIG_COMPAT
 712static void compat_standard_from_user(void *dst, const void *src)
 713{
 714        int v = *(compat_int_t *)src;
 715
 716        if (v > 0)
 717                v += xt_compat_calc_jump(NFPROTO_ARP, v);
 718        memcpy(dst, &v, sizeof(v));
 719}
 720
 721static int compat_standard_to_user(void __user *dst, const void *src)
 722{
 723        compat_int_t cv = *(int *)src;
 724
 725        if (cv > 0)
 726                cv -= xt_compat_calc_jump(NFPROTO_ARP, cv);
 727        return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
 728}
 729
 730static int compat_calc_entry(const struct arpt_entry *e,
 731                             const struct xt_table_info *info,
 732                             const void *base, struct xt_table_info *newinfo)
 733{
 734        const struct xt_entry_target *t;
 735        unsigned int entry_offset;
 736        int off, i, ret;
 737
 738        off = sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
 739        entry_offset = (void *)e - base;
 740
 741        t = arpt_get_target_c(e);
 742        off += xt_compat_target_offset(t->u.kernel.target);
 743        newinfo->size -= off;
 744        ret = xt_compat_add_offset(NFPROTO_ARP, entry_offset, off);
 745        if (ret)
 746                return ret;
 747
 748        for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
 749                if (info->hook_entry[i] &&
 750                    (e < (struct arpt_entry *)(base + info->hook_entry[i])))
 751                        newinfo->hook_entry[i] -= off;
 752                if (info->underflow[i] &&
 753                    (e < (struct arpt_entry *)(base + info->underflow[i])))
 754                        newinfo->underflow[i] -= off;
 755        }
 756        return 0;
 757}
 758
 759static int compat_table_info(const struct xt_table_info *info,
 760                             struct xt_table_info *newinfo)
 761{
 762        struct arpt_entry *iter;
 763        const void *loc_cpu_entry;
 764        int ret;
 765
 766        if (!newinfo || !info)
 767                return -EINVAL;
 768
 769        /* we dont care about newinfo->entries */
 770        memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
 771        newinfo->initial_entries = 0;
 772        loc_cpu_entry = info->entries;
 773        ret = xt_compat_init_offsets(NFPROTO_ARP, info->number);
 774        if (ret)
 775                return ret;
 776        xt_entry_foreach(iter, loc_cpu_entry, info->size) {
 777                ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
 778                if (ret != 0)
 779                        return ret;
 780        }
 781        return 0;
 782}
 783#endif
 784
 785static int get_info(struct net *net, void __user *user,
 786                    const int *len, int compat)
 787{
 788        char name[XT_TABLE_MAXNAMELEN];
 789        struct xt_table *t;
 790        int ret;
 791
 792        if (*len != sizeof(struct arpt_getinfo))
 793                return -EINVAL;
 794
 795        if (copy_from_user(name, user, sizeof(name)) != 0)
 796                return -EFAULT;
 797
 798        name[XT_TABLE_MAXNAMELEN-1] = '\0';
 799#ifdef CONFIG_COMPAT
 800        if (compat)
 801                xt_compat_lock(NFPROTO_ARP);
 802#endif
 803        t = xt_request_find_table_lock(net, NFPROTO_ARP, name);
 804        if (!IS_ERR(t)) {
 805                struct arpt_getinfo info;
 806                const struct xt_table_info *private = t->private;
 807#ifdef CONFIG_COMPAT
 808                struct xt_table_info tmp;
 809
 810                if (compat) {
 811                        ret = compat_table_info(private, &tmp);
 812                        xt_compat_flush_offsets(NFPROTO_ARP);
 813                        private = &tmp;
 814                }
 815#endif
 816                memset(&info, 0, sizeof(info));
 817                info.valid_hooks = t->valid_hooks;
 818                memcpy(info.hook_entry, private->hook_entry,
 819                       sizeof(info.hook_entry));
 820                memcpy(info.underflow, private->underflow,
 821                       sizeof(info.underflow));
 822                info.num_entries = private->number;
 823                info.size = private->size;
 824                strcpy(info.name, name);
 825
 826                if (copy_to_user(user, &info, *len) != 0)
 827                        ret = -EFAULT;
 828                else
 829                        ret = 0;
 830                xt_table_unlock(t);
 831                module_put(t->me);
 832        } else
 833                ret = PTR_ERR(t);
 834#ifdef CONFIG_COMPAT
 835        if (compat)
 836                xt_compat_unlock(NFPROTO_ARP);
 837#endif
 838        return ret;
 839}
 840
 841static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
 842                       const int *len)
 843{
 844        int ret;
 845        struct arpt_get_entries get;
 846        struct xt_table *t;
 847
 848        if (*len < sizeof(get))
 849                return -EINVAL;
 850        if (copy_from_user(&get, uptr, sizeof(get)) != 0)
 851                return -EFAULT;
 852        if (*len != sizeof(struct arpt_get_entries) + get.size)
 853                return -EINVAL;
 854
 855        get.name[sizeof(get.name) - 1] = '\0';
 856
 857        t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
 858        if (!IS_ERR(t)) {
 859                const struct xt_table_info *private = t->private;
 860
 861                if (get.size == private->size)
 862                        ret = copy_entries_to_user(private->size,
 863                                                   t, uptr->entrytable);
 864                else
 865                        ret = -EAGAIN;
 866
 867                module_put(t->me);
 868                xt_table_unlock(t);
 869        } else
 870                ret = PTR_ERR(t);
 871
 872        return ret;
 873}
 874
 875static int __do_replace(struct net *net, const char *name,
 876                        unsigned int valid_hooks,
 877                        struct xt_table_info *newinfo,
 878                        unsigned int num_counters,
 879                        void __user *counters_ptr)
 880{
 881        int ret;
 882        struct xt_table *t;
 883        struct xt_table_info *oldinfo;
 884        struct xt_counters *counters;
 885        void *loc_cpu_old_entry;
 886        struct arpt_entry *iter;
 887
 888        ret = 0;
 889        counters = xt_counters_alloc(num_counters);
 890        if (!counters) {
 891                ret = -ENOMEM;
 892                goto out;
 893        }
 894
 895        t = xt_request_find_table_lock(net, NFPROTO_ARP, name);
 896        if (IS_ERR(t)) {
 897                ret = PTR_ERR(t);
 898                goto free_newinfo_counters_untrans;
 899        }
 900
 901        /* You lied! */
 902        if (valid_hooks != t->valid_hooks) {
 903                ret = -EINVAL;
 904                goto put_module;
 905        }
 906
 907        oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
 908        if (!oldinfo)
 909                goto put_module;
 910
 911        /* Update module usage count based on number of rules */
 912        if ((oldinfo->number > oldinfo->initial_entries) ||
 913            (newinfo->number <= oldinfo->initial_entries))
 914                module_put(t->me);
 915        if ((oldinfo->number > oldinfo->initial_entries) &&
 916            (newinfo->number <= oldinfo->initial_entries))
 917                module_put(t->me);
 918
 919        xt_table_unlock(t);
 920
 921        get_old_counters(oldinfo, counters);
 922
 923        /* Decrease module usage counts and free resource */
 924        loc_cpu_old_entry = oldinfo->entries;
 925        xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size)
 926                cleanup_entry(iter);
 927
 928        xt_free_table_info(oldinfo);
 929        if (copy_to_user(counters_ptr, counters,
 930                         sizeof(struct xt_counters) * num_counters) != 0) {
 931                /* Silent error, can't fail, new table is already in place */
 932                net_warn_ratelimited("arptables: counters copy to user failed while replacing table\n");
 933        }
 934        vfree(counters);
 935        return ret;
 936
 937 put_module:
 938        module_put(t->me);
 939        xt_table_unlock(t);
 940 free_newinfo_counters_untrans:
 941        vfree(counters);
 942 out:
 943        return ret;
 944}
 945
 946static int do_replace(struct net *net, const void __user *user,
 947                      unsigned int len)
 948{
 949        int ret;
 950        struct arpt_replace tmp;
 951        struct xt_table_info *newinfo;
 952        void *loc_cpu_entry;
 953        struct arpt_entry *iter;
 954
 955        if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
 956                return -EFAULT;
 957
 958        /* overflow check */
 959        if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
 960                return -ENOMEM;
 961        if (tmp.num_counters == 0)
 962                return -EINVAL;
 963
 964        tmp.name[sizeof(tmp.name)-1] = 0;
 965
 966        newinfo = xt_alloc_table_info(tmp.size);
 967        if (!newinfo)
 968                return -ENOMEM;
 969
 970        loc_cpu_entry = newinfo->entries;
 971        if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
 972                           tmp.size) != 0) {
 973                ret = -EFAULT;
 974                goto free_newinfo;
 975        }
 976
 977        ret = translate_table(newinfo, loc_cpu_entry, &tmp);
 978        if (ret != 0)
 979                goto free_newinfo;
 980
 981        ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
 982                           tmp.num_counters, tmp.counters);
 983        if (ret)
 984                goto free_newinfo_untrans;
 985        return 0;
 986
 987 free_newinfo_untrans:
 988        xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
 989                cleanup_entry(iter);
 990 free_newinfo:
 991        xt_free_table_info(newinfo);
 992        return ret;
 993}
 994
 995static int do_add_counters(struct net *net, const void __user *user,
 996                           unsigned int len, int compat)
 997{
 998        unsigned int i;
 999        struct xt_counters_info tmp;
1000        struct xt_counters *paddc;
1001        struct xt_table *t;
1002        const struct xt_table_info *private;
1003        int ret = 0;
1004        struct arpt_entry *iter;
1005        unsigned int addend;
1006
1007        paddc = xt_copy_counters_from_user(user, len, &tmp, compat);
1008        if (IS_ERR(paddc))
1009                return PTR_ERR(paddc);
1010
1011        t = xt_find_table_lock(net, NFPROTO_ARP, tmp.name);
1012        if (IS_ERR(t)) {
1013                ret = PTR_ERR(t);
1014                goto free;
1015        }
1016
1017        local_bh_disable();
1018        private = t->private;
1019        if (private->number != tmp.num_counters) {
1020                ret = -EINVAL;
1021                goto unlock_up_free;
1022        }
1023
1024        i = 0;
1025
1026        addend = xt_write_recseq_begin();
1027        xt_entry_foreach(iter,  private->entries, private->size) {
1028                struct xt_counters *tmp;
1029
1030                tmp = xt_get_this_cpu_counter(&iter->counters);
1031                ADD_COUNTER(*tmp, paddc[i].bcnt, paddc[i].pcnt);
1032                ++i;
1033        }
1034        xt_write_recseq_end(addend);
1035 unlock_up_free:
1036        local_bh_enable();
1037        xt_table_unlock(t);
1038        module_put(t->me);
1039 free:
1040        vfree(paddc);
1041
1042        return ret;
1043}
1044
1045#ifdef CONFIG_COMPAT
1046struct compat_arpt_replace {
1047        char                            name[XT_TABLE_MAXNAMELEN];
1048        u32                             valid_hooks;
1049        u32                             num_entries;
1050        u32                             size;
1051        u32                             hook_entry[NF_ARP_NUMHOOKS];
1052        u32                             underflow[NF_ARP_NUMHOOKS];
1053        u32                             num_counters;
1054        compat_uptr_t                   counters;
1055        struct compat_arpt_entry        entries[0];
1056};
1057
1058static inline void compat_release_entry(struct compat_arpt_entry *e)
1059{
1060        struct xt_entry_target *t;
1061
1062        t = compat_arpt_get_target(e);
1063        module_put(t->u.kernel.target->me);
1064}
1065
1066static int
1067check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
1068                                  struct xt_table_info *newinfo,
1069                                  unsigned int *size,
1070                                  const unsigned char *base,
1071                                  const unsigned char *limit)
1072{
1073        struct xt_entry_target *t;
1074        struct xt_target *target;
1075        unsigned int entry_offset;
1076        int ret, off;
1077
1078        if ((unsigned long)e % __alignof__(struct compat_arpt_entry) != 0 ||
1079            (unsigned char *)e + sizeof(struct compat_arpt_entry) >= limit ||
1080            (unsigned char *)e + e->next_offset > limit)
1081                return -EINVAL;
1082
1083        if (e->next_offset < sizeof(struct compat_arpt_entry) +
1084                             sizeof(struct compat_xt_entry_target))
1085                return -EINVAL;
1086
1087        if (!arp_checkentry(&e->arp))
1088                return -EINVAL;
1089
1090        ret = xt_compat_check_entry_offsets(e, e->elems, e->target_offset,
1091                                            e->next_offset);
1092        if (ret)
1093                return ret;
1094
1095        off = sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
1096        entry_offset = (void *)e - (void *)base;
1097
1098        t = compat_arpt_get_target(e);
1099        target = xt_request_find_target(NFPROTO_ARP, t->u.user.name,
1100                                        t->u.user.revision);
1101        if (IS_ERR(target)) {
1102                ret = PTR_ERR(target);
1103                goto out;
1104        }
1105        t->u.kernel.target = target;
1106
1107        off += xt_compat_target_offset(target);
1108        *size += off;
1109        ret = xt_compat_add_offset(NFPROTO_ARP, entry_offset, off);
1110        if (ret)
1111                goto release_target;
1112
1113        return 0;
1114
1115release_target:
1116        module_put(t->u.kernel.target->me);
1117out:
1118        return ret;
1119}
1120
1121static void
1122compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr,
1123                            unsigned int *size,
1124                            struct xt_table_info *newinfo, unsigned char *base)
1125{
1126        struct xt_entry_target *t;
1127        struct arpt_entry *de;
1128        unsigned int origsize;
1129        int h;
1130
1131        origsize = *size;
1132        de = *dstptr;
1133        memcpy(de, e, sizeof(struct arpt_entry));
1134        memcpy(&de->counters, &e->counters, sizeof(e->counters));
1135
1136        *dstptr += sizeof(struct arpt_entry);
1137        *size += sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
1138
1139        de->target_offset = e->target_offset - (origsize - *size);
1140        t = compat_arpt_get_target(e);
1141        xt_compat_target_from_user(t, dstptr, size);
1142
1143        de->next_offset = e->next_offset - (origsize - *size);
1144        for (h = 0; h < NF_ARP_NUMHOOKS; h++) {
1145                if ((unsigned char *)de - base < newinfo->hook_entry[h])
1146                        newinfo->hook_entry[h] -= origsize - *size;
1147                if ((unsigned char *)de - base < newinfo->underflow[h])
1148                        newinfo->underflow[h] -= origsize - *size;
1149        }
1150}
1151
1152static int translate_compat_table(struct xt_table_info **pinfo,
1153                                  void **pentry0,
1154                                  const struct compat_arpt_replace *compatr)
1155{
1156        unsigned int i, j;
1157        struct xt_table_info *newinfo, *info;
1158        void *pos, *entry0, *entry1;
1159        struct compat_arpt_entry *iter0;
1160        struct arpt_replace repl;
1161        unsigned int size;
1162        int ret;
1163
1164        info = *pinfo;
1165        entry0 = *pentry0;
1166        size = compatr->size;
1167        info->number = compatr->num_entries;
1168
1169        j = 0;
1170        xt_compat_lock(NFPROTO_ARP);
1171        ret = xt_compat_init_offsets(NFPROTO_ARP, compatr->num_entries);
1172        if (ret)
1173                goto out_unlock;
1174        /* Walk through entries, checking offsets. */
1175        xt_entry_foreach(iter0, entry0, compatr->size) {
1176                ret = check_compat_entry_size_and_hooks(iter0, info, &size,
1177                                                        entry0,
1178                                                        entry0 + compatr->size);
1179                if (ret != 0)
1180                        goto out_unlock;
1181                ++j;
1182        }
1183
1184        ret = -EINVAL;
1185        if (j != compatr->num_entries)
1186                goto out_unlock;
1187
1188        ret = -ENOMEM;
1189        newinfo = xt_alloc_table_info(size);
1190        if (!newinfo)
1191                goto out_unlock;
1192
1193        newinfo->number = compatr->num_entries;
1194        for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
1195                newinfo->hook_entry[i] = compatr->hook_entry[i];
1196                newinfo->underflow[i] = compatr->underflow[i];
1197        }
1198        entry1 = newinfo->entries;
1199        pos = entry1;
1200        size = compatr->size;
1201        xt_entry_foreach(iter0, entry0, compatr->size)
1202                compat_copy_entry_from_user(iter0, &pos, &size,
1203                                            newinfo, entry1);
1204
1205        /* all module references in entry0 are now gone */
1206
1207        xt_compat_flush_offsets(NFPROTO_ARP);
1208        xt_compat_unlock(NFPROTO_ARP);
1209
1210        memcpy(&repl, compatr, sizeof(*compatr));
1211
1212        for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
1213                repl.hook_entry[i] = newinfo->hook_entry[i];
1214                repl.underflow[i] = newinfo->underflow[i];
1215        }
1216
1217        repl.num_counters = 0;
1218        repl.counters = NULL;
1219        repl.size = newinfo->size;
1220        ret = translate_table(newinfo, entry1, &repl);
1221        if (ret)
1222                goto free_newinfo;
1223
1224        *pinfo = newinfo;
1225        *pentry0 = entry1;
1226        xt_free_table_info(info);
1227        return 0;
1228
1229free_newinfo:
1230        xt_free_table_info(newinfo);
1231        return ret;
1232out_unlock:
1233        xt_compat_flush_offsets(NFPROTO_ARP);
1234        xt_compat_unlock(NFPROTO_ARP);
1235        xt_entry_foreach(iter0, entry0, compatr->size) {
1236                if (j-- == 0)
1237                        break;
1238                compat_release_entry(iter0);
1239        }
1240        return ret;
1241}
1242
1243static int compat_do_replace(struct net *net, void __user *user,
1244                             unsigned int len)
1245{
1246        int ret;
1247        struct compat_arpt_replace tmp;
1248        struct xt_table_info *newinfo;
1249        void *loc_cpu_entry;
1250        struct arpt_entry *iter;
1251
1252        if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1253                return -EFAULT;
1254
1255        /* overflow check */
1256        if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1257                return -ENOMEM;
1258        if (tmp.num_counters == 0)
1259                return -EINVAL;
1260
1261        tmp.name[sizeof(tmp.name)-1] = 0;
1262
1263        newinfo = xt_alloc_table_info(tmp.size);
1264        if (!newinfo)
1265                return -ENOMEM;
1266
1267        loc_cpu_entry = newinfo->entries;
1268        if (copy_from_user(loc_cpu_entry, user + sizeof(tmp), tmp.size) != 0) {
1269                ret = -EFAULT;
1270                goto free_newinfo;
1271        }
1272
1273        ret = translate_compat_table(&newinfo, &loc_cpu_entry, &tmp);
1274        if (ret != 0)
1275                goto free_newinfo;
1276
1277        ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1278                           tmp.num_counters, compat_ptr(tmp.counters));
1279        if (ret)
1280                goto free_newinfo_untrans;
1281        return 0;
1282
1283 free_newinfo_untrans:
1284        xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1285                cleanup_entry(iter);
1286 free_newinfo:
1287        xt_free_table_info(newinfo);
1288        return ret;
1289}
1290
1291static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user,
1292                                  unsigned int len)
1293{
1294        int ret;
1295
1296        if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1297                return -EPERM;
1298
1299        switch (cmd) {
1300        case ARPT_SO_SET_REPLACE:
1301                ret = compat_do_replace(sock_net(sk), user, len);
1302                break;
1303
1304        case ARPT_SO_SET_ADD_COUNTERS:
1305                ret = do_add_counters(sock_net(sk), user, len, 1);
1306                break;
1307
1308        default:
1309                ret = -EINVAL;
1310        }
1311
1312        return ret;
1313}
1314
1315static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr,
1316                                     compat_uint_t *size,
1317                                     struct xt_counters *counters,
1318                                     unsigned int i)
1319{
1320        struct xt_entry_target *t;
1321        struct compat_arpt_entry __user *ce;
1322        u_int16_t target_offset, next_offset;
1323        compat_uint_t origsize;
1324        int ret;
1325
1326        origsize = *size;
1327        ce = *dstptr;
1328        if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 ||
1329            copy_to_user(&ce->counters, &counters[i],
1330            sizeof(counters[i])) != 0)
1331                return -EFAULT;
1332
1333        *dstptr += sizeof(struct compat_arpt_entry);
1334        *size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
1335
1336        target_offset = e->target_offset - (origsize - *size);
1337
1338        t = arpt_get_target(e);
1339        ret = xt_compat_target_to_user(t, dstptr, size);
1340        if (ret)
1341                return ret;
1342        next_offset = e->next_offset - (origsize - *size);
1343        if (put_user(target_offset, &ce->target_offset) != 0 ||
1344            put_user(next_offset, &ce->next_offset) != 0)
1345                return -EFAULT;
1346        return 0;
1347}
1348
1349static int compat_copy_entries_to_user(unsigned int total_size,
1350                                       struct xt_table *table,
1351                                       void __user *userptr)
1352{
1353        struct xt_counters *counters;
1354        const struct xt_table_info *private = table->private;
1355        void __user *pos;
1356        unsigned int size;
1357        int ret = 0;
1358        unsigned int i = 0;
1359        struct arpt_entry *iter;
1360
1361        counters = alloc_counters(table);
1362        if (IS_ERR(counters))
1363                return PTR_ERR(counters);
1364
1365        pos = userptr;
1366        size = total_size;
1367        xt_entry_foreach(iter, private->entries, total_size) {
1368                ret = compat_copy_entry_to_user(iter, &pos,
1369                                                &size, counters, i++);
1370                if (ret != 0)
1371                        break;
1372        }
1373        vfree(counters);
1374        return ret;
1375}
1376
1377struct compat_arpt_get_entries {
1378        char name[XT_TABLE_MAXNAMELEN];
1379        compat_uint_t size;
1380        struct compat_arpt_entry entrytable[0];
1381};
1382
1383static int compat_get_entries(struct net *net,
1384                              struct compat_arpt_get_entries __user *uptr,
1385                              int *len)
1386{
1387        int ret;
1388        struct compat_arpt_get_entries get;
1389        struct xt_table *t;
1390
1391        if (*len < sizeof(get))
1392                return -EINVAL;
1393        if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1394                return -EFAULT;
1395        if (*len != sizeof(struct compat_arpt_get_entries) + get.size)
1396                return -EINVAL;
1397
1398        get.name[sizeof(get.name) - 1] = '\0';
1399
1400        xt_compat_lock(NFPROTO_ARP);
1401        t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
1402        if (!IS_ERR(t)) {
1403                const struct xt_table_info *private = t->private;
1404                struct xt_table_info info;
1405
1406                ret = compat_table_info(private, &info);
1407                if (!ret && get.size == info.size) {
1408                        ret = compat_copy_entries_to_user(private->size,
1409                                                          t, uptr->entrytable);
1410                } else if (!ret)
1411                        ret = -EAGAIN;
1412
1413                xt_compat_flush_offsets(NFPROTO_ARP);
1414                module_put(t->me);
1415                xt_table_unlock(t);
1416        } else
1417                ret = PTR_ERR(t);
1418
1419        xt_compat_unlock(NFPROTO_ARP);
1420        return ret;
1421}
1422
1423static int do_arpt_get_ctl(struct sock *, int, void __user *, int *);
1424
1425static int compat_do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user,
1426                                  int *len)
1427{
1428        int ret;
1429
1430        if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1431                return -EPERM;
1432
1433        switch (cmd) {
1434        case ARPT_SO_GET_INFO:
1435                ret = get_info(sock_net(sk), user, len, 1);
1436                break;
1437        case ARPT_SO_GET_ENTRIES:
1438                ret = compat_get_entries(sock_net(sk), user, len);
1439                break;
1440        default:
1441                ret = do_arpt_get_ctl(sk, cmd, user, len);
1442        }
1443        return ret;
1444}
1445#endif
1446
1447static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1448{
1449        int ret;
1450
1451        if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1452                return -EPERM;
1453
1454        switch (cmd) {
1455        case ARPT_SO_SET_REPLACE:
1456                ret = do_replace(sock_net(sk), user, len);
1457                break;
1458
1459        case ARPT_SO_SET_ADD_COUNTERS:
1460                ret = do_add_counters(sock_net(sk), user, len, 0);
1461                break;
1462
1463        default:
1464                ret = -EINVAL;
1465        }
1466
1467        return ret;
1468}
1469
1470static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1471{
1472        int ret;
1473
1474        if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1475                return -EPERM;
1476
1477        switch (cmd) {
1478        case ARPT_SO_GET_INFO:
1479                ret = get_info(sock_net(sk), user, len, 0);
1480                break;
1481
1482        case ARPT_SO_GET_ENTRIES:
1483                ret = get_entries(sock_net(sk), user, len);
1484                break;
1485
1486        case ARPT_SO_GET_REVISION_TARGET: {
1487                struct xt_get_revision rev;
1488
1489                if (*len != sizeof(rev)) {
1490                        ret = -EINVAL;
1491                        break;
1492                }
1493                if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1494                        ret = -EFAULT;
1495                        break;
1496                }
1497                rev.name[sizeof(rev.name)-1] = 0;
1498
1499                try_then_request_module(xt_find_revision(NFPROTO_ARP, rev.name,
1500                                                         rev.revision, 1, &ret),
1501                                        "arpt_%s", rev.name);
1502                break;
1503        }
1504
1505        default:
1506                ret = -EINVAL;
1507        }
1508
1509        return ret;
1510}
1511
1512static void __arpt_unregister_table(struct xt_table *table)
1513{
1514        struct xt_table_info *private;
1515        void *loc_cpu_entry;
1516        struct module *table_owner = table->me;
1517        struct arpt_entry *iter;
1518
1519        private = xt_unregister_table(table);
1520
1521        /* Decrease module usage counts and free resources */
1522        loc_cpu_entry = private->entries;
1523        xt_entry_foreach(iter, loc_cpu_entry, private->size)
1524                cleanup_entry(iter);
1525        if (private->number > private->initial_entries)
1526                module_put(table_owner);
1527        xt_free_table_info(private);
1528}
1529
1530int arpt_register_table(struct net *net,
1531                        const struct xt_table *table,
1532                        const struct arpt_replace *repl,
1533                        const struct nf_hook_ops *ops,
1534                        struct xt_table **res)
1535{
1536        int ret;
1537        struct xt_table_info *newinfo;
1538        struct xt_table_info bootstrap = {0};
1539        void *loc_cpu_entry;
1540        struct xt_table *new_table;
1541
1542        newinfo = xt_alloc_table_info(repl->size);
1543        if (!newinfo)
1544                return -ENOMEM;
1545
1546        loc_cpu_entry = newinfo->entries;
1547        memcpy(loc_cpu_entry, repl->entries, repl->size);
1548
1549        ret = translate_table(newinfo, loc_cpu_entry, repl);
1550        if (ret != 0)
1551                goto out_free;
1552
1553        new_table = xt_register_table(net, table, &bootstrap, newinfo);
1554        if (IS_ERR(new_table)) {
1555                ret = PTR_ERR(new_table);
1556                goto out_free;
1557        }
1558
1559        /* set res now, will see skbs right after nf_register_net_hooks */
1560        WRITE_ONCE(*res, new_table);
1561
1562        ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
1563        if (ret != 0) {
1564                __arpt_unregister_table(new_table);
1565                *res = NULL;
1566        }
1567
1568        return ret;
1569
1570out_free:
1571        xt_free_table_info(newinfo);
1572        return ret;
1573}
1574
1575void arpt_unregister_table(struct net *net, struct xt_table *table,
1576                           const struct nf_hook_ops *ops)
1577{
1578        nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
1579        __arpt_unregister_table(table);
1580}
1581
1582/* The built-in targets: standard (NULL) and error. */
1583static struct xt_target arpt_builtin_tg[] __read_mostly = {
1584        {
1585                .name             = XT_STANDARD_TARGET,
1586                .targetsize       = sizeof(int),
1587                .family           = NFPROTO_ARP,
1588#ifdef CONFIG_COMPAT
1589                .compatsize       = sizeof(compat_int_t),
1590                .compat_from_user = compat_standard_from_user,
1591                .compat_to_user   = compat_standard_to_user,
1592#endif
1593        },
1594        {
1595                .name             = XT_ERROR_TARGET,
1596                .target           = arpt_error,
1597                .targetsize       = XT_FUNCTION_MAXNAMELEN,
1598                .family           = NFPROTO_ARP,
1599        },
1600};
1601
1602static struct nf_sockopt_ops arpt_sockopts = {
1603        .pf             = PF_INET,
1604        .set_optmin     = ARPT_BASE_CTL,
1605        .set_optmax     = ARPT_SO_SET_MAX+1,
1606        .set            = do_arpt_set_ctl,
1607#ifdef CONFIG_COMPAT
1608        .compat_set     = compat_do_arpt_set_ctl,
1609#endif
1610        .get_optmin     = ARPT_BASE_CTL,
1611        .get_optmax     = ARPT_SO_GET_MAX+1,
1612        .get            = do_arpt_get_ctl,
1613#ifdef CONFIG_COMPAT
1614        .compat_get     = compat_do_arpt_get_ctl,
1615#endif
1616        .owner          = THIS_MODULE,
1617};
1618
1619static int __net_init arp_tables_net_init(struct net *net)
1620{
1621        return xt_proto_init(net, NFPROTO_ARP);
1622}
1623
1624static void __net_exit arp_tables_net_exit(struct net *net)
1625{
1626        xt_proto_fini(net, NFPROTO_ARP);
1627}
1628
1629static struct pernet_operations arp_tables_net_ops = {
1630        .init = arp_tables_net_init,
1631        .exit = arp_tables_net_exit,
1632};
1633
1634static int __init arp_tables_init(void)
1635{
1636        int ret;
1637
1638        ret = register_pernet_subsys(&arp_tables_net_ops);
1639        if (ret < 0)
1640                goto err1;
1641
1642        /* No one else will be downing sem now, so we won't sleep */
1643        ret = xt_register_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg));
1644        if (ret < 0)
1645                goto err2;
1646
1647        /* Register setsockopt */
1648        ret = nf_register_sockopt(&arpt_sockopts);
1649        if (ret < 0)
1650                goto err4;
1651
1652        return 0;
1653
1654err4:
1655        xt_unregister_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg));
1656err2:
1657        unregister_pernet_subsys(&arp_tables_net_ops);
1658err1:
1659        return ret;
1660}
1661
1662static void __exit arp_tables_fini(void)
1663{
1664        nf_unregister_sockopt(&arpt_sockopts);
1665        xt_unregister_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg));
1666        unregister_pernet_subsys(&arp_tables_net_ops);
1667}
1668
1669EXPORT_SYMBOL(arpt_register_table);
1670EXPORT_SYMBOL(arpt_unregister_table);
1671EXPORT_SYMBOL(arpt_do_table);
1672
1673module_init(arp_tables_init);
1674module_exit(arp_tables_fini);
1675