aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-04-14 05:15:45 -0400
committerPatrick McHardy <kaber@trash.net>2008-04-14 05:15:45 -0400
commit544473c1664f3a688be949ac078bdee6f4afeef1 (patch)
tree019b6a5088f8fe99928464d9530268d1de02924a /net/ipv4
parentfa913ddf6372b20b23061996150d38f639488d42 (diff)
[NETFILTER]: {ip,ip6,arp}_tables: return EAGAIN for invalid SO_GET_ENTRIES size
Rule dumping is performed in two steps: first userspace gets the ruleset size using getsockopt(SO_GET_INFO) and allocates memory, then it calls getsockopt(SO_GET_ENTRIES) to actually dump the ruleset. When another process changes the ruleset in between the sizes from the first getsockopt call doesn't match anymore and the kernel aborts. Unfortunately it returns EAGAIN, as for multiple other possible errors, so userspace can't distinguish this case from real errors. Return EAGAIN so userspace can retry the operation. Fixes (with current iptables SVN version) netfilter bugzilla #104. Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/netfilter/arp_tables.c4
-rw-r--r--net/ipv4/netfilter/ip_tables.c4
2 files changed, 4 insertions, 4 deletions
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index d55f3b42eba5..03e83a65aec5 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -937,7 +937,7 @@ static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
937 else { 937 else {
938 duprintf("get_entries: I've got %u not %u!\n", 938 duprintf("get_entries: I've got %u not %u!\n",
939 private->size, get.size); 939 private->size, get.size);
940 ret = -EINVAL; 940 ret = -EAGAIN;
941 } 941 }
942 module_put(t->me); 942 module_put(t->me);
943 xt_table_unlock(t); 943 xt_table_unlock(t);
@@ -1621,7 +1621,7 @@ static int compat_get_entries(struct net *net,
1621 } else if (!ret) { 1621 } else if (!ret) {
1622 duprintf("compat_get_entries: I've got %u not %u!\n", 1622 duprintf("compat_get_entries: I've got %u not %u!\n",
1623 private->size, get.size); 1623 private->size, get.size);
1624 ret = -EINVAL; 1624 ret = -EAGAIN;
1625 } 1625 }
1626 xt_compat_flush_offsets(NF_ARP); 1626 xt_compat_flush_offsets(NF_ARP);
1627 module_put(t->me); 1627 module_put(t->me);
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index aa124b50cb4a..4e7c719445c2 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1180,7 +1180,7 @@ get_entries(struct net *net, struct ipt_get_entries __user *uptr, int *len)
1180 else { 1180 else {
1181 duprintf("get_entries: I've got %u not %u!\n", 1181 duprintf("get_entries: I've got %u not %u!\n",
1182 private->size, get.size); 1182 private->size, get.size);
1183 ret = -EINVAL; 1183 ret = -EAGAIN;
1184 } 1184 }
1185 module_put(t->me); 1185 module_put(t->me);
1186 xt_table_unlock(t); 1186 xt_table_unlock(t);
@@ -1939,7 +1939,7 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr,
1939 } else if (!ret) { 1939 } else if (!ret) {
1940 duprintf("compat_get_entries: I've got %u not %u!\n", 1940 duprintf("compat_get_entries: I've got %u not %u!\n",
1941 private->size, get.size); 1941 private->size, get.size);
1942 ret = -EINVAL; 1942 ret = -EAGAIN;
1943 } 1943 }
1944 xt_compat_flush_offsets(AF_INET); 1944 xt_compat_flush_offsets(AF_INET);
1945 module_put(t->me); 1945 module_put(t->me);