netfilter: nfnetlink: nfnetlink_unicast() reports EAGAIN instead of ENOBUFS
Frontend callback reports EAGAIN to nfnetlink to retry a command, this
is used to signal that module autoloading is required. Unfortunately,
nlmsg_unicast() reports EAGAIN in case the receiver socket buffer gets
full, so it enters a busy-loop.
This patch updates nfnetlink_unicast() to turn EAGAIN into ENOBUFS and
to use nlmsg_unicast(). Remove the flags field in nfnetlink_unicast()
since this is always MSG_DONTWAIT in the existing code which is exactly
what nlmsg_unicast() passes to netlink_unicast() as parameter.
Fixes: 96518518cc
("netfilter: add nftables")
Reported-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
Родитель
4b7ddc58e6
Коммит
ee92118355
|
@ -43,8 +43,7 @@ int nfnetlink_has_listeners(struct net *net, unsigned int group);
|
|||
int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 portid,
|
||||
unsigned int group, int echo, gfp_t flags);
|
||||
int nfnetlink_set_err(struct net *net, u32 portid, u32 group, int error);
|
||||
int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid,
|
||||
int flags);
|
||||
int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid);
|
||||
|
||||
static inline u16 nfnl_msg_type(u8 subsys, u8 msg_type)
|
||||
{
|
||||
|
|
|
@ -815,11 +815,11 @@ static int nf_tables_gettable(struct net *net, struct sock *nlsk,
|
|||
nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0,
|
||||
family, table);
|
||||
if (err < 0)
|
||||
goto err;
|
||||
goto err_fill_table_info;
|
||||
|
||||
return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
|
||||
return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
|
||||
|
||||
err:
|
||||
err_fill_table_info:
|
||||
kfree_skb(skb2);
|
||||
return err;
|
||||
}
|
||||
|
@ -1563,11 +1563,11 @@ static int nf_tables_getchain(struct net *net, struct sock *nlsk,
|
|||
nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, 0,
|
||||
family, table, chain);
|
||||
if (err < 0)
|
||||
goto err;
|
||||
goto err_fill_chain_info;
|
||||
|
||||
return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
|
||||
return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
|
||||
|
||||
err:
|
||||
err_fill_chain_info:
|
||||
kfree_skb(skb2);
|
||||
return err;
|
||||
}
|
||||
|
@ -3008,11 +3008,11 @@ static int nf_tables_getrule(struct net *net, struct sock *nlsk,
|
|||
nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
|
||||
family, table, chain, rule, NULL);
|
||||
if (err < 0)
|
||||
goto err;
|
||||
goto err_fill_rule_info;
|
||||
|
||||
return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
|
||||
return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
|
||||
|
||||
err:
|
||||
err_fill_rule_info:
|
||||
kfree_skb(skb2);
|
||||
return err;
|
||||
}
|
||||
|
@ -3968,11 +3968,11 @@ static int nf_tables_getset(struct net *net, struct sock *nlsk,
|
|||
|
||||
err = nf_tables_fill_set(skb2, &ctx, set, NFT_MSG_NEWSET, 0);
|
||||
if (err < 0)
|
||||
goto err;
|
||||
goto err_fill_set_info;
|
||||
|
||||
return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
|
||||
return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
|
||||
|
||||
err:
|
||||
err_fill_set_info:
|
||||
kfree_skb(skb2);
|
||||
return err;
|
||||
}
|
||||
|
@ -4860,24 +4860,18 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
|
|||
err = -ENOMEM;
|
||||
skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
|
||||
if (skb == NULL)
|
||||
goto err1;
|
||||
return err;
|
||||
|
||||
err = nf_tables_fill_setelem_info(skb, ctx, ctx->seq, ctx->portid,
|
||||
NFT_MSG_NEWSETELEM, 0, set, &elem);
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
goto err_fill_setelem;
|
||||
|
||||
err = nfnetlink_unicast(skb, ctx->net, ctx->portid, MSG_DONTWAIT);
|
||||
/* This avoids a loop in nfnetlink. */
|
||||
if (err < 0)
|
||||
goto err1;
|
||||
return nfnetlink_unicast(skb, ctx->net, ctx->portid);
|
||||
|
||||
return 0;
|
||||
err2:
|
||||
err_fill_setelem:
|
||||
kfree_skb(skb);
|
||||
err1:
|
||||
/* this avoids a loop in nfnetlink. */
|
||||
return err == -EAGAIN ? -ENOBUFS : err;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* called with rcu_read_lock held */
|
||||
|
@ -6182,10 +6176,11 @@ static int nf_tables_getobj(struct net *net, struct sock *nlsk,
|
|||
nlh->nlmsg_seq, NFT_MSG_NEWOBJ, 0,
|
||||
family, table, obj, reset);
|
||||
if (err < 0)
|
||||
goto err;
|
||||
goto err_fill_obj_info;
|
||||
|
||||
return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
|
||||
err:
|
||||
return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
|
||||
|
||||
err_fill_obj_info:
|
||||
kfree_skb(skb2);
|
||||
return err;
|
||||
}
|
||||
|
@ -7045,10 +7040,11 @@ static int nf_tables_getflowtable(struct net *net, struct sock *nlsk,
|
|||
NFT_MSG_NEWFLOWTABLE, 0, family,
|
||||
flowtable, &flowtable->hook_list);
|
||||
if (err < 0)
|
||||
goto err;
|
||||
goto err_fill_flowtable_info;
|
||||
|
||||
return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
|
||||
err:
|
||||
return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
|
||||
|
||||
err_fill_flowtable_info:
|
||||
kfree_skb(skb2);
|
||||
return err;
|
||||
}
|
||||
|
@ -7234,10 +7230,11 @@ static int nf_tables_getgen(struct net *net, struct sock *nlsk,
|
|||
err = nf_tables_fill_gen_info(skb2, net, NETLINK_CB(skb).portid,
|
||||
nlh->nlmsg_seq);
|
||||
if (err < 0)
|
||||
goto err;
|
||||
goto err_fill_gen_info;
|
||||
|
||||
return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
|
||||
err:
|
||||
return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
|
||||
|
||||
err_fill_gen_info:
|
||||
kfree_skb(skb2);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -149,10 +149,15 @@ int nfnetlink_set_err(struct net *net, u32 portid, u32 group, int error)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(nfnetlink_set_err);
|
||||
|
||||
int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid,
|
||||
int flags)
|
||||
int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid)
|
||||
{
|
||||
return netlink_unicast(net->nfnl, skb, portid, flags);
|
||||
int err;
|
||||
|
||||
err = nlmsg_unicast(net->nfnl, skb, portid);
|
||||
if (err == -EAGAIN)
|
||||
err = -ENOBUFS;
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfnetlink_unicast);
|
||||
|
||||
|
|
|
@ -356,8 +356,7 @@ __nfulnl_send(struct nfulnl_instance *inst)
|
|||
goto out;
|
||||
}
|
||||
}
|
||||
nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid,
|
||||
MSG_DONTWAIT);
|
||||
nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid);
|
||||
out:
|
||||
inst->qlen = 0;
|
||||
inst->skb = NULL;
|
||||
|
|
|
@ -681,7 +681,7 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue,
|
|||
*packet_id_ptr = htonl(entry->id);
|
||||
|
||||
/* nfnetlink_unicast will either free the nskb or add it to a socket */
|
||||
err = nfnetlink_unicast(nskb, net, queue->peer_portid, MSG_DONTWAIT);
|
||||
err = nfnetlink_unicast(nskb, net, queue->peer_portid);
|
||||
if (err < 0) {
|
||||
if (queue->flags & NFQA_CFG_F_FAIL_OPEN) {
|
||||
failopen = 1;
|
||||
|
|
Загрузка…
Ссылка в новой задаче