linux/net/ipv6/netfilter/ip6_tables.c
<<
>>
Prefs
   1/*
   2 * Packet matching code.
   3 *
   4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
   5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  12#include <linux/capability.h>
  13#include <linux/in.h>
  14#include <linux/skbuff.h>
  15#include <linux/kmod.h>
  16#include <linux/vmalloc.h>
  17#include <linux/netdevice.h>
  18#include <linux/module.h>
  19#include <linux/poison.h>
  20#include <linux/icmpv6.h>
  21#include <net/ipv6.h>
  22#include <net/compat.h>
  23#include <asm/uaccess.h>
  24#include <linux/mutex.h>
  25#include <linux/proc_fs.h>
  26#include <linux/err.h>
  27#include <linux/cpumask.h>
  28
  29#include <linux/netfilter_ipv6/ip6_tables.h>
  30#include <linux/netfilter/x_tables.h>
  31#include <net/netfilter/nf_log.h>
  32
  33MODULE_LICENSE("GPL");
  34MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
  35MODULE_DESCRIPTION("IPv6 packet filter");
  36
  37/*#define DEBUG_IP_FIREWALL*/
  38/*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
  39/*#define DEBUG_IP_FIREWALL_USER*/
  40
  41#ifdef DEBUG_IP_FIREWALL
  42#define dprintf(format, args...)  printk(format , ## args)
  43#else
  44#define dprintf(format, args...)
  45#endif
  46
  47#ifdef DEBUG_IP_FIREWALL_USER
  48#define duprintf(format, args...) printk(format , ## args)
  49#else
  50#define duprintf(format, args...)
  51#endif
  52
  53#ifdef CONFIG_NETFILTER_DEBUG
  54#define IP_NF_ASSERT(x)                                         \
  55do {                                                            \
  56        if (!(x))                                               \
  57                printk("IP_NF_ASSERT: %s:%s:%u\n",              \
  58                       __func__, __FILE__, __LINE__);   \
  59} while(0)
  60#else
  61#define IP_NF_ASSERT(x)
  62#endif
  63
  64#if 0
  65/* All the better to debug you with... */
  66#define static
  67#define inline
  68#endif
  69
  70/*
  71   We keep a set of rules for each CPU, so we can avoid write-locking
  72   them in the softirq when updating the counters and therefore
  73   only need to read-lock in the softirq; doing a write_lock_bh() in user
  74   context stops packets coming through and allows user context to read
  75   the counters or update the rules.
  76
  77   Hence the start of any table is given by get_table() below.  */
  78
  79/* Check for an extension */
  80int
  81ip6t_ext_hdr(u8 nexthdr)
  82{
  83        return ( (nexthdr == IPPROTO_HOPOPTS)   ||
  84                 (nexthdr == IPPROTO_ROUTING)   ||
  85                 (nexthdr == IPPROTO_FRAGMENT)  ||
  86                 (nexthdr == IPPROTO_ESP)       ||
  87                 (nexthdr == IPPROTO_AH)        ||
  88                 (nexthdr == IPPROTO_NONE)      ||
  89                 (nexthdr == IPPROTO_DSTOPTS) );
  90}
  91
  92/* Returns whether matches rule or not. */
  93/* Performance critical - called for every packet */
  94static inline bool
  95ip6_packet_match(const struct sk_buff *skb,
  96                 const char *indev,
  97                 const char *outdev,
  98                 const struct ip6t_ip6 *ip6info,
  99                 unsigned int *protoff,
 100                 int *fragoff, bool *hotdrop)
 101{
 102        unsigned long ret;
 103        const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
 104
 105#define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg)))
 106
 107        if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
 108                                       &ip6info->src), IP6T_INV_SRCIP)
 109            || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
 110                                          &ip6info->dst), IP6T_INV_DSTIP)) {
 111                dprintf("Source or dest mismatch.\n");
 112/*
 113                dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
 114                        ipinfo->smsk.s_addr, ipinfo->src.s_addr,
 115                        ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
 116                dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
 117                        ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
 118                        ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
 119                return false;
 120        }
 121
 122        ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask);
 123
 124        if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
 125                dprintf("VIA in mismatch (%s vs %s).%s\n",
 126                        indev, ip6info->iniface,
 127                        ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
 128                return false;
 129        }
 130
 131        ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask);
 132
 133        if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
 134                dprintf("VIA out mismatch (%s vs %s).%s\n",
 135                        outdev, ip6info->outiface,
 136                        ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
 137                return false;
 138        }
 139
 140/* ... might want to do something with class and flowlabel here ... */
 141
 142        /* look for the desired protocol header */
 143        if((ip6info->flags & IP6T_F_PROTO)) {
 144                int protohdr;
 145                unsigned short _frag_off;
 146
 147                protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
 148                if (protohdr < 0) {
 149                        if (_frag_off == 0)
 150                                *hotdrop = true;
 151                        return false;
 152                }
 153                *fragoff = _frag_off;
 154
 155                dprintf("Packet protocol %hi ?= %s%hi.\n",
 156                                protohdr,
 157                                ip6info->invflags & IP6T_INV_PROTO ? "!":"",
 158                                ip6info->proto);
 159
 160                if (ip6info->proto == protohdr) {
 161                        if(ip6info->invflags & IP6T_INV_PROTO) {
 162                                return false;
 163                        }
 164                        return true;
 165                }
 166
 167                /* We need match for the '-p all', too! */
 168                if ((ip6info->proto != 0) &&
 169                        !(ip6info->invflags & IP6T_INV_PROTO))
 170                        return false;
 171        }
 172        return true;
 173}
 174
 175/* should be ip6 safe */
 176static bool
 177ip6_checkentry(const struct ip6t_ip6 *ipv6)
 178{
 179        if (ipv6->flags & ~IP6T_F_MASK) {
 180                duprintf("Unknown flag bits set: %08X\n",
 181                         ipv6->flags & ~IP6T_F_MASK);
 182                return false;
 183        }
 184        if (ipv6->invflags & ~IP6T_INV_MASK) {
 185                duprintf("Unknown invflag bits set: %08X\n",
 186                         ipv6->invflags & ~IP6T_INV_MASK);
 187                return false;
 188        }
 189        return true;
 190}
 191
 192static unsigned int
 193ip6t_error(struct sk_buff *skb, const struct xt_target_param *par)
 194{
 195        if (net_ratelimit())
 196                printk("ip6_tables: error: `%s'\n",
 197                       (const char *)par->targinfo);
 198
 199        return NF_DROP;
 200}
 201
 202/* Performance critical - called for every packet */
 203static inline bool
 204do_match(struct ip6t_entry_match *m, const struct sk_buff *skb,
 205         struct xt_match_param *par)
 206{
 207        par->match     = m->u.kernel.match;
 208        par->matchinfo = m->data;
 209
 210        /* Stop iteration if it doesn't match */
 211        if (!m->u.kernel.match->match(skb, par))
 212                return true;
 213        else
 214                return false;
 215}
 216
 217static inline struct ip6t_entry *
 218get_entry(void *base, unsigned int offset)
 219{
 220        return (struct ip6t_entry *)(base + offset);
 221}
 222
 223/* All zeroes == unconditional rule. */
 224/* Mildly perf critical (only if packet tracing is on) */
 225static inline bool unconditional(const struct ip6t_ip6 *ipv6)
 226{
 227        static const struct ip6t_ip6 uncond;
 228
 229        return memcmp(ipv6, &uncond, sizeof(uncond)) == 0;
 230}
 231
 232#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
 233    defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
 234/* This cries for unification! */
 235static const char *const hooknames[] = {
 236        [NF_INET_PRE_ROUTING]           = "PREROUTING",
 237        [NF_INET_LOCAL_IN]              = "INPUT",
 238        [NF_INET_FORWARD]               = "FORWARD",
 239        [NF_INET_LOCAL_OUT]             = "OUTPUT",
 240        [NF_INET_POST_ROUTING]          = "POSTROUTING",
 241};
 242
 243enum nf_ip_trace_comments {
 244        NF_IP6_TRACE_COMMENT_RULE,
 245        NF_IP6_TRACE_COMMENT_RETURN,
 246        NF_IP6_TRACE_COMMENT_POLICY,
 247};
 248
 249static const char *const comments[] = {
 250        [NF_IP6_TRACE_COMMENT_RULE]     = "rule",
 251        [NF_IP6_TRACE_COMMENT_RETURN]   = "return",
 252        [NF_IP6_TRACE_COMMENT_POLICY]   = "policy",
 253};
 254
 255static struct nf_loginfo trace_loginfo = {
 256        .type = NF_LOG_TYPE_LOG,
 257        .u = {
 258                .log = {
 259                        .level = 4,
 260                        .logflags = NF_LOG_MASK,
 261                },
 262        },
 263};
 264
 265/* Mildly perf critical (only if packet tracing is on) */
 266static inline int
 267get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e,
 268                      const char *hookname, const char **chainname,
 269                      const char **comment, unsigned int *rulenum)
 270{
 271        struct ip6t_standard_target *t = (void *)ip6t_get_target(s);
 272
 273        if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) {
 274                /* Head of user chain: ERROR target with chainname */
 275                *chainname = t->target.data;
 276                (*rulenum) = 0;
 277        } else if (s == e) {
 278                (*rulenum)++;
 279
 280                if (s->target_offset == sizeof(struct ip6t_entry)
 281                   && strcmp(t->target.u.kernel.target->name,
 282                             IP6T_STANDARD_TARGET) == 0
 283                   && t->verdict < 0
 284                   && unconditional(&s->ipv6)) {
 285                        /* Tail of chains: STANDARD target (return/policy) */
 286                        *comment = *chainname == hookname
 287                                ? comments[NF_IP6_TRACE_COMMENT_POLICY]
 288                                : comments[NF_IP6_TRACE_COMMENT_RETURN];
 289                }
 290                return 1;
 291        } else
 292                (*rulenum)++;
 293
 294        return 0;
 295}
 296
 297static void trace_packet(struct sk_buff *skb,
 298                         unsigned int hook,
 299                         const struct net_device *in,
 300                         const struct net_device *out,
 301                         const char *tablename,
 302                         struct xt_table_info *private,
 303                         struct ip6t_entry *e)
 304{
 305        void *table_base;
 306        const struct ip6t_entry *root;
 307        const char *hookname, *chainname, *comment;
 308        unsigned int rulenum = 0;
 309
 310        table_base = private->entries[smp_processor_id()];
 311        root = get_entry(table_base, private->hook_entry[hook]);
 312
 313        hookname = chainname = hooknames[hook];
 314        comment = comments[NF_IP6_TRACE_COMMENT_RULE];
 315
 316        IP6T_ENTRY_ITERATE(root,
 317                           private->size - private->hook_entry[hook],
 318                           get_chainname_rulenum,
 319                           e, hookname, &chainname, &comment, &rulenum);
 320
 321        nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo,
 322                      "TRACE: %s:%s:%s:%u ",
 323                      tablename, chainname, comment, rulenum);
 324}
 325#endif
 326
 327static inline __pure struct ip6t_entry *
 328ip6t_next_entry(const struct ip6t_entry *entry)
 329{
 330        return (void *)entry + entry->next_offset;
 331}
 332
 333/* Returns one of the generic firewall policies, like NF_ACCEPT. */
 334unsigned int
 335ip6t_do_table(struct sk_buff *skb,
 336              unsigned int hook,
 337              const struct net_device *in,
 338              const struct net_device *out,
 339              struct xt_table *table)
 340{
 341#define tb_comefrom ((struct ip6t_entry *)table_base)->comefrom
 342
 343        static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
 344        bool hotdrop = false;
 345        /* Initializing verdict to NF_DROP keeps gcc happy. */
 346        unsigned int verdict = NF_DROP;
 347        const char *indev, *outdev;
 348        void *table_base;
 349        struct ip6t_entry *e, *back;
 350        struct xt_table_info *private;
 351        struct xt_match_param mtpar;
 352        struct xt_target_param tgpar;
 353
 354        /* Initialization */
 355        indev = in ? in->name : nulldevname;
 356        outdev = out ? out->name : nulldevname;
 357        /* We handle fragments by dealing with the first fragment as
 358         * if it was a normal packet.  All other fragments are treated
 359         * normally, except that they will NEVER match rules that ask
 360         * things we don't know, ie. tcp syn flag or ports).  If the
 361         * rule is also a fragment-specific rule, non-fragments won't
 362         * match it. */
 363        mtpar.hotdrop = &hotdrop;
 364        mtpar.in      = tgpar.in  = in;
 365        mtpar.out     = tgpar.out = out;
 366        mtpar.family  = tgpar.family = NFPROTO_IPV6;
 367        mtpar.hooknum = tgpar.hooknum = hook;
 368
 369        IP_NF_ASSERT(table->valid_hooks & (1 << hook));
 370
 371        xt_info_rdlock_bh();
 372        private = table->private;
 373        table_base = private->entries[smp_processor_id()];
 374
 375        e = get_entry(table_base, private->hook_entry[hook]);
 376
 377        /* For return from builtin chain */
 378        back = get_entry(table_base, private->underflow[hook]);
 379
 380        do {
 381                struct ip6t_entry_target *t;
 382
 383                IP_NF_ASSERT(e);
 384                IP_NF_ASSERT(back);
 385                if (!ip6_packet_match(skb, indev, outdev, &e->ipv6,
 386                    &mtpar.thoff, &mtpar.fragoff, &hotdrop) ||
 387                    IP6T_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) {
 388                        e = ip6t_next_entry(e);
 389                        continue;
 390                }
 391
 392                ADD_COUNTER(e->counters,
 393                            ntohs(ipv6_hdr(skb)->payload_len) +
 394                            sizeof(struct ipv6hdr), 1);
 395
 396                t = ip6t_get_target(e);
 397                IP_NF_ASSERT(t->u.kernel.target);
 398
 399#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
 400    defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
 401                /* The packet is traced: log it */
 402                if (unlikely(skb->nf_trace))
 403                        trace_packet(skb, hook, in, out,
 404                                     table->name, private, e);
 405#endif
 406                /* Standard target? */
 407                if (!t->u.kernel.target->target) {
 408                        int v;
 409
 410                        v = ((struct ip6t_standard_target *)t)->verdict;
 411                        if (v < 0) {
 412                                /* Pop from stack? */
 413                                if (v != IP6T_RETURN) {
 414                                        verdict = (unsigned)(-v) - 1;
 415                                        break;
 416                                }
 417                                e = back;
 418                                back = get_entry(table_base, back->comefrom);
 419                                continue;
 420                        }
 421                        if (table_base + v != ip6t_next_entry(e)
 422                            && !(e->ipv6.flags & IP6T_F_GOTO)) {
 423                                /* Save old back ptr in next entry */
 424                                struct ip6t_entry *next = ip6t_next_entry(e);
 425                                next->comefrom = (void *)back - table_base;
 426                                /* set back pointer to next entry */
 427                                back = next;
 428                        }
 429
 430                        e = get_entry(table_base, v);
 431                        continue;
 432                }
 433
 434                /* Targets which reenter must return
 435                   abs. verdicts */
 436                tgpar.target   = t->u.kernel.target;
 437                tgpar.targinfo = t->data;
 438
 439#ifdef CONFIG_NETFILTER_DEBUG
 440                tb_comefrom = 0xeeeeeeec;
 441#endif
 442                verdict = t->u.kernel.target->target(skb, &tgpar);
 443
 444#ifdef CONFIG_NETFILTER_DEBUG
 445                if (tb_comefrom != 0xeeeeeeec && verdict == IP6T_CONTINUE) {
 446                        printk("Target %s reentered!\n",
 447                               t->u.kernel.target->name);
 448                        verdict = NF_DROP;
 449                }
 450                tb_comefrom = 0x57acc001;
 451#endif
 452                if (verdict == IP6T_CONTINUE)
 453                        e = ip6t_next_entry(e);
 454                else
 455                        /* Verdict */
 456                        break;
 457        } while (!hotdrop);
 458
 459#ifdef CONFIG_NETFILTER_DEBUG
 460        tb_comefrom = NETFILTER_LINK_POISON;
 461#endif
 462        xt_info_rdunlock_bh();
 463
 464#ifdef DEBUG_ALLOW_ALL
 465        return NF_ACCEPT;
 466#else
 467        if (hotdrop)
 468                return NF_DROP;
 469        else return verdict;
 470#endif
 471
 472#undef tb_comefrom
 473}
 474
 475/* Figures out from what hook each rule can be called: returns 0 if
 476   there are loops.  Puts hook bitmask in comefrom. */
 477static int
 478mark_source_chains(struct xt_table_info *newinfo,
 479                   unsigned int valid_hooks, void *entry0)
 480{
 481        unsigned int hook;
 482
 483        /* No recursion; use packet counter to save back ptrs (reset
 484           to 0 as we leave), and comefrom to save source hook bitmask */
 485        for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
 486                unsigned int pos = newinfo->hook_entry[hook];
 487                struct ip6t_entry *e = (struct ip6t_entry *)(entry0 + pos);
 488
 489                if (!(valid_hooks & (1 << hook)))
 490                        continue;
 491
 492                /* Set initial back pointer. */
 493                e->counters.pcnt = pos;
 494
 495                for (;;) {
 496                        struct ip6t_standard_target *t
 497                                = (void *)ip6t_get_target(e);
 498                        int visited = e->comefrom & (1 << hook);
 499
 500                        if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
 501                                printk("iptables: loop hook %u pos %u %08X.\n",
 502                                       hook, pos, e->comefrom);
 503                                return 0;
 504                        }
 505                        e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
 506
 507                        /* Unconditional return/END. */
 508                        if ((e->target_offset == sizeof(struct ip6t_entry)
 509                            && (strcmp(t->target.u.user.name,
 510                                       IP6T_STANDARD_TARGET) == 0)
 511                            && t->verdict < 0
 512                            && unconditional(&e->ipv6)) || visited) {
 513                                unsigned int oldpos, size;
 514
 515                                if ((strcmp(t->target.u.user.name,
 516                                            IP6T_STANDARD_TARGET) == 0) &&
 517                                    t->verdict < -NF_MAX_VERDICT - 1) {
 518                                        duprintf("mark_source_chains: bad "
 519                                                "negative verdict (%i)\n",
 520                                                                t->verdict);
 521                                        return 0;
 522                                }
 523
 524                                /* Return: backtrack through the last
 525                                   big jump. */
 526                                do {
 527                                        e->comefrom ^= (1<<NF_INET_NUMHOOKS);
 528#ifdef DEBUG_IP_FIREWALL_USER
 529                                        if (e->comefrom
 530                                            & (1 << NF_INET_NUMHOOKS)) {
 531                                                duprintf("Back unset "
 532                                                         "on hook %u "
 533                                                         "rule %u\n",
 534                                                         hook, pos);
 535                                        }
 536#endif
 537                                        oldpos = pos;
 538                                        pos = e->counters.pcnt;
 539                                        e->counters.pcnt = 0;
 540
 541                                        /* We're at the start. */
 542                                        if (pos == oldpos)
 543                                                goto next;
 544
 545                                        e = (struct ip6t_entry *)
 546                                                (entry0 + pos);
 547                                } while (oldpos == pos + e->next_offset);
 548
 549                                /* Move along one */
 550                                size = e->next_offset;
 551                                e = (struct ip6t_entry *)
 552                                        (entry0 + pos + size);
 553                                e->counters.pcnt = pos;
 554                                pos += size;
 555                        } else {
 556                                int newpos = t->verdict;
 557
 558                                if (strcmp(t->target.u.user.name,
 559                                           IP6T_STANDARD_TARGET) == 0
 560                                    && newpos >= 0) {
 561                                        if (newpos > newinfo->size -
 562                                                sizeof(struct ip6t_entry)) {
 563                                                duprintf("mark_source_chains: "
 564                                                        "bad verdict (%i)\n",
 565                                                                newpos);
 566                                                return 0;
 567                                        }
 568                                        /* This a jump; chase it. */
 569                                        duprintf("Jump rule %u -> %u\n",
 570                                                 pos, newpos);
 571                                } else {
 572                                        /* ... this is a fallthru */
 573                                        newpos = pos + e->next_offset;
 574                                }
 575                                e = (struct ip6t_entry *)
 576                                        (entry0 + newpos);
 577                                e->counters.pcnt = pos;
 578                                pos = newpos;
 579                        }
 580                }
 581                next:
 582                duprintf("Finished chain %u\n", hook);
 583        }
 584        return 1;
 585}
 586
 587static int
 588cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
 589{
 590        struct xt_mtdtor_param par;
 591
 592        if (i && (*i)-- == 0)
 593                return 1;
 594
 595        par.match     = m->u.kernel.match;
 596        par.matchinfo = m->data;
 597        par.family    = NFPROTO_IPV6;
 598        if (par.match->destroy != NULL)
 599                par.match->destroy(&par);
 600        module_put(par.match->me);
 601        return 0;
 602}
 603
 604static int
 605check_entry(struct ip6t_entry *e, const char *name)
 606{
 607        struct ip6t_entry_target *t;
 608
 609        if (!ip6_checkentry(&e->ipv6)) {
 610                duprintf("ip_tables: ip check failed %p %s.\n", e, name);
 611                return -EINVAL;
 612        }
 613
 614        if (e->target_offset + sizeof(struct ip6t_entry_target) >
 615            e->next_offset)
 616                return -EINVAL;
 617
 618        t = ip6t_get_target(e);
 619        if (e->target_offset + t->u.target_size > e->next_offset)
 620                return -EINVAL;
 621
 622        return 0;
 623}
 624
 625static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par,
 626                       unsigned int *i)
 627{
 628        const struct ip6t_ip6 *ipv6 = par->entryinfo;
 629        int ret;
 630
 631        par->match     = m->u.kernel.match;
 632        par->matchinfo = m->data;
 633
 634        ret = xt_check_match(par, m->u.match_size - sizeof(*m),
 635                             ipv6->proto, ipv6->invflags & IP6T_INV_PROTO);
 636        if (ret < 0) {
 637                duprintf("ip_tables: check failed for `%s'.\n",
 638                         par.match->name);
 639                return ret;
 640        }
 641        ++*i;
 642        return 0;
 643}
 644
 645static int
 646find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par,
 647                 unsigned int *i)
 648{
 649        struct xt_match *match;
 650        int ret;
 651
 652        match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
 653                                                      m->u.user.revision),
 654                                        "ip6t_%s", m->u.user.name);
 655        if (IS_ERR(match) || !match) {
 656                duprintf("find_check_match: `%s' not found\n", m->u.user.name);
 657                return match ? PTR_ERR(match) : -ENOENT;
 658        }
 659        m->u.kernel.match = match;
 660
 661        ret = check_match(m, par, i);
 662        if (ret)
 663                goto err;
 664
 665        return 0;
 666err:
 667        module_put(m->u.kernel.match->me);
 668        return ret;
 669}
 670
 671static int check_target(struct ip6t_entry *e, const char *name)
 672{
 673        struct ip6t_entry_target *t = ip6t_get_target(e);
 674        struct xt_tgchk_param par = {
 675                .table     = name,
 676                .entryinfo = e,
 677                .target    = t->u.kernel.target,
 678                .targinfo  = t->data,
 679                .hook_mask = e->comefrom,
 680                .family    = NFPROTO_IPV6,
 681        };
 682        int ret;
 683
 684        t = ip6t_get_target(e);
 685        ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
 686              e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
 687        if (ret < 0) {
 688                duprintf("ip_tables: check failed for `%s'.\n",
 689                         t->u.kernel.target->name);
 690                return ret;
 691        }
 692        return 0;
 693}
 694
 695static int
 696find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
 697                 unsigned int *i)
 698{
 699        struct ip6t_entry_target *t;
 700        struct xt_target *target;
 701        int ret;
 702        unsigned int j;
 703        struct xt_mtchk_param mtpar;
 704
 705        ret = check_entry(e, name);
 706        if (ret)
 707                return ret;
 708
 709        j = 0;
 710        mtpar.table     = name;
 711        mtpar.entryinfo = &e->ipv6;
 712        mtpar.hook_mask = e->comefrom;
 713        mtpar.family    = NFPROTO_IPV6;
 714        ret = IP6T_MATCH_ITERATE(e, find_check_match, &mtpar, &j);
 715        if (ret != 0)
 716                goto cleanup_matches;
 717
 718        t = ip6t_get_target(e);
 719        target = try_then_request_module(xt_find_target(AF_INET6,
 720                                                        t->u.user.name,
 721                                                        t->u.user.revision),
 722                                         "ip6t_%s", t->u.user.name);
 723        if (IS_ERR(target) || !target) {
 724                duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
 725                ret = target ? PTR_ERR(target) : -ENOENT;
 726                goto cleanup_matches;
 727        }
 728        t->u.kernel.target = target;
 729
 730        ret = check_target(e, name);
 731        if (ret)
 732                goto err;
 733
 734        (*i)++;
 735        return 0;
 736 err:
 737        module_put(t->u.kernel.target->me);
 738 cleanup_matches:
 739        IP6T_MATCH_ITERATE(e, cleanup_match, &j);
 740        return ret;
 741}
 742
 743static bool check_underflow(struct ip6t_entry *e)
 744{
 745        const struct ip6t_entry_target *t;
 746        unsigned int verdict;
 747
 748        if (!unconditional(&e->ipv6))
 749                return false;
 750        t = ip6t_get_target(e);
 751        if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
 752                return false;
 753        verdict = ((struct ip6t_standard_target *)t)->verdict;
 754        verdict = -verdict - 1;
 755        return verdict == NF_DROP || verdict == NF_ACCEPT;
 756}
 757
 758static int
 759check_entry_size_and_hooks(struct ip6t_entry *e,
 760                           struct xt_table_info *newinfo,
 761                           unsigned char *base,
 762                           unsigned char *limit,
 763                           const unsigned int *hook_entries,
 764                           const unsigned int *underflows,
 765                           unsigned int valid_hooks,
 766                           unsigned int *i)
 767{
 768        unsigned int h;
 769
 770        if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
 771            || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
 772                duprintf("Bad offset %p\n", e);
 773                return -EINVAL;
 774        }
 775
 776        if (e->next_offset
 777            < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
 778                duprintf("checking: element %p size %u\n",
 779                         e, e->next_offset);
 780                return -EINVAL;
 781        }
 782
 783        /* Check hooks & underflows */
 784        for (h = 0; h < NF_INET_NUMHOOKS; h++) {
 785                if (!(valid_hooks & (1 << h)))
 786                        continue;
 787                if ((unsigned char *)e - base == hook_entries[h])
 788                        newinfo->hook_entry[h] = hook_entries[h];
 789                if ((unsigned char *)e - base == underflows[h]) {
 790                        if (!check_underflow(e)) {
 791                                pr_err("Underflows must be unconditional and "
 792                                       "use the STANDARD target with "
 793                                       "ACCEPT/DROP\n");
 794                                return -EINVAL;
 795                        }
 796                        newinfo->underflow[h] = underflows[h];
 797                }
 798        }
 799
 800        /* Clear counters and comefrom */
 801        e->counters = ((struct xt_counters) { 0, 0 });
 802        e->comefrom = 0;
 803
 804        (*i)++;
 805        return 0;
 806}
 807
 808static int
 809cleanup_entry(struct ip6t_entry *e, unsigned int *i)
 810{
 811        struct xt_tgdtor_param par;
 812        struct ip6t_entry_target *t;
 813
 814        if (i && (*i)-- == 0)
 815                return 1;
 816
 817        /* Cleanup all matches */
 818        IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
 819        t = ip6t_get_target(e);
 820
 821        par.target   = t->u.kernel.target;
 822        par.targinfo = t->data;
 823        par.family   = NFPROTO_IPV6;
 824        if (par.target->destroy != NULL)
 825                par.target->destroy(&par);
 826        module_put(par.target->me);
 827        return 0;
 828}
 829
 830/* Checks and translates the user-supplied table segment (held in
 831   newinfo) */
 832static int
 833translate_table(const char *name,
 834                unsigned int valid_hooks,
 835                struct xt_table_info *newinfo,
 836                void *entry0,
 837                unsigned int size,
 838                unsigned int number,
 839                const unsigned int *hook_entries,
 840                const unsigned int *underflows)
 841{
 842        unsigned int i;
 843        int ret;
 844
 845        newinfo->size = size;
 846        newinfo->number = number;
 847
 848        /* Init all hooks to impossible value. */
 849        for (i = 0; i < NF_INET_NUMHOOKS; i++) {
 850                newinfo->hook_entry[i] = 0xFFFFFFFF;
 851                newinfo->underflow[i] = 0xFFFFFFFF;
 852        }
 853
 854        duprintf("translate_table: size %u\n", newinfo->size);
 855        i = 0;
 856        /* Walk through entries, checking offsets. */
 857        ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
 858                                check_entry_size_and_hooks,
 859                                newinfo,
 860                                entry0,
 861                                entry0 + size,
 862                                hook_entries, underflows, valid_hooks, &i);
 863        if (ret != 0)
 864                return ret;
 865
 866        if (i != number) {
 867                duprintf("translate_table: %u not %u entries\n",
 868                         i, number);
 869                return -EINVAL;
 870        }
 871
 872        /* Check hooks all assigned */
 873        for (i = 0; i < NF_INET_NUMHOOKS; i++) {
 874                /* Only hooks which are valid */
 875                if (!(valid_hooks & (1 << i)))
 876                        continue;
 877                if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
 878                        duprintf("Invalid hook entry %u %u\n",
 879                                 i, hook_entries[i]);
 880                        return -EINVAL;
 881                }
 882                if (newinfo->underflow[i] == 0xFFFFFFFF) {
 883                        duprintf("Invalid underflow %u %u\n",
 884                                 i, underflows[i]);
 885                        return -EINVAL;
 886                }
 887        }
 888
 889        if (!mark_source_chains(newinfo, valid_hooks, entry0))
 890                return -ELOOP;
 891
 892        /* Finally, each sanity check must pass */
 893        i = 0;
 894        ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
 895                                find_check_entry, name, size, &i);
 896
 897        if (ret != 0) {
 898                IP6T_ENTRY_ITERATE(entry0, newinfo->size,
 899                                   cleanup_entry, &i);
 900                return ret;
 901        }
 902
 903        /* And one copy for every other CPU */
 904        for_each_possible_cpu(i) {
 905                if (newinfo->entries[i] && newinfo->entries[i] != entry0)
 906                        memcpy(newinfo->entries[i], entry0, newinfo->size);
 907        }
 908
 909        return ret;
 910}
 911
 912/* Gets counters. */
 913static inline int
 914add_entry_to_counter(const struct ip6t_entry *e,
 915                     struct xt_counters total[],
 916                     unsigned int *i)
 917{
 918        ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
 919
 920        (*i)++;
 921        return 0;
 922}
 923
 924static inline int
 925set_entry_to_counter(const struct ip6t_entry *e,
 926                     struct ip6t_counters total[],
 927                     unsigned int *i)
 928{
 929        SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
 930
 931        (*i)++;
 932        return 0;
 933}
 934
 935static void
 936get_counters(const struct xt_table_info *t,
 937             struct xt_counters counters[])
 938{
 939        unsigned int cpu;
 940        unsigned int i;
 941        unsigned int curcpu;
 942
 943        /* Instead of clearing (by a previous call to memset())
 944         * the counters and using adds, we set the counters
 945         * with data used by 'current' CPU
 946         *
 947         * Bottom half has to be disabled to prevent deadlock
 948         * if new softirq were to run and call ipt_do_table
 949         */
 950        local_bh_disable();
 951        curcpu = smp_processor_id();
 952
 953        i = 0;
 954        IP6T_ENTRY_ITERATE(t->entries[curcpu],
 955                           t->size,
 956                           set_entry_to_counter,
 957                           counters,
 958                           &i);
 959
 960        for_each_possible_cpu(cpu) {
 961                if (cpu == curcpu)
 962                        continue;
 963                i = 0;
 964                xt_info_wrlock(cpu);
 965                IP6T_ENTRY_ITERATE(t->entries[cpu],
 966                                  t->size,
 967                                  add_entry_to_counter,
 968                                  counters,
 969                                  &i);
 970                xt_info_wrunlock(cpu);
 971        }
 972        local_bh_enable();
 973}
 974
 975static struct xt_counters *alloc_counters(struct xt_table *table)
 976{
 977        unsigned int countersize;
 978        struct xt_counters *counters;
 979        struct xt_table_info *private = table->private;
 980
 981        /* We need atomic snapshot of counters: rest doesn't change
 982           (other than comefrom, which userspace doesn't care
 983           about). */
 984        countersize = sizeof(struct xt_counters) * private->number;
 985        counters = vmalloc_node(countersize, numa_node_id());
 986
 987        if (counters == NULL)
 988                return ERR_PTR(-ENOMEM);
 989
 990        get_counters(private, counters);
 991
 992        return counters;
 993}
 994
 995static int
 996copy_entries_to_user(unsigned int total_size,
 997                     struct xt_table *table,
 998                     void __user *userptr)
 999{
1000        unsigned int off, num;
1001        struct ip6t_entry *e;
1002        struct xt_counters *counters;
1003        const struct xt_table_info *private = table->private;
1004        int ret = 0;
1005        const void *loc_cpu_entry;
1006
1007        counters = alloc_counters(table);
1008        if (IS_ERR(counters))
1009                return PTR_ERR(counters);
1010
1011        /* choose the copy that is on our node/cpu, ...
1012         * This choice is lazy (because current thread is
1013         * allowed to migrate to another cpu)
1014         */
1015        loc_cpu_entry = private->entries[raw_smp_processor_id()];
1016        if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
1017                ret = -EFAULT;
1018                goto free_counters;
1019        }
1020
1021        /* FIXME: use iterator macros --RR */
1022        /* ... then go back and fix counters and names */
1023        for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1024                unsigned int i;
1025                const struct ip6t_entry_match *m;
1026                const struct ip6t_entry_target *t;
1027
1028                e = (struct ip6t_entry *)(loc_cpu_entry + off);
1029                if (copy_to_user(userptr + off
1030                                 + offsetof(struct ip6t_entry, counters),
1031                                 &counters[num],
1032                                 sizeof(counters[num])) != 0) {
1033                        ret = -EFAULT;
1034                        goto free_counters;
1035                }
1036
1037                for (i = sizeof(struct ip6t_entry);
1038                     i < e->target_offset;
1039                     i += m->u.match_size) {
1040                        m = (void *)e + i;
1041
1042                        if (copy_to_user(userptr + off + i
1043                                         + offsetof(struct ip6t_entry_match,
1044                                                    u.user.name),
1045                                         m->u.kernel.match->name,
1046                                         strlen(m->u.kernel.match->name)+1)
1047                            != 0) {
1048                                ret = -EFAULT;
1049                                goto free_counters;
1050                        }
1051                }
1052
1053                t = ip6t_get_target(e);
1054                if (copy_to_user(userptr + off + e->target_offset
1055                                 + offsetof(struct ip6t_entry_target,
1056                                            u.user.name),
1057                                 t->u.kernel.target->name,
1058                                 strlen(t->u.kernel.target->name)+1) != 0) {
1059                        ret = -EFAULT;
1060                        goto free_counters;
1061                }
1062        }
1063
1064 free_counters:
1065        vfree(counters);
1066        return ret;
1067}
1068
1069#ifdef CONFIG_COMPAT
1070static void compat_standard_from_user(void *dst, void *src)
1071{
1072        int v = *(compat_int_t *)src;
1073
1074        if (v > 0)
1075                v += xt_compat_calc_jump(AF_INET6, v);
1076        memcpy(dst, &v, sizeof(v));
1077}
1078
1079static int compat_standard_to_user(void __user *dst, void *src)
1080{
1081        compat_int_t cv = *(int *)src;
1082
1083        if (cv > 0)
1084                cv -= xt_compat_calc_jump(AF_INET6, cv);
1085        return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
1086}
1087
1088static inline int
1089compat_calc_match(struct ip6t_entry_match *m, int *size)
1090{
1091        *size += xt_compat_match_offset(m->u.kernel.match);
1092        return 0;
1093}
1094
1095static int compat_calc_entry(struct ip6t_entry *e,
1096                             const struct xt_table_info *info,
1097                             void *base, struct xt_table_info *newinfo)
1098{
1099        struct ip6t_entry_target *t;
1100        unsigned int entry_offset;
1101        int off, i, ret;
1102
1103        off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1104        entry_offset = (void *)e - base;
1105        IP6T_MATCH_ITERATE(e, compat_calc_match, &off);
1106        t = ip6t_get_target(e);
1107        off += xt_compat_target_offset(t->u.kernel.target);
1108        newinfo->size -= off;
1109        ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1110        if (ret)
1111                return ret;
1112
1113        for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1114                if (info->hook_entry[i] &&
1115                    (e < (struct ip6t_entry *)(base + info->hook_entry[i])))
1116                        newinfo->hook_entry[i] -= off;
1117                if (info->underflow[i] &&
1118                    (e < (struct ip6t_entry *)(base + info->underflow[i])))
1119                        newinfo->underflow[i] -= off;
1120        }
1121        return 0;
1122}
1123
1124static int compat_table_info(const struct xt_table_info *info,
1125                             struct xt_table_info *newinfo)
1126{
1127        void *loc_cpu_entry;
1128
1129        if (!newinfo || !info)
1130                return -EINVAL;
1131
1132        /* we dont care about newinfo->entries[] */
1133        memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
1134        newinfo->initial_entries = 0;
1135        loc_cpu_entry = info->entries[raw_smp_processor_id()];
1136        return IP6T_ENTRY_ITERATE(loc_cpu_entry, info->size,
1137                                  compat_calc_entry, info, loc_cpu_entry,
1138                                  newinfo);
1139}
1140#endif
1141
1142static int get_info(struct net *net, void __user *user, int *len, int compat)
1143{
1144        char name[IP6T_TABLE_MAXNAMELEN];
1145        struct xt_table *t;
1146        int ret;
1147
1148        if (*len != sizeof(struct ip6t_getinfo)) {
1149                duprintf("length %u != %zu\n", *len,
1150                         sizeof(struct ip6t_getinfo));
1151                return -EINVAL;
1152        }
1153
1154        if (copy_from_user(name, user, sizeof(name)) != 0)
1155                return -EFAULT;
1156
1157        name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1158#ifdef CONFIG_COMPAT
1159        if (compat)
1160                xt_compat_lock(AF_INET6);
1161#endif
1162        t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1163                                    "ip6table_%s", name);
1164        if (t && !IS_ERR(t)) {
1165                struct ip6t_getinfo info;
1166                const struct xt_table_info *private = t->private;
1167
1168#ifdef CONFIG_COMPAT
1169                if (compat) {
1170                        struct xt_table_info tmp;
1171                        ret = compat_table_info(private, &tmp);
1172                        xt_compat_flush_offsets(AF_INET6);
1173                        private = &tmp;
1174                }
1175#endif
1176                info.valid_hooks = t->valid_hooks;
1177                memcpy(info.hook_entry, private->hook_entry,
1178                       sizeof(info.hook_entry));
1179                memcpy(info.underflow, private->underflow,
1180                       sizeof(info.underflow));
1181                info.num_entries = private->number;
1182                info.size = private->size;
1183                strcpy(info.name, name);
1184
1185                if (copy_to_user(user, &info, *len) != 0)
1186                        ret = -EFAULT;
1187                else
1188                        ret = 0;
1189
1190                xt_table_unlock(t);
1191                module_put(t->me);
1192        } else
1193                ret = t ? PTR_ERR(t) : -ENOENT;
1194#ifdef CONFIG_COMPAT
1195        if (compat)
1196                xt_compat_unlock(AF_INET6);
1197#endif
1198        return ret;
1199}
1200
1201static int
1202get_entries(struct net *net, struct ip6t_get_entries __user *uptr, int *len)
1203{
1204        int ret;
1205        struct ip6t_get_entries get;
1206        struct xt_table *t;
1207
1208        if (*len < sizeof(get)) {
1209                duprintf("get_entries: %u < %zu\n", *len, sizeof(get));
1210                return -EINVAL;
1211        }
1212        if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1213                return -EFAULT;
1214        if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1215                duprintf("get_entries: %u != %zu\n",
1216                         *len, sizeof(get) + get.size);
1217                return -EINVAL;
1218        }
1219
1220        t = xt_find_table_lock(net, AF_INET6, get.name);
1221        if (t && !IS_ERR(t)) {
1222                struct xt_table_info *private = t->private;
1223                duprintf("t->private->number = %u\n", private->number);
1224                if (get.size == private->size)
1225                        ret = copy_entries_to_user(private->size,
1226                                                   t, uptr->entrytable);
1227                else {
1228                        duprintf("get_entries: I've got %u not %u!\n",
1229                                 private->size, get.size);
1230                        ret = -EAGAIN;
1231                }
1232                module_put(t->me);
1233                xt_table_unlock(t);
1234        } else
1235                ret = t ? PTR_ERR(t) : -ENOENT;
1236
1237        return ret;
1238}
1239
1240static int
1241__do_replace(struct net *net, const char *name, unsigned int valid_hooks,
1242             struct xt_table_info *newinfo, unsigned int num_counters,
1243             void __user *counters_ptr)
1244{
1245        int ret;
1246        struct xt_table *t;
1247        struct xt_table_info *oldinfo;
1248        struct xt_counters *counters;
1249        const void *loc_cpu_old_entry;
1250
1251        ret = 0;
1252        counters = vmalloc_node(num_counters * sizeof(struct xt_counters),
1253                                numa_node_id());
1254        if (!counters) {
1255                ret = -ENOMEM;
1256                goto out;
1257        }
1258
1259        t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1260                                    "ip6table_%s", name);
1261        if (!t || IS_ERR(t)) {
1262                ret = t ? PTR_ERR(t) : -ENOENT;
1263                goto free_newinfo_counters_untrans;
1264        }
1265
1266        /* You lied! */
1267        if (valid_hooks != t->valid_hooks) {
1268                duprintf("Valid hook crap: %08X vs %08X\n",
1269                         valid_hooks, t->valid_hooks);
1270                ret = -EINVAL;
1271                goto put_module;
1272        }
1273
1274        oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1275        if (!oldinfo)
1276                goto put_module;
1277
1278        /* Update module usage count based on number of rules */
1279        duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1280                oldinfo->number, oldinfo->initial_entries, newinfo->number);
1281        if ((oldinfo->number > oldinfo->initial_entries) ||
1282            (newinfo->number <= oldinfo->initial_entries))
1283                module_put(t->me);
1284        if ((oldinfo->number > oldinfo->initial_entries) &&
1285            (newinfo->number <= oldinfo->initial_entries))
1286                module_put(t->me);
1287
1288        /* Get the old counters, and synchronize with replace */
1289        get_counters(oldinfo, counters);
1290
1291        /* Decrease module usage counts and free resource */
1292        loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1293        IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
1294                           NULL);
1295        xt_free_table_info(oldinfo);
1296        if (copy_to_user(counters_ptr, counters,
1297                         sizeof(struct xt_counters) * num_counters) != 0)
1298                ret = -EFAULT;
1299        vfree(counters);
1300        xt_table_unlock(t);
1301        return ret;
1302
1303 put_module:
1304        module_put(t->me);
1305        xt_table_unlock(t);
1306 free_newinfo_counters_untrans:
1307        vfree(counters);
1308 out:
1309        return ret;
1310}
1311
1312static int
1313do_replace(struct net *net, void __user *user, unsigned int len)
1314{
1315        int ret;
1316        struct ip6t_replace tmp;
1317        struct xt_table_info *newinfo;
1318        void *loc_cpu_entry;
1319
1320        if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1321                return -EFAULT;
1322
1323        /* overflow check */
1324        if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1325                return -ENOMEM;
1326
1327        newinfo = xt_alloc_table_info(tmp.size);
1328        if (!newinfo)
1329                return -ENOMEM;
1330
1331        /* choose the copy that is on our node/cpu */
1332        loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1333        if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1334                           tmp.size) != 0) {
1335                ret = -EFAULT;
1336                goto free_newinfo;
1337        }
1338
1339        ret = translate_table(tmp.name, tmp.valid_hooks,
1340                              newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1341                              tmp.hook_entry, tmp.underflow);
1342        if (ret != 0)
1343                goto free_newinfo;
1344
1345        duprintf("ip_tables: Translated table\n");
1346
1347        ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1348                           tmp.num_counters, tmp.counters);
1349        if (ret)
1350                goto free_newinfo_untrans;
1351        return 0;
1352
1353 free_newinfo_untrans:
1354        IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
1355 free_newinfo:
1356        xt_free_table_info(newinfo);
1357        return ret;
1358}
1359
1360/* We're lazy, and add to the first CPU; overflow works its fey magic
1361 * and everything is OK. */
1362static int
1363add_counter_to_entry(struct ip6t_entry *e,
1364                     const struct xt_counters addme[],
1365                     unsigned int *i)
1366{
1367        ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1368
1369        (*i)++;
1370        return 0;
1371}
1372
1373static int
1374do_add_counters(struct net *net, void __user *user, unsigned int len,
1375                int compat)
1376{
1377        unsigned int i, curcpu;
1378        struct xt_counters_info tmp;
1379        struct xt_counters *paddc;
1380        unsigned int num_counters;
1381        char *name;
1382        int size;
1383        void *ptmp;
1384        struct xt_table *t;
1385        const struct xt_table_info *private;
1386        int ret = 0;
1387        const void *loc_cpu_entry;
1388#ifdef CONFIG_COMPAT
1389        struct compat_xt_counters_info compat_tmp;
1390
1391        if (compat) {
1392                ptmp = &compat_tmp;
1393                size = sizeof(struct compat_xt_counters_info);
1394        } else
1395#endif
1396        {
1397                ptmp = &tmp;
1398                size = sizeof(struct xt_counters_info);
1399        }
1400
1401        if (copy_from_user(ptmp, user, size) != 0)
1402                return -EFAULT;
1403
1404#ifdef CONFIG_COMPAT
1405        if (compat) {
1406                num_counters = compat_tmp.num_counters;
1407                name = compat_tmp.name;
1408        } else
1409#endif
1410        {
1411                num_counters = tmp.num_counters;
1412                name = tmp.name;
1413        }
1414
1415        if (len != size + num_counters * sizeof(struct xt_counters))
1416                return -EINVAL;
1417
1418        paddc = vmalloc_node(len - size, numa_node_id());
1419        if (!paddc)
1420                return -ENOMEM;
1421
1422        if (copy_from_user(paddc, user + size, len - size) != 0) {
1423                ret = -EFAULT;
1424                goto free;
1425        }
1426
1427        t = xt_find_table_lock(net, AF_INET6, name);
1428        if (!t || IS_ERR(t)) {
1429                ret = t ? PTR_ERR(t) : -ENOENT;
1430                goto free;
1431        }
1432
1433
1434        local_bh_disable();
1435        private = t->private;
1436        if (private->number != num_counters) {
1437                ret = -EINVAL;
1438                goto unlock_up_free;
1439        }
1440
1441        i = 0;
1442        /* Choose the copy that is on our node */
1443        curcpu = smp_processor_id();
1444        xt_info_wrlock(curcpu);
1445        loc_cpu_entry = private->entries[curcpu];
1446        IP6T_ENTRY_ITERATE(loc_cpu_entry,
1447                          private->size,
1448                          add_counter_to_entry,
1449                          paddc,
1450                          &i);
1451        xt_info_wrunlock(curcpu);
1452
1453 unlock_up_free:
1454        local_bh_enable();
1455        xt_table_unlock(t);
1456        module_put(t->me);
1457 free:
1458        vfree(paddc);
1459
1460        return ret;
1461}
1462
1463#ifdef CONFIG_COMPAT
1464struct compat_ip6t_replace {
1465        char                    name[IP6T_TABLE_MAXNAMELEN];
1466        u32                     valid_hooks;
1467        u32                     num_entries;
1468        u32                     size;
1469        u32                     hook_entry[NF_INET_NUMHOOKS];
1470        u32                     underflow[NF_INET_NUMHOOKS];
1471        u32                     num_counters;
1472        compat_uptr_t           counters;       /* struct ip6t_counters * */
1473        struct compat_ip6t_entry entries[0];
1474};
1475
1476static int
1477compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
1478                          unsigned int *size, struct xt_counters *counters,
1479                          unsigned int *i)
1480{
1481        struct ip6t_entry_target *t;
1482        struct compat_ip6t_entry __user *ce;
1483        u_int16_t target_offset, next_offset;
1484        compat_uint_t origsize;
1485        int ret;
1486
1487        ret = -EFAULT;
1488        origsize = *size;
1489        ce = (struct compat_ip6t_entry __user *)*dstptr;
1490        if (copy_to_user(ce, e, sizeof(struct ip6t_entry)))
1491                goto out;
1492
1493        if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i])))
1494                goto out;
1495
1496        *dstptr += sizeof(struct compat_ip6t_entry);
1497        *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1498
1499        ret = IP6T_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size);
1500        target_offset = e->target_offset - (origsize - *size);
1501        if (ret)
1502                goto out;
1503        t = ip6t_get_target(e);
1504        ret = xt_compat_target_to_user(t, dstptr, size);
1505        if (ret)
1506                goto out;
1507        ret = -EFAULT;
1508        next_offset = e->next_offset - (origsize - *size);
1509        if (put_user(target_offset, &ce->target_offset))
1510                goto out;
1511        if (put_user(next_offset, &ce->next_offset))
1512                goto out;
1513
1514        (*i)++;
1515        return 0;
1516out:
1517        return ret;
1518}
1519
1520static int
1521compat_find_calc_match(struct ip6t_entry_match *m,
1522                       const char *name,
1523                       const struct ip6t_ip6 *ipv6,
1524                       unsigned int hookmask,
1525                       int *size, unsigned int *i)
1526{
1527        struct xt_match *match;
1528
1529        match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
1530                                                      m->u.user.revision),
1531                                        "ip6t_%s", m->u.user.name);
1532        if (IS_ERR(match) || !match) {
1533                duprintf("compat_check_calc_match: `%s' not found\n",
1534                         m->u.user.name);
1535                return match ? PTR_ERR(match) : -ENOENT;
1536        }
1537        m->u.kernel.match = match;
1538        *size += xt_compat_match_offset(match);
1539
1540        (*i)++;
1541        return 0;
1542}
1543
1544static int
1545compat_release_match(struct ip6t_entry_match *m, unsigned int *i)
1546{
1547        if (i && (*i)-- == 0)
1548                return 1;
1549
1550        module_put(m->u.kernel.match->me);
1551        return 0;
1552}
1553
1554static int
1555compat_release_entry(struct compat_ip6t_entry *e, unsigned int *i)
1556{
1557        struct ip6t_entry_target *t;
1558
1559        if (i && (*i)-- == 0)
1560                return 1;
1561
1562        /* Cleanup all matches */
1563        COMPAT_IP6T_MATCH_ITERATE(e, compat_release_match, NULL);
1564        t = compat_ip6t_get_target(e);
1565        module_put(t->u.kernel.target->me);
1566        return 0;
1567}
1568
1569static int
1570check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
1571                                  struct xt_table_info *newinfo,
1572                                  unsigned int *size,
1573                                  unsigned char *base,
1574                                  unsigned char *limit,
1575                                  unsigned int *hook_entries,
1576                                  unsigned int *underflows,
1577                                  unsigned int *i,
1578                                  const char *name)
1579{
1580        struct ip6t_entry_target *t;
1581        struct xt_target *target;
1582        unsigned int entry_offset;
1583        unsigned int j;
1584        int ret, off, h;
1585
1586        duprintf("check_compat_entry_size_and_hooks %p\n", e);
1587        if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0
1588            || (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) {
1589                duprintf("Bad offset %p, limit = %p\n", e, limit);
1590                return -EINVAL;
1591        }
1592
1593        if (e->next_offset < sizeof(struct compat_ip6t_entry) +
1594                             sizeof(struct compat_xt_entry_target)) {
1595                duprintf("checking: element %p size %u\n",
1596                         e, e->next_offset);
1597                return -EINVAL;
1598        }
1599
1600        /* For purposes of check_entry casting the compat entry is fine */
1601        ret = check_entry((struct ip6t_entry *)e, name);
1602        if (ret)
1603                return ret;
1604
1605        off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1606        entry_offset = (void *)e - (void *)base;
1607        j = 0;
1608        ret = COMPAT_IP6T_MATCH_ITERATE(e, compat_find_calc_match, name,
1609                                        &e->ipv6, e->comefrom, &off, &j);
1610        if (ret != 0)
1611                goto release_matches;
1612
1613        t = compat_ip6t_get_target(e);
1614        target = try_then_request_module(xt_find_target(AF_INET6,
1615                                                        t->u.user.name,
1616                                                        t->u.user.revision),
1617                                         "ip6t_%s", t->u.user.name);
1618        if (IS_ERR(target) || !target) {
1619                duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1620                         t->u.user.name);
1621                ret = target ? PTR_ERR(target) : -ENOENT;
1622                goto release_matches;
1623        }
1624        t->u.kernel.target = target;
1625
1626        off += xt_compat_target_offset(target);
1627        *size += off;
1628        ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1629        if (ret)
1630                goto out;
1631
1632        /* Check hooks & underflows */
1633        for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1634                if ((unsigned char *)e - base == hook_entries[h])
1635                        newinfo->hook_entry[h] = hook_entries[h];
1636                if ((unsigned char *)e - base == underflows[h])
1637                        newinfo->underflow[h] = underflows[h];
1638        }
1639
1640        /* Clear counters and comefrom */
1641        memset(&e->counters, 0, sizeof(e->counters));
1642        e->comefrom = 0;
1643
1644        (*i)++;
1645        return 0;
1646
1647out:
1648        module_put(t->u.kernel.target->me);
1649release_matches:
1650        IP6T_MATCH_ITERATE(e, compat_release_match, &j);
1651        return ret;
1652}
1653
1654static int
1655compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
1656                            unsigned int *size, const char *name,
1657                            struct xt_table_info *newinfo, unsigned char *base)
1658{
1659        struct ip6t_entry_target *t;
1660        struct xt_target *target;
1661        struct ip6t_entry *de;
1662        unsigned int origsize;
1663        int ret, h;
1664
1665        ret = 0;
1666        origsize = *size;
1667        de = (struct ip6t_entry *)*dstptr;
1668        memcpy(de, e, sizeof(struct ip6t_entry));
1669        memcpy(&de->counters, &e->counters, sizeof(e->counters));
1670
1671        *dstptr += sizeof(struct ip6t_entry);
1672        *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1673
1674        ret = COMPAT_IP6T_MATCH_ITERATE(e, xt_compat_match_from_user,
1675                                        dstptr, size);
1676        if (ret)
1677                return ret;
1678        de->target_offset = e->target_offset - (origsize - *size);
1679        t = compat_ip6t_get_target(e);
1680        target = t->u.kernel.target;
1681        xt_compat_target_from_user(t, dstptr, size);
1682
1683        de->next_offset = e->next_offset - (origsize - *size);
1684        for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1685                if ((unsigned char *)de - base < newinfo->hook_entry[h])
1686                        newinfo->hook_entry[h] -= origsize - *size;
1687                if ((unsigned char *)de - base < newinfo->underflow[h])
1688                        newinfo->underflow[h] -= origsize - *size;
1689        }
1690        return ret;
1691}
1692
1693static int compat_check_entry(struct ip6t_entry *e, const char *name,
1694                                     unsigned int *i)
1695{
1696        unsigned int j;
1697        int ret;
1698        struct xt_mtchk_param mtpar;
1699
1700        j = 0;
1701        mtpar.table     = name;
1702        mtpar.entryinfo = &e->ipv6;
1703        mtpar.hook_mask = e->comefrom;
1704        mtpar.family    = NFPROTO_IPV6;
1705        ret = IP6T_MATCH_ITERATE(e, check_match, &mtpar, &j);
1706        if (ret)
1707                goto cleanup_matches;
1708
1709        ret = check_target(e, name);
1710        if (ret)
1711                goto cleanup_matches;
1712
1713        (*i)++;
1714        return 0;
1715
1716 cleanup_matches:
1717        IP6T_MATCH_ITERATE(e, cleanup_match, &j);
1718        return ret;
1719}
1720
1721static int
1722translate_compat_table(const char *name,
1723                       unsigned int valid_hooks,
1724                       struct xt_table_info **pinfo,
1725                       void **pentry0,
1726                       unsigned int total_size,
1727                       unsigned int number,
1728                       unsigned int *hook_entries,
1729                       unsigned int *underflows)
1730{
1731        unsigned int i, j;
1732        struct xt_table_info *newinfo, *info;
1733        void *pos, *entry0, *entry1;
1734        unsigned int size;
1735        int ret;
1736
1737        info = *pinfo;
1738        entry0 = *pentry0;
1739        size = total_size;
1740        info->number = number;
1741
1742        /* Init all hooks to impossible value. */
1743        for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1744                info->hook_entry[i] = 0xFFFFFFFF;
1745                info->underflow[i] = 0xFFFFFFFF;
1746        }
1747
1748        duprintf("translate_compat_table: size %u\n", info->size);
1749        j = 0;
1750        xt_compat_lock(AF_INET6);
1751        /* Walk through entries, checking offsets. */
1752        ret = COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size,
1753                                        check_compat_entry_size_and_hooks,
1754                                        info, &size, entry0,
1755                                        entry0 + total_size,
1756                                        hook_entries, underflows, &j, name);
1757        if (ret != 0)
1758                goto out_unlock;
1759
1760        ret = -EINVAL;
1761        if (j != number) {
1762                duprintf("translate_compat_table: %u not %u entries\n",
1763                         j, number);
1764                goto out_unlock;
1765        }
1766
1767        /* Check hooks all assigned */
1768        for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1769                /* Only hooks which are valid */
1770                if (!(valid_hooks & (1 << i)))
1771                        continue;
1772                if (info->hook_entry[i] == 0xFFFFFFFF) {
1773                        duprintf("Invalid hook entry %u %u\n",
1774                                 i, hook_entries[i]);
1775                        goto out_unlock;
1776                }
1777                if (info->underflow[i] == 0xFFFFFFFF) {
1778                        duprintf("Invalid underflow %u %u\n",
1779                                 i, underflows[i]);
1780                        goto out_unlock;
1781                }
1782        }
1783
1784        ret = -ENOMEM;
1785        newinfo = xt_alloc_table_info(size);
1786        if (!newinfo)
1787                goto out_unlock;
1788
1789        newinfo->number = number;
1790        for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1791                newinfo->hook_entry[i] = info->hook_entry[i];
1792                newinfo->underflow[i] = info->underflow[i];
1793        }
1794        entry1 = newinfo->entries[raw_smp_processor_id()];
1795        pos = entry1;
1796        size = total_size;
1797        ret = COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size,
1798                                        compat_copy_entry_from_user,
1799                                        &pos, &size, name, newinfo, entry1);
1800        xt_compat_flush_offsets(AF_INET6);
1801        xt_compat_unlock(AF_INET6);
1802        if (ret)
1803                goto free_newinfo;
1804
1805        ret = -ELOOP;
1806        if (!mark_source_chains(newinfo, valid_hooks, entry1))
1807                goto free_newinfo;
1808
1809        i = 0;
1810        ret = IP6T_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
1811                                 name, &i);
1812        if (ret) {
1813                j -= i;
1814                COMPAT_IP6T_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i,
1815                                                   compat_release_entry, &j);
1816                IP6T_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i);
1817                xt_free_table_info(newinfo);
1818                return ret;
1819        }
1820
1821        /* And one copy for every other CPU */
1822        for_each_possible_cpu(i)
1823                if (newinfo->entries[i] && newinfo->entries[i] != entry1)
1824                        memcpy(newinfo->entries[i], entry1, newinfo->size);
1825
1826        *pinfo = newinfo;
1827        *pentry0 = entry1;
1828        xt_free_table_info(info);
1829        return 0;
1830
1831free_newinfo:
1832        xt_free_table_info(newinfo);
1833out:
1834        COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j);
1835        return ret;
1836out_unlock:
1837        xt_compat_flush_offsets(AF_INET6);
1838        xt_compat_unlock(AF_INET6);
1839        goto out;
1840}
1841
1842static int
1843compat_do_replace(struct net *net, void __user *user, unsigned int len)
1844{
1845        int ret;
1846        struct compat_ip6t_replace tmp;
1847        struct xt_table_info *newinfo;
1848        void *loc_cpu_entry;
1849
1850        if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1851                return -EFAULT;
1852
1853        /* overflow check */
1854        if (tmp.size >= INT_MAX / num_possible_cpus())
1855                return -ENOMEM;
1856        if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1857                return -ENOMEM;
1858
1859        newinfo = xt_alloc_table_info(tmp.size);
1860        if (!newinfo)
1861                return -ENOMEM;
1862
1863        /* choose the copy that is on our node/cpu */
1864        loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1865        if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1866                           tmp.size) != 0) {
1867                ret = -EFAULT;
1868                goto free_newinfo;
1869        }
1870
1871        ret = translate_compat_table(tmp.name, tmp.valid_hooks,
1872                                     &newinfo, &loc_cpu_entry, tmp.size,
1873                                     tmp.num_entries, tmp.hook_entry,
1874                                     tmp.underflow);
1875        if (ret != 0)
1876                goto free_newinfo;
1877
1878        duprintf("compat_do_replace: Translated table\n");
1879
1880        ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1881                           tmp.num_counters, compat_ptr(tmp.counters));
1882        if (ret)
1883                goto free_newinfo_untrans;
1884        return 0;
1885
1886 free_newinfo_untrans:
1887        IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
1888 free_newinfo:
1889        xt_free_table_info(newinfo);
1890        return ret;
1891}
1892
1893static int
1894compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
1895                       unsigned int len)
1896{
1897        int ret;
1898
1899        if (!capable(CAP_NET_ADMIN))
1900                return -EPERM;
1901
1902        switch (cmd) {
1903        case IP6T_SO_SET_REPLACE:
1904                ret = compat_do_replace(sock_net(sk), user, len);
1905                break;
1906
1907        case IP6T_SO_SET_ADD_COUNTERS:
1908                ret = do_add_counters(sock_net(sk), user, len, 1);
1909                break;
1910
1911        default:
1912                duprintf("do_ip6t_set_ctl:  unknown request %i\n", cmd);
1913                ret = -EINVAL;
1914        }
1915
1916        return ret;
1917}
1918
1919struct compat_ip6t_get_entries {
1920        char name[IP6T_TABLE_MAXNAMELEN];
1921        compat_uint_t size;
1922        struct compat_ip6t_entry entrytable[0];
1923};
1924
1925static int
1926compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1927                            void __user *userptr)
1928{
1929        struct xt_counters *counters;
1930        const struct xt_table_info *private = table->private;
1931        void __user *pos;
1932        unsigned int size;
1933        int ret = 0;
1934        const void *loc_cpu_entry;
1935        unsigned int i = 0;
1936
1937        counters = alloc_counters(table);
1938        if (IS_ERR(counters))
1939                return PTR_ERR(counters);
1940
1941        /* choose the copy that is on our node/cpu, ...
1942         * This choice is lazy (because current thread is
1943         * allowed to migrate to another cpu)
1944         */
1945        loc_cpu_entry = private->entries[raw_smp_processor_id()];
1946        pos = userptr;
1947        size = total_size;
1948        ret = IP6T_ENTRY_ITERATE(loc_cpu_entry, total_size,
1949                                 compat_copy_entry_to_user,
1950                                 &pos, &size, counters, &i);
1951
1952        vfree(counters);
1953        return ret;
1954}
1955
1956static int
1957compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
1958                   int *len)
1959{
1960        int ret;
1961        struct compat_ip6t_get_entries get;
1962        struct xt_table *t;
1963
1964        if (*len < sizeof(get)) {
1965                duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
1966                return -EINVAL;
1967        }
1968
1969        if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1970                return -EFAULT;
1971
1972        if (*len != sizeof(struct compat_ip6t_get_entries) + get.size) {
1973                duprintf("compat_get_entries: %u != %zu\n",
1974                         *len, sizeof(get) + get.size);
1975                return -EINVAL;
1976        }
1977
1978        xt_compat_lock(AF_INET6);
1979        t = xt_find_table_lock(net, AF_INET6, get.name);
1980        if (t && !IS_ERR(t)) {
1981                const struct xt_table_info *private = t->private;
1982                struct xt_table_info info;
1983                duprintf("t->private->number = %u\n", private->number);
1984                ret = compat_table_info(private, &info);
1985                if (!ret && get.size == info.size) {
1986                        ret = compat_copy_entries_to_user(private->size,
1987                                                          t, uptr->entrytable);
1988                } else if (!ret) {
1989                        duprintf("compat_get_entries: I've got %u not %u!\n",
1990                                 private->size, get.size);
1991                        ret = -EAGAIN;
1992                }
1993                xt_compat_flush_offsets(AF_INET6);
1994                module_put(t->me);
1995                xt_table_unlock(t);
1996        } else
1997                ret = t ? PTR_ERR(t) : -ENOENT;
1998
1999        xt_compat_unlock(AF_INET6);
2000        return ret;
2001}
2002
2003static int do_ip6t_get_ctl(struct sock *, int, void __user *, int *);
2004
2005static int
2006compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2007{
2008        int ret;
2009
2010        if (!capable(CAP_NET_ADMIN))
2011                return -EPERM;
2012
2013        switch (cmd) {
2014        case IP6T_SO_GET_INFO:
2015                ret = get_info(sock_net(sk), user, len, 1);
2016                break;
2017        case IP6T_SO_GET_ENTRIES:
2018                ret = compat_get_entries(sock_net(sk), user, len);
2019                break;
2020        default:
2021                ret = do_ip6t_get_ctl(sk, cmd, user, len);
2022        }
2023        return ret;
2024}
2025#endif
2026
2027static int
2028do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2029{
2030        int ret;
2031
2032        if (!capable(CAP_NET_ADMIN))
2033                return -EPERM;
2034
2035        switch (cmd) {
2036        case IP6T_SO_SET_REPLACE:
2037                ret = do_replace(sock_net(sk), user, len);
2038                break;
2039
2040        case IP6T_SO_SET_ADD_COUNTERS:
2041                ret = do_add_counters(sock_net(sk), user, len, 0);
2042                break;
2043
2044        default:
2045                duprintf("do_ip6t_set_ctl:  unknown request %i\n", cmd);
2046                ret = -EINVAL;
2047        }
2048
2049        return ret;
2050}
2051
2052static int
2053do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2054{
2055        int ret;
2056
2057        if (!capable(CAP_NET_ADMIN))
2058                return -EPERM;
2059
2060        switch (cmd) {
2061        case IP6T_SO_GET_INFO:
2062                ret = get_info(sock_net(sk), user, len, 0);
2063                break;
2064
2065        case IP6T_SO_GET_ENTRIES:
2066                ret = get_entries(sock_net(sk), user, len);
2067                break;
2068
2069        case IP6T_SO_GET_REVISION_MATCH:
2070        case IP6T_SO_GET_REVISION_TARGET: {
2071                struct ip6t_get_revision rev;
2072                int target;
2073
2074                if (*len != sizeof(rev)) {
2075                        ret = -EINVAL;
2076                        break;
2077                }
2078                if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
2079                        ret = -EFAULT;
2080                        break;
2081                }
2082
2083                if (cmd == IP6T_SO_GET_REVISION_TARGET)
2084                        target = 1;
2085                else
2086                        target = 0;
2087
2088                try_then_request_module(xt_find_revision(AF_INET6, rev.name,
2089                                                         rev.revision,
2090                                                         target, &ret),
2091                                        "ip6t_%s", rev.name);
2092                break;
2093        }
2094
2095        default:
2096                duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
2097                ret = -EINVAL;
2098        }
2099
2100        return ret;
2101}
2102
2103struct xt_table *ip6t_register_table(struct net *net,
2104                                     const struct xt_table *table,
2105                                     const struct ip6t_replace *repl)
2106{
2107        int ret;
2108        struct xt_table_info *newinfo;
2109        struct xt_table_info bootstrap
2110                = { 0, 0, 0, { 0 }, { 0 }, { } };
2111        void *loc_cpu_entry;
2112        struct xt_table *new_table;
2113
2114        newinfo = xt_alloc_table_info(repl->size);
2115        if (!newinfo) {
2116                ret = -ENOMEM;
2117                goto out;
2118        }
2119
2120        /* choose the copy on our node/cpu, but dont care about preemption */
2121        loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
2122        memcpy(loc_cpu_entry, repl->entries, repl->size);
2123
2124        ret = translate_table(table->name, table->valid_hooks,
2125                              newinfo, loc_cpu_entry, repl->size,
2126                              repl->num_entries,
2127                              repl->hook_entry,
2128                              repl->underflow);
2129        if (ret != 0)
2130                goto out_free;
2131
2132        new_table = xt_register_table(net, table, &bootstrap, newinfo);
2133        if (IS_ERR(new_table)) {
2134                ret = PTR_ERR(new_table);
2135                goto out_free;
2136        }
2137        return new_table;
2138
2139out_free:
2140        xt_free_table_info(newinfo);
2141out:
2142        return ERR_PTR(ret);
2143}
2144
2145void ip6t_unregister_table(struct xt_table *table)
2146{
2147        struct xt_table_info *private;
2148        void *loc_cpu_entry;
2149        struct module *table_owner = table->me;
2150
2151        private = xt_unregister_table(table);
2152
2153        /* Decrease module usage counts and free resources */
2154        loc_cpu_entry = private->entries[raw_smp_processor_id()];
2155        IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
2156        if (private->number > private->initial_entries)
2157                module_put(table_owner);
2158        xt_free_table_info(private);
2159}
2160
2161/* Returns 1 if the type and code is matched by the range, 0 otherwise */
2162static inline bool
2163icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
2164                     u_int8_t type, u_int8_t code,
2165                     bool invert)
2166{
2167        return (type == test_type && code >= min_code && code <= max_code)
2168                ^ invert;
2169}
2170
2171static bool
2172icmp6_match(const struct sk_buff *skb, const struct xt_match_param *par)
2173{
2174        const struct icmp6hdr *ic;
2175        struct icmp6hdr _icmph;
2176        const struct ip6t_icmp *icmpinfo = par->matchinfo;
2177
2178        /* Must not be a fragment. */
2179        if (par->fragoff != 0)
2180                return false;
2181
2182        ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
2183        if (ic == NULL) {
2184                /* We've been asked to examine this packet, and we
2185                 * can't.  Hence, no choice but to drop.
2186                 */
2187                duprintf("Dropping evil ICMP tinygram.\n");
2188                *par->hotdrop = true;
2189                return false;
2190        }
2191
2192        return icmp6_type_code_match(icmpinfo->type,
2193                                     icmpinfo->code[0],
2194                                     icmpinfo->code[1],
2195                                     ic->icmp6_type, ic->icmp6_code,
2196                                     !!(icmpinfo->invflags&IP6T_ICMP_INV));
2197}
2198
2199/* Called when user tries to insert an entry of this type. */
2200static bool icmp6_checkentry(const struct xt_mtchk_param *par)
2201{
2202        const struct ip6t_icmp *icmpinfo = par->matchinfo;
2203
2204        /* Must specify no unknown invflags */
2205        return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
2206}
2207
2208/* The built-in targets: standard (NULL) and error. */
2209static struct xt_target ip6t_standard_target __read_mostly = {
2210        .name           = IP6T_STANDARD_TARGET,
2211        .targetsize     = sizeof(int),
2212        .family         = NFPROTO_IPV6,
2213#ifdef CONFIG_COMPAT
2214        .compatsize     = sizeof(compat_int_t),
2215        .compat_from_user = compat_standard_from_user,
2216        .compat_to_user = compat_standard_to_user,
2217#endif
2218};
2219
2220static struct xt_target ip6t_error_target __read_mostly = {
2221        .name           = IP6T_ERROR_TARGET,
2222        .target         = ip6t_error,
2223        .targetsize     = IP6T_FUNCTION_MAXNAMELEN,
2224        .family         = NFPROTO_IPV6,
2225};
2226
2227static struct nf_sockopt_ops ip6t_sockopts = {
2228        .pf             = PF_INET6,
2229        .set_optmin     = IP6T_BASE_CTL,
2230        .set_optmax     = IP6T_SO_SET_MAX+1,
2231        .set            = do_ip6t_set_ctl,
2232#ifdef CONFIG_COMPAT
2233        .compat_set     = compat_do_ip6t_set_ctl,
2234#endif
2235        .get_optmin     = IP6T_BASE_CTL,
2236        .get_optmax     = IP6T_SO_GET_MAX+1,
2237        .get            = do_ip6t_get_ctl,
2238#ifdef CONFIG_COMPAT
2239        .compat_get     = compat_do_ip6t_get_ctl,
2240#endif
2241        .owner          = THIS_MODULE,
2242};
2243
2244static struct xt_match icmp6_matchstruct __read_mostly = {
2245        .name           = "icmp6",
2246        .match          = icmp6_match,
2247        .matchsize      = sizeof(struct ip6t_icmp),
2248        .checkentry     = icmp6_checkentry,
2249        .proto          = IPPROTO_ICMPV6,
2250        .family         = NFPROTO_IPV6,
2251};
2252
2253static int __net_init ip6_tables_net_init(struct net *net)
2254{
2255        return xt_proto_init(net, NFPROTO_IPV6);
2256}
2257
2258static void __net_exit ip6_tables_net_exit(struct net *net)
2259{
2260        xt_proto_fini(net, NFPROTO_IPV6);
2261}
2262
2263static struct pernet_operations ip6_tables_net_ops = {
2264        .init = ip6_tables_net_init,
2265        .exit = ip6_tables_net_exit,
2266};
2267
2268static int __init ip6_tables_init(void)
2269{
2270        int ret;
2271
2272        ret = register_pernet_subsys(&ip6_tables_net_ops);
2273        if (ret < 0)
2274                goto err1;
2275
2276        /* Noone else will be downing sem now, so we won't sleep */
2277        ret = xt_register_target(&ip6t_standard_target);
2278        if (ret < 0)
2279                goto err2;
2280        ret = xt_register_target(&ip6t_error_target);
2281        if (ret < 0)
2282                goto err3;
2283        ret = xt_register_match(&icmp6_matchstruct);
2284        if (ret < 0)
2285                goto err4;
2286
2287        /* Register setsockopt */
2288        ret = nf_register_sockopt(&ip6t_sockopts);
2289        if (ret < 0)
2290                goto err5;
2291
2292        printk(KERN_INFO "ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
2293        return 0;
2294
2295err5:
2296        xt_unregister_match(&icmp6_matchstruct);
2297err4:
2298        xt_unregister_target(&ip6t_error_target);
2299err3:
2300        xt_unregister_target(&ip6t_standard_target);
2301err2:
2302        unregister_pernet_subsys(&ip6_tables_net_ops);
2303err1:
2304        return ret;
2305}
2306
2307static void __exit ip6_tables_fini(void)
2308{
2309        nf_unregister_sockopt(&ip6t_sockopts);
2310
2311        xt_unregister_match(&icmp6_matchstruct);
2312        xt_unregister_target(&ip6t_error_target);
2313        xt_unregister_target(&ip6t_standard_target);
2314
2315        unregister_pernet_subsys(&ip6_tables_net_ops);
2316}
2317
2318/*
2319 * find the offset to specified header or the protocol number of last header
2320 * if target < 0. "last header" is transport protocol header, ESP, or
2321 * "No next header".
2322 *
2323 * If target header is found, its offset is set in *offset and return protocol
2324 * number. Otherwise, return -1.
2325 *
2326 * If the first fragment doesn't contain the final protocol header or
2327 * NEXTHDR_NONE it is considered invalid.
2328 *
2329 * Note that non-1st fragment is special case that "the protocol number
2330 * of last header" is "next header" field in Fragment header. In this case,
2331 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
2332 * isn't NULL.
2333 *
2334 */
2335int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
2336                  int target, unsigned short *fragoff)
2337{
2338        unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
2339        u8 nexthdr = ipv6_hdr(skb)->nexthdr;
2340        unsigned int len = skb->len - start;
2341
2342        if (fragoff)
2343                *fragoff = 0;
2344
2345        while (nexthdr != target) {
2346                struct ipv6_opt_hdr _hdr, *hp;
2347                unsigned int hdrlen;
2348
2349                if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
2350                        if (target < 0)
2351                                break;
2352                        return -ENOENT;
2353                }
2354
2355                hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
2356                if (hp == NULL)
2357                        return -EBADMSG;
2358                if (nexthdr == NEXTHDR_FRAGMENT) {
2359                        unsigned short _frag_off;
2360                        __be16 *fp;
2361                        fp = skb_header_pointer(skb,
2362                                                start+offsetof(struct frag_hdr,
2363                                                               frag_off),
2364                                                sizeof(_frag_off),
2365                                                &_frag_off);
2366                        if (fp == NULL)
2367                                return -EBADMSG;
2368
2369                        _frag_off = ntohs(*fp) & ~0x7;
2370                        if (_frag_off) {
2371                                if (target < 0 &&
2372                                    ((!ipv6_ext_hdr(hp->nexthdr)) ||
2373                                     hp->nexthdr == NEXTHDR_NONE)) {
2374                                        if (fragoff)
2375                                                *fragoff = _frag_off;
2376                                        return hp->nexthdr;
2377                                }
2378                                return -ENOENT;
2379                        }
2380                        hdrlen = 8;
2381                } else if (nexthdr == NEXTHDR_AUTH)
2382                        hdrlen = (hp->hdrlen + 2) << 2;
2383                else
2384                        hdrlen = ipv6_optlen(hp);
2385
2386                nexthdr = hp->nexthdr;
2387                len -= hdrlen;
2388                start += hdrlen;
2389        }
2390
2391        *offset = start;
2392        return nexthdr;
2393}
2394
2395EXPORT_SYMBOL(ip6t_register_table);
2396EXPORT_SYMBOL(ip6t_unregister_table);
2397EXPORT_SYMBOL(ip6t_do_table);
2398EXPORT_SYMBOL(ip6t_ext_hdr);
2399EXPORT_SYMBOL(ipv6_find_hdr);
2400
2401module_init(ip6_tables_init);
2402module_exit(ip6_tables_fini);
2403