aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2016-04-01 08:17:21 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2016-04-13 18:30:34 -0400
commitf24e230d257af1ad7476c6e81a8dc3127a74204e (patch)
tree941d889997d998419e5d3a6e5486188dfe5457a7
parent7d45a04cbc2683f9552572850f1c711d9b96dd26 (diff)
netfilter: x_tables: don't move to non-existent next rule
Ben Hawkes says: In the mark_source_chains function (net/ipv4/netfilter/ip_tables.c) it is possible for a user-supplied ipt_entry structure to have a large next_offset field. This field is not bounds checked prior to writing a counter value at the supplied offset. Base chains enforce absolute verdict. User defined chains are supposed to end with an unconditional return, xtables userspace adds them automatically. But if such return is missing we will move to non-existent next rule. Reported-by: Ben Hawkes <hawkes@google.com> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--net/ipv4/netfilter/arp_tables.c8
-rw-r--r--net/ipv4/netfilter/ip_tables.c4
-rw-r--r--net/ipv6/netfilter/ip6_tables.c4
3 files changed, 13 insertions, 3 deletions
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 4133b0f513af..82a434bf8653 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -439,6 +439,8 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
439 size = e->next_offset; 439 size = e->next_offset;
440 e = (struct arpt_entry *) 440 e = (struct arpt_entry *)
441 (entry0 + pos + size); 441 (entry0 + pos + size);
442 if (pos + size >= newinfo->size)
443 return 0;
442 e->counters.pcnt = pos; 444 e->counters.pcnt = pos;
443 pos += size; 445 pos += size;
444 } else { 446 } else {
@@ -461,6 +463,8 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
461 } else { 463 } else {
462 /* ... this is a fallthru */ 464 /* ... this is a fallthru */
463 newpos = pos + e->next_offset; 465 newpos = pos + e->next_offset;
466 if (newpos >= newinfo->size)
467 return 0;
464 } 468 }
465 e = (struct arpt_entry *) 469 e = (struct arpt_entry *)
466 (entry0 + newpos); 470 (entry0 + newpos);
@@ -691,10 +695,8 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0,
691 } 695 }
692 } 696 }
693 697
694 if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) { 698 if (!mark_source_chains(newinfo, repl->valid_hooks, entry0))
695 duprintf("Looping hook\n");
696 return -ELOOP; 699 return -ELOOP;
697 }
698 700
699 /* Finally, each sanity check must pass */ 701 /* Finally, each sanity check must pass */
700 i = 0; 702 i = 0;
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 631c100a1338..e301a3db4717 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -520,6 +520,8 @@ mark_source_chains(const struct xt_table_info *newinfo,
520 size = e->next_offset; 520 size = e->next_offset;
521 e = (struct ipt_entry *) 521 e = (struct ipt_entry *)
522 (entry0 + pos + size); 522 (entry0 + pos + size);
523 if (pos + size >= newinfo->size)
524 return 0;
523 e->counters.pcnt = pos; 525 e->counters.pcnt = pos;
524 pos += size; 526 pos += size;
525 } else { 527 } else {
@@ -541,6 +543,8 @@ mark_source_chains(const struct xt_table_info *newinfo,
541 } else { 543 } else {
542 /* ... this is a fallthru */ 544 /* ... this is a fallthru */
543 newpos = pos + e->next_offset; 545 newpos = pos + e->next_offset;
546 if (newpos >= newinfo->size)
547 return 0;
544 } 548 }
545 e = (struct ipt_entry *) 549 e = (struct ipt_entry *)
546 (entry0 + newpos); 550 (entry0 + newpos);
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 86b67b70b626..7b3335bce3fd 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -532,6 +532,8 @@ mark_source_chains(const struct xt_table_info *newinfo,
532 size = e->next_offset; 532 size = e->next_offset;
533 e = (struct ip6t_entry *) 533 e = (struct ip6t_entry *)
534 (entry0 + pos + size); 534 (entry0 + pos + size);
535 if (pos + size >= newinfo->size)
536 return 0;
535 e->counters.pcnt = pos; 537 e->counters.pcnt = pos;
536 pos += size; 538 pos += size;
537 } else { 539 } else {
@@ -553,6 +555,8 @@ mark_source_chains(const struct xt_table_info *newinfo,
553 } else { 555 } else {
554 /* ... this is a fallthru */ 556 /* ... this is a fallthru */
555 newpos = pos + e->next_offset; 557 newpos = pos + e->next_offset;
558 if (newpos >= newinfo->size)
559 return 0;
556 } 560 }
557 e = (struct ip6t_entry *) 561 e = (struct ip6t_entry *)
558 (entry0 + newpos); 562 (entry0 + newpos);