提交 544473c1 编写于 作者: P Patrick McHardy

[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: NPatrick McHardy <kaber@trash.net>
上级 fa913ddf
...@@ -937,7 +937,7 @@ static int get_entries(struct net *net, struct arpt_get_entries __user *uptr, ...@@ -937,7 +937,7 @@ static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
else { else {
duprintf("get_entries: I've got %u not %u!\n", duprintf("get_entries: I've got %u not %u!\n",
private->size, get.size); private->size, get.size);
ret = -EINVAL; ret = -EAGAIN;
} }
module_put(t->me); module_put(t->me);
xt_table_unlock(t); xt_table_unlock(t);
...@@ -1621,7 +1621,7 @@ static int compat_get_entries(struct net *net, ...@@ -1621,7 +1621,7 @@ static int compat_get_entries(struct net *net,
} else if (!ret) { } else if (!ret) {
duprintf("compat_get_entries: I've got %u not %u!\n", duprintf("compat_get_entries: I've got %u not %u!\n",
private->size, get.size); private->size, get.size);
ret = -EINVAL; ret = -EAGAIN;
} }
xt_compat_flush_offsets(NF_ARP); xt_compat_flush_offsets(NF_ARP);
module_put(t->me); module_put(t->me);
......
...@@ -1180,7 +1180,7 @@ get_entries(struct net *net, struct ipt_get_entries __user *uptr, int *len) ...@@ -1180,7 +1180,7 @@ get_entries(struct net *net, struct ipt_get_entries __user *uptr, int *len)
else { else {
duprintf("get_entries: I've got %u not %u!\n", duprintf("get_entries: I've got %u not %u!\n",
private->size, get.size); private->size, get.size);
ret = -EINVAL; ret = -EAGAIN;
} }
module_put(t->me); module_put(t->me);
xt_table_unlock(t); xt_table_unlock(t);
...@@ -1939,7 +1939,7 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr, ...@@ -1939,7 +1939,7 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr,
} else if (!ret) { } else if (!ret) {
duprintf("compat_get_entries: I've got %u not %u!\n", duprintf("compat_get_entries: I've got %u not %u!\n",
private->size, get.size); private->size, get.size);
ret = -EINVAL; ret = -EAGAIN;
} }
xt_compat_flush_offsets(AF_INET); xt_compat_flush_offsets(AF_INET);
module_put(t->me); module_put(t->me);
......
...@@ -1206,7 +1206,7 @@ get_entries(struct net *net, struct ip6t_get_entries __user *uptr, int *len) ...@@ -1206,7 +1206,7 @@ get_entries(struct net *net, struct ip6t_get_entries __user *uptr, int *len)
else { else {
duprintf("get_entries: I've got %u not %u!\n", duprintf("get_entries: I've got %u not %u!\n",
private->size, get.size); private->size, get.size);
ret = -EINVAL; ret = -EAGAIN;
} }
module_put(t->me); module_put(t->me);
xt_table_unlock(t); xt_table_unlock(t);
...@@ -1966,7 +1966,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr, ...@@ -1966,7 +1966,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
} else if (!ret) { } else if (!ret) {
duprintf("compat_get_entries: I've got %u not %u!\n", duprintf("compat_get_entries: I've got %u not %u!\n",
private->size, get.size); private->size, get.size);
ret = -EINVAL; ret = -EAGAIN;
} }
xt_compat_flush_offsets(AF_INET6); xt_compat_flush_offsets(AF_INET6);
module_put(t->me); module_put(t->me);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册