[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>
This commit is contained in:
parent
fa913ddf63
commit
544473c166
@ -937,7 +937,7 @@ static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
|
||||
else {
|
||||
duprintf("get_entries: I've got %u not %u!\n",
|
||||
private->size, get.size);
|
||||
ret = -EINVAL;
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
module_put(t->me);
|
||||
xt_table_unlock(t);
|
||||
@ -1621,7 +1621,7 @@ static int compat_get_entries(struct net *net,
|
||||
} else if (!ret) {
|
||||
duprintf("compat_get_entries: I've got %u not %u!\n",
|
||||
private->size, get.size);
|
||||
ret = -EINVAL;
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
xt_compat_flush_offsets(NF_ARP);
|
||||
module_put(t->me);
|
||||
|
@ -1180,7 +1180,7 @@ get_entries(struct net *net, struct ipt_get_entries __user *uptr, int *len)
|
||||
else {
|
||||
duprintf("get_entries: I've got %u not %u!\n",
|
||||
private->size, get.size);
|
||||
ret = -EINVAL;
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
module_put(t->me);
|
||||
xt_table_unlock(t);
|
||||
@ -1939,7 +1939,7 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr,
|
||||
} else if (!ret) {
|
||||
duprintf("compat_get_entries: I've got %u not %u!\n",
|
||||
private->size, get.size);
|
||||
ret = -EINVAL;
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
xt_compat_flush_offsets(AF_INET);
|
||||
module_put(t->me);
|
||||
|
@ -1206,7 +1206,7 @@ get_entries(struct net *net, struct ip6t_get_entries __user *uptr, int *len)
|
||||
else {
|
||||
duprintf("get_entries: I've got %u not %u!\n",
|
||||
private->size, get.size);
|
||||
ret = -EINVAL;
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
module_put(t->me);
|
||||
xt_table_unlock(t);
|
||||
@ -1966,7 +1966,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
|
||||
} else if (!ret) {
|
||||
duprintf("compat_get_entries: I've got %u not %u!\n",
|
||||
private->size, get.size);
|
||||
ret = -EINVAL;
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
xt_compat_flush_offsets(AF_INET6);
|
||||
module_put(t->me);
|
||||
|
Loading…
Reference in New Issue
Block a user