lkml.org 
[lkml]   [2021]   [Apr]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.10 049/126] appletalk: Fix skb allocation size in loopback case
    Date
    From: Doug Brown <doug@schmorgal.com>

    [ Upstream commit 39935dccb21c60f9bbf1bb72d22ab6fd14ae7705 ]

    If a DDP broadcast packet is sent out to a non-gateway target, it is
    also looped back. There is a potential for the loopback device to have a
    longer hardware header length than the original target route's device,
    which can result in the skb not being created with enough room for the
    loopback device's hardware header. This patch fixes the issue by
    determining that a loopback will be necessary prior to allocating the
    skb, and if so, ensuring the skb has enough room.

    This was discovered while testing a new driver that creates a LocalTalk
    network interface (LTALK_HLEN = 1). It caused an skb_under_panic.

    Signed-off-by: Doug Brown <doug@schmorgal.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    net/appletalk/ddp.c | 33 +++++++++++++++++++++------------
    1 file changed, 21 insertions(+), 12 deletions(-)

    diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
    index 1d48708c5a2e..c94b212d8e7c 100644
    --- a/net/appletalk/ddp.c
    +++ b/net/appletalk/ddp.c
    @@ -1576,8 +1576,8 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
    struct sk_buff *skb;
    struct net_device *dev;
    struct ddpehdr *ddp;
    - int size;
    - struct atalk_route *rt;
    + int size, hard_header_len;
    + struct atalk_route *rt, *rt_lo = NULL;
    int err;

    if (flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
    @@ -1640,7 +1640,22 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
    SOCK_DEBUG(sk, "SK %p: Size needed %d, device %s\n",
    sk, size, dev->name);

    - size += dev->hard_header_len;
    + hard_header_len = dev->hard_header_len;
    + /* Leave room for loopback hardware header if necessary */
    + if (usat->sat_addr.s_node == ATADDR_BCAST &&
    + (dev->flags & IFF_LOOPBACK || !(rt->flags & RTF_GATEWAY))) {
    + struct atalk_addr at_lo;
    +
    + at_lo.s_node = 0;
    + at_lo.s_net = 0;
    +
    + rt_lo = atrtr_find(&at_lo);
    +
    + if (rt_lo && rt_lo->dev->hard_header_len > hard_header_len)
    + hard_header_len = rt_lo->dev->hard_header_len;
    + }
    +
    + size += hard_header_len;
    release_sock(sk);
    skb = sock_alloc_send_skb(sk, size, (flags & MSG_DONTWAIT), &err);
    lock_sock(sk);
    @@ -1648,7 +1663,7 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
    goto out;

    skb_reserve(skb, ddp_dl->header_length);
    - skb_reserve(skb, dev->hard_header_len);
    + skb_reserve(skb, hard_header_len);
    skb->dev = dev;

    SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk);
    @@ -1699,18 +1714,12 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
    /* loop back */
    skb_orphan(skb);
    if (ddp->deh_dnode == ATADDR_BCAST) {
    - struct atalk_addr at_lo;
    -
    - at_lo.s_node = 0;
    - at_lo.s_net = 0;
    -
    - rt = atrtr_find(&at_lo);
    - if (!rt) {
    + if (!rt_lo) {
    kfree_skb(skb);
    err = -ENETUNREACH;
    goto out;
    }
    - dev = rt->dev;
    + dev = rt_lo->dev;
    skb->dev = dev;
    }
    ddp_dl->request(ddp_dl, skb, dev->dev_addr);
    --
    2.30.1


    \
     
     \ /
      Last update: 2021-04-05 11:41    [W:4.329 / U:0.840 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site