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