aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Chapman <jchapman@katalix.com>2008-12-17 07:02:16 -0500
committerDavid S. Miller <davem@davemloft.net>2008-12-18 22:41:42 -0500
commit739840d529eb7505d3cbfe9d468bf1440c9a8e27 (patch)
tree432ffe292f8886a63f1328e6e2466c01dbe452d5
parent1b08534e562dae7b084326f8aa8cc12a4c1b6593 (diff)
ppp: fix segfaults introduced by netdev_priv changes
This patch fixes a segfault in ppp_shutdown_interface() and ppp_destroy_interface() when a PPP connection is closed. I bisected the problem to the following commit: commit c8019bf3aff653cceb64f66489fc299ee5957b57 Author: Wang Chen <wangchen@cn.fujitsu.com> Date: Thu Nov 20 04:24:17 2008 -0800 netdevice ppp: Convert directly reference of netdev->priv 1. Use netdev_priv(dev) to replace dev->priv. 2. Alloc netdev's private data by alloc_netdev(). Signed-off-by: Wang Chen <wangchen@cn.fujitsu.com> Signed-off-by: David S. Miller <davem@davemloft.net> The original ppp_generic code treated the netdev and struct ppp as independent data structures which were freed separately. In moving the ppp struct into the netdev, it is now possible for the private data to be freed before the call to ppp_shutdown_interface(), which is bad. The kfree(ppp) in ppp_destroy_interface() is also wrong; presumably ppp hasn't worked since the above commit. The following patch fixes both problems. Signed-off-by: James Chapman <jchapman@katalix.com> Reviewed-by: Wang Chen <wangchen@cn.fujitsu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ppp_generic.c28
1 files changed, 13 insertions, 15 deletions
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 7e857e938adb..714a23035de1 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -116,6 +116,7 @@ struct ppp {
116 unsigned long last_xmit; /* jiffies when last pkt sent 9c */ 116 unsigned long last_xmit; /* jiffies when last pkt sent 9c */
117 unsigned long last_recv; /* jiffies when last pkt rcvd a0 */ 117 unsigned long last_recv; /* jiffies when last pkt rcvd a0 */
118 struct net_device *dev; /* network interface device a4 */ 118 struct net_device *dev; /* network interface device a4 */
119 int closing; /* is device closing down? a8 */
119#ifdef CONFIG_PPP_MULTILINK 120#ifdef CONFIG_PPP_MULTILINK
120 int nxchan; /* next channel to send something on */ 121 int nxchan; /* next channel to send something on */
121 u32 nxseq; /* next sequence number to send */ 122 u32 nxseq; /* next sequence number to send */
@@ -995,7 +996,7 @@ ppp_xmit_process(struct ppp *ppp)
995 struct sk_buff *skb; 996 struct sk_buff *skb;
996 997
997 ppp_xmit_lock(ppp); 998 ppp_xmit_lock(ppp);
998 if (ppp->dev) { 999 if (!ppp->closing) {
999 ppp_push(ppp); 1000 ppp_push(ppp);
1000 while (!ppp->xmit_pending 1001 while (!ppp->xmit_pending
1001 && (skb = skb_dequeue(&ppp->file.xq))) 1002 && (skb = skb_dequeue(&ppp->file.xq)))
@@ -1463,8 +1464,7 @@ static inline void
1463ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) 1464ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
1464{ 1465{
1465 ppp_recv_lock(ppp); 1466 ppp_recv_lock(ppp);
1466 /* ppp->dev == 0 means interface is closing down */ 1467 if (!ppp->closing)
1467 if (ppp->dev)
1468 ppp_receive_frame(ppp, skb, pch); 1468 ppp_receive_frame(ppp, skb, pch);
1469 else 1469 else
1470 kfree_skb(skb); 1470 kfree_skb(skb);
@@ -2498,18 +2498,16 @@ init_ppp_file(struct ppp_file *pf, int kind)
2498 */ 2498 */
2499static void ppp_shutdown_interface(struct ppp *ppp) 2499static void ppp_shutdown_interface(struct ppp *ppp)
2500{ 2500{
2501 struct net_device *dev;
2502
2503 mutex_lock(&all_ppp_mutex); 2501 mutex_lock(&all_ppp_mutex);
2504 ppp_lock(ppp);
2505 dev = ppp->dev;
2506 ppp->dev = NULL;
2507 ppp_unlock(ppp);
2508 /* This will call dev_close() for us. */ 2502 /* This will call dev_close() for us. */
2509 if (dev) { 2503 ppp_lock(ppp);
2510 unregister_netdev(dev); 2504 if (!ppp->closing) {
2511 free_netdev(dev); 2505 ppp->closing = 1;
2512 } 2506 ppp_unlock(ppp);
2507 unregister_netdev(ppp->dev);
2508 } else
2509 ppp_unlock(ppp);
2510
2513 cardmap_set(&all_ppp_units, ppp->file.index, NULL); 2511 cardmap_set(&all_ppp_units, ppp->file.index, NULL);
2514 ppp->file.dead = 1; 2512 ppp->file.dead = 1;
2515 ppp->owner = NULL; 2513 ppp->owner = NULL;
@@ -2554,7 +2552,7 @@ static void ppp_destroy_interface(struct ppp *ppp)
2554 if (ppp->xmit_pending) 2552 if (ppp->xmit_pending)
2555 kfree_skb(ppp->xmit_pending); 2553 kfree_skb(ppp->xmit_pending);
2556 2554
2557 kfree(ppp); 2555 free_netdev(ppp->dev);
2558} 2556}
2559 2557
2560/* 2558/*
@@ -2616,7 +2614,7 @@ ppp_connect_channel(struct channel *pch, int unit)
2616 if (pch->file.hdrlen > ppp->file.hdrlen) 2614 if (pch->file.hdrlen > ppp->file.hdrlen)
2617 ppp->file.hdrlen = pch->file.hdrlen; 2615 ppp->file.hdrlen = pch->file.hdrlen;
2618 hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */ 2616 hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */
2619 if (ppp->dev && hdrlen > ppp->dev->hard_header_len) 2617 if (hdrlen > ppp->dev->hard_header_len)
2620 ppp->dev->hard_header_len = hdrlen; 2618 ppp->dev->hard_header_len = hdrlen;
2621 list_add_tail(&pch->clist, &ppp->channels); 2619 list_add_tail(&pch->clist, &ppp->channels);
2622 ++ppp->n_channels; 2620 ++ppp->n_channels;