aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorJan Engelhardt <jengelh@medozas.de>2010-04-19 10:05:10 -0400
committerPatrick McHardy <kaber@trash.net>2010-04-19 10:05:10 -0400
commitf3c5c1bfd430858d3a05436f82c51e53104feb6b (patch)
treeada5b570b66e141e79fdb256f69e2541a3d30c04 /net/ipv4
parente281b19897dc21c1071802808d461627d747a877 (diff)
netfilter: xtables: make ip_tables reentrant
Currently, the table traverser stores return addresses in the ruleset itself (struct ip6t_entry->comefrom). This has a well-known drawback: the jumpstack is overwritten on reentry, making it necessary for targets to return absolute verdicts. Also, the ruleset (which might be heavy memory-wise) needs to be replicated for each CPU that can possibly invoke ip6t_do_table. This patch decouples the jumpstack from struct ip6t_entry and instead puts it into xt_table_info. Not being restricted by 'comefrom' anymore, we can set up a stack as needed. By default, there is room allocated for two entries into the traverser. arp_tables is not touched though, because there is just one/two modules and further patches seek to collapse the table traverser anyhow. Signed-off-by: Jan Engelhardt <jengelh@medozas.de> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/netfilter/arp_tables.c6
-rw-r--r--net/ipv4/netfilter/ip_tables.c65
2 files changed, 39 insertions, 32 deletions
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index e8e363d90365..07a699059390 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -649,6 +649,9 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0,
649 if (ret != 0) 649 if (ret != 0)
650 break; 650 break;
651 ++i; 651 ++i;
652 if (strcmp(arpt_get_target(iter)->u.user.name,
653 XT_ERROR_TARGET) == 0)
654 ++newinfo->stacksize;
652 } 655 }
653 duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); 656 duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret);
654 if (ret != 0) 657 if (ret != 0)
@@ -1774,8 +1777,7 @@ struct xt_table *arpt_register_table(struct net *net,
1774{ 1777{
1775 int ret; 1778 int ret;
1776 struct xt_table_info *newinfo; 1779 struct xt_table_info *newinfo;
1777 struct xt_table_info bootstrap 1780 struct xt_table_info bootstrap = {0};
1778 = { 0, 0, 0, { 0 }, { 0 }, { } };
1779 void *loc_cpu_entry; 1781 void *loc_cpu_entry;
1780 struct xt_table *new_table; 1782 struct xt_table *new_table;
1781 1783
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 18c5b1573f3e..70900ecf88e2 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -321,8 +321,6 @@ ipt_do_table(struct sk_buff *skb,
321 const struct net_device *out, 321 const struct net_device *out,
322 struct xt_table *table) 322 struct xt_table *table)
323{ 323{
324#define tb_comefrom ((struct ipt_entry *)table_base)->comefrom
325
326 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); 324 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
327 const struct iphdr *ip; 325 const struct iphdr *ip;
328 bool hotdrop = false; 326 bool hotdrop = false;
@@ -330,7 +328,8 @@ ipt_do_table(struct sk_buff *skb,
330 unsigned int verdict = NF_DROP; 328 unsigned int verdict = NF_DROP;
331 const char *indev, *outdev; 329 const char *indev, *outdev;
332 const void *table_base; 330 const void *table_base;
333 struct ipt_entry *e, *back; 331 struct ipt_entry *e, **jumpstack;
332 unsigned int *stackptr, origptr, cpu;
334 const struct xt_table_info *private; 333 const struct xt_table_info *private;
335 struct xt_match_param mtpar; 334 struct xt_match_param mtpar;
336 struct xt_target_param tgpar; 335 struct xt_target_param tgpar;
@@ -356,19 +355,23 @@ ipt_do_table(struct sk_buff *skb,
356 IP_NF_ASSERT(table->valid_hooks & (1 << hook)); 355 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
357 xt_info_rdlock_bh(); 356 xt_info_rdlock_bh();
358 private = table->private; 357 private = table->private;
359 table_base = private->entries[smp_processor_id()]; 358 cpu = smp_processor_id();
359 table_base = private->entries[cpu];
360 jumpstack = (struct ipt_entry **)private->jumpstack[cpu];
361 stackptr = &private->stackptr[cpu];
362 origptr = *stackptr;
360 363
361 e = get_entry(table_base, private->hook_entry[hook]); 364 e = get_entry(table_base, private->hook_entry[hook]);
362 365
363 /* For return from builtin chain */ 366 pr_devel("Entering %s(hook %u); sp at %u (UF %p)\n",
364 back = get_entry(table_base, private->underflow[hook]); 367 table->name, hook, origptr,
368 get_entry(table_base, private->underflow[hook]));
365 369
366 do { 370 do {
367 const struct ipt_entry_target *t; 371 const struct ipt_entry_target *t;
368 const struct xt_entry_match *ematch; 372 const struct xt_entry_match *ematch;
369 373
370 IP_NF_ASSERT(e); 374 IP_NF_ASSERT(e);
371 IP_NF_ASSERT(back);
372 if (!ip_packet_match(ip, indev, outdev, 375 if (!ip_packet_match(ip, indev, outdev,
373 &e->ip, mtpar.fragoff)) { 376 &e->ip, mtpar.fragoff)) {
374 no_match: 377 no_match:
@@ -403,17 +406,28 @@ ipt_do_table(struct sk_buff *skb,
403 verdict = (unsigned)(-v) - 1; 406 verdict = (unsigned)(-v) - 1;
404 break; 407 break;
405 } 408 }
406 e = back; 409 if (*stackptr == 0) {
407 back = get_entry(table_base, back->comefrom); 410 e = get_entry(table_base,
411 private->underflow[hook]);
412 pr_devel("Underflow (this is normal) "
413 "to %p\n", e);
414 } else {
415 e = jumpstack[--*stackptr];
416 pr_devel("Pulled %p out from pos %u\n",
417 e, *stackptr);
418 e = ipt_next_entry(e);
419 }
408 continue; 420 continue;
409 } 421 }
410 if (table_base + v != ipt_next_entry(e) && 422 if (table_base + v != ipt_next_entry(e) &&
411 !(e->ip.flags & IPT_F_GOTO)) { 423 !(e->ip.flags & IPT_F_GOTO)) {
412 /* Save old back ptr in next entry */ 424 if (*stackptr >= private->stacksize) {
413 struct ipt_entry *next = ipt_next_entry(e); 425 verdict = NF_DROP;
414 next->comefrom = (void *)back - table_base; 426 break;
415 /* set back pointer to next entry */ 427 }
416 back = next; 428 jumpstack[(*stackptr)++] = e;
429 pr_devel("Pushed %p into pos %u\n",
430 e, *stackptr - 1);
417 } 431 }
418 432
419 e = get_entry(table_base, v); 433 e = get_entry(table_base, v);
@@ -426,18 +440,7 @@ ipt_do_table(struct sk_buff *skb,
426 tgpar.targinfo = t->data; 440 tgpar.targinfo = t->data;
427 441
428 442
429#ifdef CONFIG_NETFILTER_DEBUG
430 tb_comefrom = 0xeeeeeeec;
431#endif
432 verdict = t->u.kernel.target->target(skb, &tgpar); 443 verdict = t->u.kernel.target->target(skb, &tgpar);
433#ifdef CONFIG_NETFILTER_DEBUG
434 if (tb_comefrom != 0xeeeeeeec && verdict == IPT_CONTINUE) {
435 printk("Target %s reentered!\n",
436 t->u.kernel.target->name);
437 verdict = NF_DROP;
438 }
439 tb_comefrom = 0x57acc001;
440#endif
441 /* Target might have changed stuff. */ 444 /* Target might have changed stuff. */
442 ip = ip_hdr(skb); 445 ip = ip_hdr(skb);
443 if (verdict == IPT_CONTINUE) 446 if (verdict == IPT_CONTINUE)
@@ -447,7 +450,9 @@ ipt_do_table(struct sk_buff *skb,
447 break; 450 break;
448 } while (!hotdrop); 451 } while (!hotdrop);
449 xt_info_rdunlock_bh(); 452 xt_info_rdunlock_bh();
450 453 pr_devel("Exiting %s; resetting sp from %u to %u\n",
454 __func__, *stackptr, origptr);
455 *stackptr = origptr;
451#ifdef DEBUG_ALLOW_ALL 456#ifdef DEBUG_ALLOW_ALL
452 return NF_ACCEPT; 457 return NF_ACCEPT;
453#else 458#else
@@ -455,8 +460,6 @@ ipt_do_table(struct sk_buff *skb,
455 return NF_DROP; 460 return NF_DROP;
456 else return verdict; 461 else return verdict;
457#endif 462#endif
458
459#undef tb_comefrom
460} 463}
461 464
462/* Figures out from what hook each rule can be called: returns 0 if 465/* Figures out from what hook each rule can be called: returns 0 if
@@ -838,6 +841,9 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
838 if (ret != 0) 841 if (ret != 0)
839 return ret; 842 return ret;
840 ++i; 843 ++i;
844 if (strcmp(ipt_get_target(iter)->u.user.name,
845 XT_ERROR_TARGET) == 0)
846 ++newinfo->stacksize;
841 } 847 }
842 848
843 if (i != repl->num_entries) { 849 if (i != repl->num_entries) {
@@ -2086,8 +2092,7 @@ struct xt_table *ipt_register_table(struct net *net,
2086{ 2092{
2087 int ret; 2093 int ret;
2088 struct xt_table_info *newinfo; 2094 struct xt_table_info *newinfo;
2089 struct xt_table_info bootstrap 2095 struct xt_table_info bootstrap = {0};
2090 = { 0, 0, 0, { 0 }, { 0 }, { } };
2091 void *loc_cpu_entry; 2096 void *loc_cpu_entry;
2092 struct xt_table *new_table; 2097 struct xt_table *new_table;
2093 2098