aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2014-04-04 11:57:45 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2014-04-05 11:46:22 -0400
commitc58dd2dd443c26d856a168db108a0cd11c285bf3 (patch)
treefc3b89ed8e66d3f99f9322efc812e8c7bcd60509 /net/ipv4
parent2fec6bb6f484b1a88b4a325724234d6cfd08c918 (diff)
netfilter: Can't fail and free after table replacement
All xtables variants suffer from the defect that the copy_to_user() to copy the counters to user memory may fail after the table has already been exchanged and thus exposed. Return an error at this point will result in freeing the already exposed table. Any subsequent packet processing will result in a kernel panic. We can't copy the counters before exposing the new tables as we want provide the counter state after the old table has been unhooked. Therefore convert this into a silent error. Cc: Florian Westphal <fw@strlen.de> Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/netfilter/arp_tables.c6
-rw-r--r--net/ipv4/netfilter/ip_tables.c6
2 files changed, 8 insertions, 4 deletions
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 59da7cde0724..f95b6f93814b 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -1044,8 +1044,10 @@ static int __do_replace(struct net *net, const char *name,
1044 1044
1045 xt_free_table_info(oldinfo); 1045 xt_free_table_info(oldinfo);
1046 if (copy_to_user(counters_ptr, counters, 1046 if (copy_to_user(counters_ptr, counters,
1047 sizeof(struct xt_counters) * num_counters) != 0) 1047 sizeof(struct xt_counters) * num_counters) != 0) {
1048 ret = -EFAULT; 1048 /* Silent error, can't fail, new table is already in place */
1049 net_warn_ratelimited("arptables: counters copy to user failed while replacing table\n");
1050 }
1049 vfree(counters); 1051 vfree(counters);
1050 xt_table_unlock(t); 1052 xt_table_unlock(t);
1051 return ret; 1053 return ret;
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 718dfbd30cbe..99e810f84671 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1231,8 +1231,10 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
1231 1231
1232 xt_free_table_info(oldinfo); 1232 xt_free_table_info(oldinfo);
1233 if (copy_to_user(counters_ptr, counters, 1233 if (copy_to_user(counters_ptr, counters,
1234 sizeof(struct xt_counters) * num_counters) != 0) 1234 sizeof(struct xt_counters) * num_counters) != 0) {
1235 ret = -EFAULT; 1235 /* Silent error, can't fail, new table is already in place */
1236 net_warn_ratelimited("iptables: counters copy to user failed while replacing table\n");
1237 }
1236 vfree(counters); 1238 vfree(counters);
1237 xt_table_unlock(t); 1239 xt_table_unlock(t);
1238 return ret; 1240 return ret;