|
@@ -296,12 +296,13 @@ ipt_do_table(struct sk_buff *skb,
|
|
|
const char *indev, *outdev;
|
|
|
const void *table_base;
|
|
|
struct ipt_entry *e, **jumpstack;
|
|
|
- unsigned int *stackptr, origptr, cpu;
|
|
|
+ unsigned int stackidx, cpu;
|
|
|
const struct xt_table_info *private;
|
|
|
struct xt_action_param acpar;
|
|
|
unsigned int addend;
|
|
|
|
|
|
/* Initialization */
|
|
|
+ stackidx = 0;
|
|
|
ip = ip_hdr(skb);
|
|
|
indev = state->in ? state->in->name : nulldevname;
|
|
|
outdev = state->out ? state->out->name : nulldevname;
|
|
@@ -331,13 +332,20 @@ ipt_do_table(struct sk_buff *skb,
|
|
|
smp_read_barrier_depends();
|
|
|
table_base = private->entries;
|
|
|
jumpstack = (struct ipt_entry **)private->jumpstack[cpu];
|
|
|
- stackptr = per_cpu_ptr(private->stackptr, cpu);
|
|
|
- origptr = *stackptr;
|
|
|
+
|
|
|
+ /* Switch to alternate jumpstack if we're being invoked via TEE.
|
|
|
+ * TEE issues XT_CONTINUE verdict on original skb so we must not
|
|
|
+ * clobber the jumpstack.
|
|
|
+ *
|
|
|
+ * For recursion via REJECT or SYNPROXY the stack will be clobbered
|
|
|
+ * but it is no problem since absolute verdict is issued by these.
|
|
|
+ */
|
|
|
+ jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated);
|
|
|
|
|
|
e = get_entry(table_base, private->hook_entry[hook]);
|
|
|
|
|
|
- pr_debug("Entering %s(hook %u); sp at %u (UF %p)\n",
|
|
|
- table->name, hook, origptr,
|
|
|
+ pr_debug("Entering %s(hook %u), UF %p\n",
|
|
|
+ table->name, hook,
|
|
|
get_entry(table_base, private->underflow[hook]));
|
|
|
|
|
|
do {
|
|
@@ -383,28 +391,24 @@ ipt_do_table(struct sk_buff *skb,
|
|
|
verdict = (unsigned int)(-v) - 1;
|
|
|
break;
|
|
|
}
|
|
|
- if (*stackptr <= origptr) {
|
|
|
+ if (stackidx == 0) {
|
|
|
e = get_entry(table_base,
|
|
|
private->underflow[hook]);
|
|
|
pr_debug("Underflow (this is normal) "
|
|
|
"to %p\n", e);
|
|
|
} else {
|
|
|
- e = jumpstack[--*stackptr];
|
|
|
+ e = jumpstack[--stackidx];
|
|
|
pr_debug("Pulled %p out from pos %u\n",
|
|
|
- e, *stackptr);
|
|
|
+ e, stackidx);
|
|
|
e = ipt_next_entry(e);
|
|
|
}
|
|
|
continue;
|
|
|
}
|
|
|
if (table_base + v != ipt_next_entry(e) &&
|
|
|
!(e->ip.flags & IPT_F_GOTO)) {
|
|
|
- if (*stackptr >= private->stacksize) {
|
|
|
- verdict = NF_DROP;
|
|
|
- break;
|
|
|
- }
|
|
|
- jumpstack[(*stackptr)++] = e;
|
|
|
+ jumpstack[stackidx++] = e;
|
|
|
pr_debug("Pushed %p into pos %u\n",
|
|
|
- e, *stackptr - 1);
|
|
|
+ e, stackidx - 1);
|
|
|
}
|
|
|
|
|
|
e = get_entry(table_base, v);
|
|
@@ -423,9 +427,8 @@ ipt_do_table(struct sk_buff *skb,
|
|
|
/* Verdict */
|
|
|
break;
|
|
|
} while (!acpar.hotdrop);
|
|
|
- pr_debug("Exiting %s; resetting sp from %u to %u\n",
|
|
|
- __func__, *stackptr, origptr);
|
|
|
- *stackptr = origptr;
|
|
|
+ pr_debug("Exiting %s; sp at %u\n", __func__, stackidx);
|
|
|
+
|
|
|
xt_write_recseq_end(addend);
|
|
|
local_bh_enable();
|
|
|
|