Skip to content

Commit

Permalink
appletalk: Fix skb allocation size in loopback case
Browse files Browse the repository at this point in the history
[ 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>
  • Loading branch information
dougg3 authored and gregkh committed Apr 7, 2021
1 parent e10999a commit b978036
Showing 1 changed file with 21 additions and 12 deletions.
33 changes: 21 additions & 12 deletions net/appletalk/ddp.c
Expand Up @@ -1577,8 +1577,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))
Expand Down Expand Up @@ -1641,15 +1641,30 @@ 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);
if (!skb)
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);
Expand Down Expand Up @@ -1700,18 +1715,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);
Expand Down

0 comments on commit b978036

Please sign in to comment.