mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
xfrm: propagate -EINPROGRESS from validate_xmit_xfrm()
validate_xmit_xfrm() returns NULL both when a packet is dropped and when it is stolen by async crypto (-EINPROGRESS from ->xmit()). Callers cannot distinguish the two cases.f53c723902("net: Add asynchronous callbacks for xfrm on layer 2.") changed the semantics of a NULL return from "dropped" to "stolen or dropped", but __dev_queue_xmit() was not updated. On virtual/bridge interfaces (noqueue qdisc) __dev_queue_xmit() initialises rc=-ENOMEM and jumps to out: when skb is NULL, returning -ENOMEM to the caller even though the packet will be delivered correctly via xfrm_dev_resume(). Return ERR_PTR(-EINPROGRESS) from validate_xmit_xfrm() for the async case so callers can tell it apart from a real drop. Update __dev_queue_xmit() to handle ERR_PTR(-EINPROGRESS) from validate_xmit_skb() correctly. Update validate_xmit_skb_list() to use IS_ERR_OR_NULL() so that ERR_PTR(-EINPROGRESS) is not mistakenly added to the transmitted list. Fixes:f53c723902("net: Add asynchronous callbacks for xfrm on layer 2.") Suggested-by: Sabrina Dubroca <sd@queasysnail.net> Signed-off-by: Petr Wozniak <petr.wozniak@gmail.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
This commit is contained in:
committed by
Steffen Klassert
parent
805185b7c7
commit
6860b467f5
@@ -4018,6 +4018,9 @@ static struct sk_buff *validate_xmit_unreadable_skb(struct sk_buff *skb,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Returns the skb on success, NULL if dropped, or ERR_PTR(-EINPROGRESS)
|
||||
* if stolen by async xfrm crypto (delivered via xfrm_dev_resume()).
|
||||
*/
|
||||
static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev, bool *again)
|
||||
{
|
||||
netdev_features_t features;
|
||||
@@ -4089,7 +4092,7 @@ struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *d
|
||||
skb->prev = skb;
|
||||
|
||||
skb = validate_xmit_skb(skb, dev, again);
|
||||
if (!skb)
|
||||
if (IS_ERR_OR_NULL(skb))
|
||||
continue;
|
||||
|
||||
if (!head)
|
||||
@@ -4860,8 +4863,11 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
|
||||
goto recursion_alert;
|
||||
|
||||
skb = validate_xmit_skb(skb, dev, &again);
|
||||
if (!skb)
|
||||
if (IS_ERR_OR_NULL(skb)) {
|
||||
if (PTR_ERR(skb) == -EINPROGRESS)
|
||||
rc = NET_XMIT_SUCCESS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
HARD_TX_LOCK(dev, txq, cpu);
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
|
||||
err = x->type_offload->xmit(x, skb, esp_features);
|
||||
if (err) {
|
||||
if (err == -EINPROGRESS)
|
||||
return NULL;
|
||||
return ERR_PTR(-EINPROGRESS);
|
||||
|
||||
XFRM_INC_STATS(xs_net(x), LINUX_MIB_XFRMOUTSTATEPROTOERROR);
|
||||
kfree_skb(skb);
|
||||
@@ -224,7 +224,7 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
|
||||
pskb = skb2;
|
||||
}
|
||||
|
||||
return skb;
|
||||
return skb ? skb : ERR_PTR(-EINPROGRESS);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(validate_xmit_xfrm);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user