diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index aaafdbd15ad3517250971e2ade4ea568515292cc..f366ff1cfc19ed89d83d0c6a420abeafa0b1debe 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -309,10 +309,13 @@ static int mark_source_chains(const struct xt_table_info *newinfo, for (hook = 0; hook < NF_ARP_NUMHOOKS; hook++) { unsigned int pos = newinfo->hook_entry[hook]; struct arpt_entry *e = entry0 + pos; + unsigned int last_pos, depth; if (!(valid_hooks & (1 << hook))) continue; + depth = 0; + last_pos = pos; /* Set initial back pointer. */ e->counters.pcnt = pos; @@ -343,6 +346,8 @@ static int mark_source_chains(const struct xt_table_info *newinfo, pos = e->counters.pcnt; e->counters.pcnt = 0; + if (depth) + --depth; /* We're at the start. */ if (pos == oldpos) goto next; @@ -367,6 +372,9 @@ static int mark_source_chains(const struct xt_table_info *newinfo, if (!xt_find_jump_offset(offsets, newpos, newinfo->number)) return 0; + + if (entry0 + newpos != arpt_next_entry(e)) + ++depth; } else { /* ... this is a fallthru */ newpos = pos + e->next_offset; @@ -377,8 +385,15 @@ static int mark_source_chains(const struct xt_table_info *newinfo, e->counters.pcnt = pos; pos = newpos; } + if (depth == 0) + last_pos = pos; + } +next: + if (last_pos != newinfo->underflow[hook]) { + pr_err_ratelimited("last base chain position %u doesn't match underflow %u (hook %u)\n", + last_pos, newinfo->underflow[hook], hook); + return 0; } -next: ; } return 1; } diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index f9063513f9d19878edf8cca7641fdb10c4d061af..2362ca2c9e0c10235be1c773046ece2b06633298 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -378,10 +378,13 @@ mark_source_chains(const struct xt_table_info *newinfo, for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) { unsigned int pos = newinfo->hook_entry[hook]; struct ipt_entry *e = entry0 + pos; + unsigned int last_pos, depth; if (!(valid_hooks & (1 << hook))) continue; + depth = 0; + last_pos = pos; /* Set initial back pointer. */ e->counters.pcnt = pos; @@ -410,6 +413,8 @@ mark_source_chains(const struct xt_table_info *newinfo, pos = e->counters.pcnt; e->counters.pcnt = 0; + if (depth) + --depth; /* We're at the start. */ if (pos == oldpos) goto next; @@ -434,6 +439,9 @@ mark_source_chains(const struct xt_table_info *newinfo, if (!xt_find_jump_offset(offsets, newpos, newinfo->number)) return 0; + + if (entry0 + newpos != ipt_next_entry(e)) + ++depth; } else { /* ... this is a fallthru */ newpos = pos + e->next_offset; @@ -444,8 +452,15 @@ mark_source_chains(const struct xt_table_info *newinfo, e->counters.pcnt = pos; pos = newpos; } + if (depth == 0) + last_pos = pos; + } +next: + if (last_pos != newinfo->underflow[hook]) { + pr_err_ratelimited("last base chain position %u doesn't match underflow %u (hook %u)\n", + last_pos, newinfo->underflow[hook], hook); + return 0; } -next: ; } return 1; } diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 3c36a4c77f2920077673dfaca20034746149577a..004508753abc62d2889469362c92fa94e2ba7244 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -396,10 +396,13 @@ mark_source_chains(const struct xt_table_info *newinfo, for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) { unsigned int pos = newinfo->hook_entry[hook]; struct ip6t_entry *e = entry0 + pos; + unsigned int last_pos, depth; if (!(valid_hooks & (1 << hook))) continue; + depth = 0; + last_pos = pos; /* Set initial back pointer. */ e->counters.pcnt = pos; @@ -428,6 +431,8 @@ mark_source_chains(const struct xt_table_info *newinfo, pos = e->counters.pcnt; e->counters.pcnt = 0; + if (depth) + --depth; /* We're at the start. */ if (pos == oldpos) goto next; @@ -452,6 +457,9 @@ mark_source_chains(const struct xt_table_info *newinfo, if (!xt_find_jump_offset(offsets, newpos, newinfo->number)) return 0; + + if (entry0 + newpos != ip6t_next_entry(e)) + ++depth; } else { /* ... this is a fallthru */ newpos = pos + e->next_offset; @@ -462,8 +470,15 @@ mark_source_chains(const struct xt_table_info *newinfo, e->counters.pcnt = pos; pos = newpos; } + if (depth == 0) + last_pos = pos; + } +next: + if (last_pos != newinfo->underflow[hook]) { + pr_err_ratelimited("last base chain position %u doesn't match underflow %u (hook %u)\n", + last_pos, newinfo->underflow[hook], hook); + return 0; } -next: ; } return 1; }