Commit ffcfb8db authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo Committed by David S. Miller

Subject: [PATCH] appletalk: Fix skb leak when ipddp interface is not loaded

And also do a better job of returning proper NET_{RX,XMIT}_ values.

Based on a patch and suggestions by Mark Smith.

This fixes CVE-2009-2903
Reported-by: default avatarMark Smith <lk-netdev@lk-netdev.nosense.org>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8ba69ba6
...@@ -177,8 +177,7 @@ static netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -177,8 +177,7 @@ static netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_packets++; dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len; dev->stats.tx_bytes += skb->len;
if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) aarp_send_ddp(rt->dev, skb, &rt->at, NULL);
dev_kfree_skb(skb);
spin_unlock(&ipddp_route_lock); spin_unlock(&ipddp_route_lock);
......
...@@ -599,7 +599,7 @@ int aarp_send_ddp(struct net_device *dev, struct sk_buff *skb, ...@@ -599,7 +599,7 @@ int aarp_send_ddp(struct net_device *dev, struct sk_buff *skb,
/* Non ELAP we cannot do. */ /* Non ELAP we cannot do. */
if (dev->type != ARPHRD_ETHER) if (dev->type != ARPHRD_ETHER)
return -1; goto free_it;
skb->dev = dev; skb->dev = dev;
skb->protocol = htons(ETH_P_ATALK); skb->protocol = htons(ETH_P_ATALK);
...@@ -634,7 +634,7 @@ int aarp_send_ddp(struct net_device *dev, struct sk_buff *skb, ...@@ -634,7 +634,7 @@ int aarp_send_ddp(struct net_device *dev, struct sk_buff *skb,
if (!a) { if (!a) {
/* Whoops slipped... good job it's an unreliable protocol 8) */ /* Whoops slipped... good job it's an unreliable protocol 8) */
write_unlock_bh(&aarp_lock); write_unlock_bh(&aarp_lock);
return -1; goto free_it;
} }
/* Set up the queue */ /* Set up the queue */
...@@ -663,15 +663,21 @@ out_unlock: ...@@ -663,15 +663,21 @@ out_unlock:
write_unlock_bh(&aarp_lock); write_unlock_bh(&aarp_lock);
/* Tell the ddp layer we have taken over for this frame. */ /* Tell the ddp layer we have taken over for this frame. */
return 0; goto sent;
sendit: sendit:
if (skb->sk) if (skb->sk)
skb->priority = skb->sk->sk_priority; skb->priority = skb->sk->sk_priority;
dev_queue_xmit(skb); if (dev_queue_xmit(skb))
goto drop;
sent: sent:
return 1; return NET_XMIT_SUCCESS;
free_it:
kfree_skb(skb);
drop:
return NET_XMIT_DROP;
} }
EXPORT_SYMBOL(aarp_send_ddp);
/* /*
* An entry in the aarp unresolved queue has become resolved. Send * An entry in the aarp unresolved queue has become resolved. Send
......
...@@ -1270,8 +1270,10 @@ static int handle_ip_over_ddp(struct sk_buff *skb) ...@@ -1270,8 +1270,10 @@ static int handle_ip_over_ddp(struct sk_buff *skb)
struct net_device_stats *stats; struct net_device_stats *stats;
/* This needs to be able to handle ipddp"N" devices */ /* This needs to be able to handle ipddp"N" devices */
if (!dev) if (!dev) {
return -ENODEV; kfree_skb(skb);
return NET_RX_DROP;
}
skb->protocol = htons(ETH_P_IP); skb->protocol = htons(ETH_P_IP);
skb_pull(skb, 13); skb_pull(skb, 13);
...@@ -1281,8 +1283,7 @@ static int handle_ip_over_ddp(struct sk_buff *skb) ...@@ -1281,8 +1283,7 @@ static int handle_ip_over_ddp(struct sk_buff *skb)
stats = netdev_priv(dev); stats = netdev_priv(dev);
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += skb->len + 13; stats->rx_bytes += skb->len + 13;
netif_rx(skb); /* Send the SKB up to a higher place. */ return netif_rx(skb); /* Send the SKB up to a higher place. */
return 0;
} }
#else #else
/* make it easy for gcc to optimize this test out, i.e. kill the code */ /* make it easy for gcc to optimize this test out, i.e. kill the code */
...@@ -1290,9 +1291,8 @@ static int handle_ip_over_ddp(struct sk_buff *skb) ...@@ -1290,9 +1291,8 @@ static int handle_ip_over_ddp(struct sk_buff *skb)
#define handle_ip_over_ddp(skb) 0 #define handle_ip_over_ddp(skb) 0
#endif #endif
static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev, static int atalk_route_packet(struct sk_buff *skb, struct net_device *dev,
struct ddpehdr *ddp, __u16 len_hops, struct ddpehdr *ddp, __u16 len_hops, int origlen)
int origlen)
{ {
struct atalk_route *rt; struct atalk_route *rt;
struct atalk_addr ta; struct atalk_addr ta;
...@@ -1359,8 +1359,6 @@ static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev, ...@@ -1359,8 +1359,6 @@ static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev,
/* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */ /* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */
struct sk_buff *nskb = skb_realloc_headroom(skb, 32); struct sk_buff *nskb = skb_realloc_headroom(skb, 32);
kfree_skb(skb); kfree_skb(skb);
if (!nskb)
goto out;
skb = nskb; skb = nskb;
} else } else
skb = skb_unshare(skb, GFP_ATOMIC); skb = skb_unshare(skb, GFP_ATOMIC);
...@@ -1369,12 +1367,16 @@ static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev, ...@@ -1369,12 +1367,16 @@ static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev,
* If the buffer didn't vanish into the lack of space bitbucket we can * If the buffer didn't vanish into the lack of space bitbucket we can
* send it. * send it.
*/ */
if (skb && aarp_send_ddp(rt->dev, skb, &ta, NULL) == -1) if (skb == NULL)
goto free_it; goto drop;
out:
return; if (aarp_send_ddp(rt->dev, skb, &ta, NULL) == NET_XMIT_DROP)
return NET_RX_DROP;
return NET_XMIT_SUCCESS;
free_it: free_it:
kfree_skb(skb); kfree_skb(skb);
drop:
return NET_RX_DROP;
} }
/** /**
...@@ -1448,8 +1450,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -1448,8 +1450,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
/* Not ours, so we route the packet via the correct /* Not ours, so we route the packet via the correct
* AppleTalk iface * AppleTalk iface
*/ */
atalk_route_packet(skb, dev, ddp, len_hops, origlen); return atalk_route_packet(skb, dev, ddp, len_hops, origlen);
return NET_RX_SUCCESS;
} }
/* if IP over DDP is not selected this code will be optimized out */ /* if IP over DDP is not selected this code will be optimized out */
...@@ -1655,10 +1656,10 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr ...@@ -1655,10 +1656,10 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
if (skb2) { if (skb2) {
loopback = 1; loopback = 1;
SOCK_DEBUG(sk, "SK %p: send out(copy).\n", sk); SOCK_DEBUG(sk, "SK %p: send out(copy).\n", sk);
if (aarp_send_ddp(dev, skb2, /*
&usat->sat_addr, NULL) == -1) * If it fails it is queued/sent above in the aarp queue
kfree_skb(skb2); */
/* else queued/sent above in the aarp queue */ aarp_send_ddp(dev, skb2, &usat->sat_addr, NULL);
} }
} }
...@@ -1688,9 +1689,10 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr ...@@ -1688,9 +1689,10 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
usat = &gsat; usat = &gsat;
} }
if (aarp_send_ddp(dev, skb, &usat->sat_addr, NULL) == -1) /*
kfree_skb(skb); * If it fails it is queued/sent above in the aarp queue
/* else queued/sent above in the aarp queue */ */
aarp_send_ddp(dev, skb, &usat->sat_addr, NULL);
} }
SOCK_DEBUG(sk, "SK %p: Done write (%Zd).\n", sk, len); SOCK_DEBUG(sk, "SK %p: Done write (%Zd).\n", sk, len);
...@@ -1868,7 +1870,6 @@ static struct packet_type ppptalk_packet_type __read_mostly = { ...@@ -1868,7 +1870,6 @@ static struct packet_type ppptalk_packet_type __read_mostly = {
static unsigned char ddp_snap_id[] = { 0x08, 0x00, 0x07, 0x80, 0x9B }; static unsigned char ddp_snap_id[] = { 0x08, 0x00, 0x07, 0x80, 0x9B };
/* Export symbols for use by drivers when AppleTalk is a module */ /* Export symbols for use by drivers when AppleTalk is a module */
EXPORT_SYMBOL(aarp_send_ddp);
EXPORT_SYMBOL(atrtr_get_dev); EXPORT_SYMBOL(atrtr_get_dev);
EXPORT_SYMBOL(atalk_find_dev_addr); EXPORT_SYMBOL(atalk_find_dev_addr);
......
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