Commit d1729226 authored by Julian Wiedmann's avatar Julian Wiedmann Committed by Khalid Elmously

net/af_iucv: fix skb handling on HiperTransport xmit error

BugLink: http://bugs.launchpad.net/bugs/1800639

When sending an skb, afiucv_hs_send() bails out on various error
conditions. But currently the caller has no way of telling whether the
skb was freed or not - resulting in potentially either
a) leaked skbs from iucv_send_ctrl(), or
b) double-free's from iucv_sock_sendmsg().

As dev_queue_xmit() will always consume the skb (even on error), be
consistent and also free the skb from all other error paths. This way
callers no longer need to care about managing the skb.
Signed-off-by: default avatarJulian Wiedmann <jwi@linux.ibm.com>
Reviewed-by: default avatarUrsula Braun <ubraun@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
(cherry-picked from commit b2f54394)
Signed-off-by: default avatarFrank Heimes <frank.heimes@canonical.com>
Acked-by: default avatarStefan Bader <stefan.bader@canonical.com>
Acked-by: default avatarColin Ian King <colin.king@canonical.com>
Signed-off-by: default avatarKhalid Elmously <khalid.elmously@canonical.com>
parent c56b7d6c
...@@ -352,20 +352,28 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock, ...@@ -352,20 +352,28 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock,
memcpy(&phs_hdr->iucv_hdr, imsg, sizeof(struct iucv_message)); memcpy(&phs_hdr->iucv_hdr, imsg, sizeof(struct iucv_message));
skb->dev = iucv->hs_dev; skb->dev = iucv->hs_dev;
if (!skb->dev) if (!skb->dev) {
return -ENODEV; err = -ENODEV;
if (!(skb->dev->flags & IFF_UP) || !netif_carrier_ok(skb->dev)) goto err_free;
return -ENETDOWN; }
if (!(skb->dev->flags & IFF_UP) || !netif_carrier_ok(skb->dev)) {
err = -ENETDOWN;
goto err_free;
}
if (skb->len > skb->dev->mtu) { if (skb->len > skb->dev->mtu) {
if (sock->sk_type == SOCK_SEQPACKET) if (sock->sk_type == SOCK_SEQPACKET) {
return -EMSGSIZE; err = -EMSGSIZE;
else goto err_free;
}
skb_trim(skb, skb->dev->mtu); skb_trim(skb, skb->dev->mtu);
} }
skb->protocol = ETH_P_AF_IUCV; skb->protocol = ETH_P_AF_IUCV;
nskb = skb_clone(skb, GFP_ATOMIC); nskb = skb_clone(skb, GFP_ATOMIC);
if (!nskb) if (!nskb) {
return -ENOMEM; err = -ENOMEM;
goto err_free;
}
skb_queue_tail(&iucv->send_skb_q, nskb); skb_queue_tail(&iucv->send_skb_q, nskb);
err = dev_queue_xmit(skb); err = dev_queue_xmit(skb);
if (net_xmit_eval(err)) { if (net_xmit_eval(err)) {
...@@ -376,6 +384,10 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock, ...@@ -376,6 +384,10 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock,
WARN_ON(atomic_read(&iucv->msg_recv) < 0); WARN_ON(atomic_read(&iucv->msg_recv) < 0);
} }
return net_xmit_eval(err); return net_xmit_eval(err);
err_free:
kfree_skb(skb);
return err;
} }
static struct sock *__iucv_get_sock_by_name(char *nm) static struct sock *__iucv_get_sock_by_name(char *nm)
...@@ -1146,7 +1158,7 @@ static int iucv_sock_sendmsg(struct socket *sock, struct msghdr *msg, ...@@ -1146,7 +1158,7 @@ static int iucv_sock_sendmsg(struct socket *sock, struct msghdr *msg,
err = afiucv_hs_send(&txmsg, sk, skb, 0); err = afiucv_hs_send(&txmsg, sk, skb, 0);
if (err) { if (err) {
atomic_dec(&iucv->msg_sent); atomic_dec(&iucv->msg_sent);
goto fail; goto out;
} }
goto release; goto release;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment