diff options
| author | Girish Moodalbail <girish.moodalbail@oracle.com> | 2017-10-25 03:23:04 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2017-10-26 04:57:39 -0400 |
| commit | 78e0ea6791d7baafb8a0ca82b1bd0c7b3453c919 (patch) | |
| tree | 6be52d342cd4ea32359a90ec7aabc96d9b08dd40 | |
| parent | 5889e2c0e441d84060e66211ed5c4517ca591167 (diff) | |
tap: double-free in error path in tap_open()
Double free of skb_array in tap module is causing kernel panic. When
tap_set_queue() fails we free skb_array right away by calling
skb_array_cleanup(). However, later on skb_array_cleanup() is called
again by tap_sock_destruct through sock_put(). This patch fixes that
issue.
Fixes: 362899b8725b35e3 (macvtap: switch to use skb array)
Signed-off-by: Girish Moodalbail <girish.moodalbail@oracle.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/tap.c | 18 |
1 files changed, 9 insertions, 9 deletions
diff --git a/drivers/net/tap.c b/drivers/net/tap.c index 21b71ae947fd..98ee6cc2875d 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c | |||
| @@ -517,6 +517,10 @@ static int tap_open(struct inode *inode, struct file *file) | |||
| 517 | &tap_proto, 0); | 517 | &tap_proto, 0); |
| 518 | if (!q) | 518 | if (!q) |
| 519 | goto err; | 519 | goto err; |
| 520 | if (skb_array_init(&q->skb_array, tap->dev->tx_queue_len, GFP_KERNEL)) { | ||
| 521 | sk_free(&q->sk); | ||
| 522 | goto err; | ||
| 523 | } | ||
| 520 | 524 | ||
| 521 | RCU_INIT_POINTER(q->sock.wq, &q->wq); | 525 | RCU_INIT_POINTER(q->sock.wq, &q->wq); |
| 522 | init_waitqueue_head(&q->wq.wait); | 526 | init_waitqueue_head(&q->wq.wait); |
| @@ -540,22 +544,18 @@ static int tap_open(struct inode *inode, struct file *file) | |||
| 540 | if ((tap->dev->features & NETIF_F_HIGHDMA) && (tap->dev->features & NETIF_F_SG)) | 544 | if ((tap->dev->features & NETIF_F_HIGHDMA) && (tap->dev->features & NETIF_F_SG)) |
| 541 | sock_set_flag(&q->sk, SOCK_ZEROCOPY); | 545 | sock_set_flag(&q->sk, SOCK_ZEROCOPY); |
| 542 | 546 | ||
| 543 | err = -ENOMEM; | ||
| 544 | if (skb_array_init(&q->skb_array, tap->dev->tx_queue_len, GFP_KERNEL)) | ||
| 545 | goto err_array; | ||
| 546 | |||
| 547 | err = tap_set_queue(tap, file, q); | 547 | err = tap_set_queue(tap, file, q); |
| 548 | if (err) | 548 | if (err) { |
| 549 | goto err_queue; | 549 | /* tap_sock_destruct() will take care of freeing skb_array */ |
| 550 | goto err_put; | ||
| 551 | } | ||
| 550 | 552 | ||
| 551 | dev_put(tap->dev); | 553 | dev_put(tap->dev); |
| 552 | 554 | ||
| 553 | rtnl_unlock(); | 555 | rtnl_unlock(); |
| 554 | return err; | 556 | return err; |
| 555 | 557 | ||
| 556 | err_queue: | 558 | err_put: |
| 557 | skb_array_cleanup(&q->skb_array); | ||
| 558 | err_array: | ||
| 559 | sock_put(&q->sk); | 559 | sock_put(&q->sk); |
| 560 | err: | 560 | err: |
| 561 | if (tap) | 561 | if (tap) |
