<div dir="ltr"><div dir="ltr"><div>From: Julian Wiedmann <<a href="mailto:jwi@linux.ibm.com">jwi@linux.ibm.com</a>></div><div><br></div><div>BugLink: <a href="http://bugs.launchpad.net/bugs/1800639">http://bugs.launchpad.net/bugs/1800639</a></div><div><br></div><div>    net/af_iucv: fix skb handling on HiperTransport xmit error</div><div>    </div><div>    When sending an skb, afiucv_hs_send() bails out on various error</div><div>    conditions. But currently the caller has no way of telling whether the</div><div>    skb was freed or not - resulting in potentially either</div><div>    a) leaked skbs from iucv_send_ctrl(), or</div><div>    b) double-free's from iucv_sock_sendmsg().</div><div>    </div><div>    As dev_queue_xmit() will always consume the skb (even on error), be</div><div>    consistent and also free the skb from all other error paths. This way</div><div>    callers no longer need to care about managing the skb.</div><div>    </div><div>    Signed-off-by: Julian Wiedmann <<a href="mailto:jwi@linux.ibm.com">jwi@linux.ibm.com</a>></div><div>    Reviewed-by: Ursula Braun <<a href="mailto:ubraun@linux.ibm.com">ubraun@linux.ibm.com</a>></div><div>    Signed-off-by: David S. Miller <<a href="mailto:davem@davemloft.net">davem@davemloft.net</a>></div><div><br></div><div>---</div><div><br></div><div>diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c</div><div>index 01000c1..e2f16a0 100644</div><div>--- a/net/iucv/af_iucv.c</div><div>+++ b/net/iucv/af_iucv.c</div><div>@@ -351,20 +351,28 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock,</div><div>                memcpy(&phs_hdr->iucv_hdr, imsg, sizeof(struct iucv_message));</div><div> </div><div>        skb->dev = iucv->hs_dev;</div><div>-       if (!skb->dev)</div><div>-               return -ENODEV;</div><div>-       if (!(skb->dev->flags & IFF_UP) || !netif_carrier_ok(skb->dev))</div><div>-               return -ENETDOWN;</div><div>+       if (!skb->dev) {</div><div>+               err = -ENODEV;</div><div>+               goto err_free;</div><div>+       }</div><div>+       if (!(skb->dev->flags & IFF_UP) || !netif_carrier_ok(skb->dev)) {</div><div>+               err = -ENETDOWN;</div><div>+               goto err_free;</div><div>+       }</div><div>        if (skb->len > skb->dev->mtu) {</div><div>-               if (sock->sk_type == SOCK_SEQPACKET)</div><div>-                       return -EMSGSIZE;</div><div>-               else</div><div>-                       skb_trim(skb, skb->dev->mtu);</div><div>+               if (sock->sk_type == SOCK_SEQPACKET) {</div><div>+                       err = -EMSGSIZE;</div><div>+                       goto err_free;</div><div>+               }</div><div>+               skb_trim(skb, skb->dev->mtu);</div><div>        }</div><div>        skb->protocol = cpu_to_be16(ETH_P_AF_IUCV);</div><div>        nskb = skb_clone(skb, GFP_ATOMIC);</div><div>-       if (!nskb)</div><div>-               return -ENOMEM;</div><div>+       if (!nskb) {</div><div>+               err = -ENOMEM;</div><div>+               goto err_free;</div><div>+       }</div><div>+</div><div>        skb_queue_tail(&iucv->send_skb_q, nskb);</div><div>        err = dev_queue_xmit(skb);</div><div>        if (net_xmit_eval(err)) {</div><div>@@ -375,6 +383,10 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock,</div><div>                WARN_ON(atomic_read(&iucv->msg_recv) < 0);</div><div>        }</div><div>        return net_xmit_eval(err);</div><div>+</div><div>+err_free:</div><div>+       kfree_skb(skb);</div><div>+       return err;</div><div> }</div><div> </div><div> static struct sock *__iucv_get_sock_by_name(char *nm)</div><div>@@ -1167,7 +1179,7 @@ static int iucv_sock_sendmsg(struct socket *sock, struct msghdr *msg,</div><div>                err = afiucv_hs_send(&txmsg, sk, skb, 0);</div><div>                if (err) {</div><div>                        atomic_dec(&iucv->msg_sent);</div><div>-                       goto fail;</div><div>+                       goto out;</div><div>                }</div><div>        } else { /* Classic VM IUCV transport */</div><div>                skb_queue_tail(&iucv->send_skb_q, skb);</div></div></div>