pandora: defconfig: update
[pandora-kernel.git] / net / ipv4 / netfilter / ip_tables.c
index cfa2952..41c01de 100644 (file)
@@ -168,11 +168,12 @@ get_entry(const void *base, unsigned int offset)
 
 /* All zeroes == unconditional rule. */
 /* Mildly perf critical (only if packet tracing is on) */
-static inline bool unconditional(const struct ipt_ip *ip)
+static inline bool unconditional(const struct ipt_entry *e)
 {
        static const struct ipt_ip uncond;
 
-       return memcmp(ip, &uncond, sizeof(uncond)) == 0;
+       return e->target_offset == sizeof(struct ipt_entry) &&
+              memcmp(&e->ip, &uncond, sizeof(uncond)) == 0;
 #undef FWINV
 }
 
@@ -230,11 +231,10 @@ get_chainname_rulenum(const struct ipt_entry *s, const struct ipt_entry *e,
        } else if (s == e) {
                (*rulenum)++;
 
-               if (s->target_offset == sizeof(struct ipt_entry) &&
+               if (unconditional(s) &&
                    strcmp(t->target.u.kernel.target->name,
                           XT_STANDARD_TARGET) == 0 &&
-                  t->verdict < 0 &&
-                  unconditional(&s->ip)) {
+                  t->verdict < 0) {
                        /* Tail of chains: STANDARD target (return/policy) */
                        *comment = *chainname == hookname
                                ? comments[NF_IP_TRACE_COMMENT_POLICY]
@@ -468,11 +468,10 @@ mark_source_chains(const struct xt_table_info *newinfo,
                        e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
 
                        /* Unconditional return/END. */
-                       if ((e->target_offset == sizeof(struct ipt_entry) &&
+                       if ((unconditional(e) &&
                             (strcmp(t->target.u.user.name,
                                     XT_STANDARD_TARGET) == 0) &&
-                            t->verdict < 0 && unconditional(&e->ip)) ||
-                           visited) {
+                            t->verdict < 0) || visited) {
                                unsigned int oldpos, size;
 
                                if ((strcmp(t->target.u.user.name,
@@ -699,7 +698,7 @@ static bool check_underflow(const struct ipt_entry *e)
        const struct xt_entry_target *t;
        unsigned int verdict;
 
-       if (!unconditional(&e->ip))
+       if (!unconditional(e))
                return false;
        t = ipt_get_target_c(e);
        if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
@@ -722,7 +721,8 @@ check_entry_size_and_hooks(struct ipt_entry *e,
        int err;
 
        if ((unsigned long)e % __alignof__(struct ipt_entry) != 0 ||
-           (unsigned char *)e + sizeof(struct ipt_entry) >= limit) {
+           (unsigned char *)e + sizeof(struct ipt_entry) >= limit ||
+           (unsigned char *)e + e->next_offset > limit) {
                duprintf("Bad offset %p\n", e);
                return -EINVAL;
        }
@@ -746,9 +746,9 @@ check_entry_size_and_hooks(struct ipt_entry *e,
                        newinfo->hook_entry[h] = hook_entries[h];
                if ((unsigned char *)e - base == underflows[h]) {
                        if (!check_underflow(e)) {
-                               pr_err("Underflows must be unconditional and "
-                                      "use the STANDARD target with "
-                                      "ACCEPT/DROP\n");
+                               pr_debug("Underflows must be unconditional and "
+                                        "use the STANDARD target with "
+                                        "ACCEPT/DROP\n");
                                return -EINVAL;
                        }
                        newinfo->underflow[h] = underflows[h];
@@ -1485,7 +1485,8 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
 
        duprintf("check_compat_entry_size_and_hooks %p\n", e);
        if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0 ||
-           (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) {
+           (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit ||
+           (unsigned char *)e + e->next_offset > limit) {
                duprintf("Bad offset %p, limit = %p\n", e, limit);
                return -EINVAL;
        }