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