Skip to content

Commit c805f21

Browse files
dougg3gregkh
authored andcommitted
appletalk: Fix skb allocation size in loopback case
[ Upstream commit 39935dc ] 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>
1 parent f2294a7 commit c805f21

1 file changed

Lines changed: 21 additions & 12 deletions

File tree

net/appletalk/ddp.c

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,8 +1576,8 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
15761576
struct sk_buff *skb;
15771577
struct net_device *dev;
15781578
struct ddpehdr *ddp;
1579-
int size;
1580-
struct atalk_route *rt;
1579+
int size, hard_header_len;
1580+
struct atalk_route *rt, *rt_lo = NULL;
15811581
int err;
15821582

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

1643-
size += dev->hard_header_len;
1643+
hard_header_len = dev->hard_header_len;
1644+
/* Leave room for loopback hardware header if necessary */
1645+
if (usat->sat_addr.s_node == ATADDR_BCAST &&
1646+
(dev->flags & IFF_LOOPBACK || !(rt->flags & RTF_GATEWAY))) {
1647+
struct atalk_addr at_lo;
1648+
1649+
at_lo.s_node = 0;
1650+
at_lo.s_net = 0;
1651+
1652+
rt_lo = atrtr_find(&at_lo);
1653+
1654+
if (rt_lo && rt_lo->dev->hard_header_len > hard_header_len)
1655+
hard_header_len = rt_lo->dev->hard_header_len;
1656+
}
1657+
1658+
size += hard_header_len;
16441659
release_sock(sk);
16451660
skb = sock_alloc_send_skb(sk, size, (flags & MSG_DONTWAIT), &err);
16461661
lock_sock(sk);
16471662
if (!skb)
16481663
goto out;
16491664

16501665
skb_reserve(skb, ddp_dl->header_length);
1651-
skb_reserve(skb, dev->hard_header_len);
1666+
skb_reserve(skb, hard_header_len);
16521667
skb->dev = dev;
16531668

16541669
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)
16991714
/* loop back */
17001715
skb_orphan(skb);
17011716
if (ddp->deh_dnode == ATADDR_BCAST) {
1702-
struct atalk_addr at_lo;
1703-
1704-
at_lo.s_node = 0;
1705-
at_lo.s_net = 0;
1706-
1707-
rt = atrtr_find(&at_lo);
1708-
if (!rt) {
1717+
if (!rt_lo) {
17091718
kfree_skb(skb);
17101719
err = -ENETUNREACH;
17111720
goto out;
17121721
}
1713-
dev = rt->dev;
1722+
dev = rt_lo->dev;
17141723
skb->dev = dev;
17151724
}
17161725
ddp_dl->request(ddp_dl, skb, dev->dev_addr);

0 commit comments

Comments
 (0)