Commit 07e4b4df authored by Marcel Holtmann's avatar Marcel Holtmann

[Bluetooth] Fix several copy_to_user() and reference counting glitches

This patch corrects the error handling of copy_to_user() and adds more
error checks. It also fixes two reference counting bugs.

Noticed by Andi Kleen <ak@suse.de>
parent b25756ec
......@@ -353,21 +353,24 @@ int hci_get_conn_list(unsigned long arg)
struct hci_conn_info *ci;
struct hci_dev *hdev;
struct list_head *p;
int n = 0, size;
int n = 0, size, err;
if (copy_from_user(&req, (void *) arg, sizeof(req)))
return -EFAULT;
if (!(hdev = hci_dev_get(req.dev_id)))
return -ENODEV;
size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req);
if (!req.conn_num || req.conn_num > (PAGE_SIZE * 2) / sizeof(*ci))
return -EINVAL;
if (verify_area(VERIFY_WRITE, (void *)arg, size))
return -EFAULT;
size = sizeof(req) + req.conn_num * sizeof(*ci);
if (!(cl = (void *) kmalloc(size, GFP_KERNEL)))
return -ENOMEM;
if (!(hdev = hci_dev_get(req.dev_id))) {
kfree(cl);
return -ENODEV;
}
ci = cl->conn_info;
hci_dev_lock_bh(hdev);
......@@ -381,20 +384,21 @@ int hci_get_conn_list(unsigned long arg)
(ci + n)->out = c->out;
(ci + n)->state = c->state;
(ci + n)->link_mode = c->link_mode;
n++;
if (++n >= req.conn_num)
break;
}
hci_dev_unlock_bh(hdev);
cl->dev_id = hdev->id;
cl->conn_num = n;
size = n * sizeof(struct hci_conn_info) + sizeof(req);
size = sizeof(req) + n * sizeof(*ci);
hci_dev_put(hdev);
copy_to_user((void *) arg, cl, size);
err = copy_to_user((void *) arg, cl, size);
kfree(cl);
return 0;
return err ? -EFAULT : 0;
}
int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg)
......@@ -407,9 +411,6 @@ int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg)
if (copy_from_user(&req, (void *) arg, sizeof(req)))
return -EFAULT;
if (verify_area(VERIFY_WRITE, ptr, sizeof(ci)))
return -EFAULT;
hci_dev_lock_bh(hdev);
conn = hci_conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
if (conn) {
......@@ -425,6 +426,5 @@ int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg)
if (!conn)
return -ENOENT;
copy_to_user(ptr, &ci, sizeof(ci));
return 0;
return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
}
......@@ -716,22 +716,20 @@ int hci_get_dev_list(unsigned long arg)
struct hci_dev_list_req *dl;
struct hci_dev_req *dr;
struct list_head *p;
int n = 0, size;
int n = 0, size, err;
__u16 dev_num;
if (get_user(dev_num, (__u16 *) arg))
return -EFAULT;
if (!dev_num)
if (!dev_num || dev_num > (PAGE_SIZE * 2) / sizeof(*dr))
return -EINVAL;
size = dev_num * sizeof(*dr) + sizeof(*dl);
if (verify_area(VERIFY_WRITE, (void *) arg, size))
return -EFAULT;
size = sizeof(*dl) + dev_num * sizeof(*dr);
if (!(dl = kmalloc(size, GFP_KERNEL)))
return -ENOMEM;
dr = dl->dev_req;
read_lock_bh(&hci_dev_list_lock);
......@@ -746,12 +744,12 @@ int hci_get_dev_list(unsigned long arg)
read_unlock_bh(&hci_dev_list_lock);
dl->dev_num = n;
size = n * sizeof(*dr) + sizeof(*dl);
size = sizeof(*dl) + n * sizeof(*dr);
copy_to_user((void *) arg, dl, size);
err = copy_to_user((void *) arg, dl, size);
kfree(dl);
return 0;
return err ? -EFAULT : 0;
}
int hci_get_dev_info(unsigned long arg)
......
......@@ -349,7 +349,7 @@ static int rfcomm_get_dev_list(unsigned long arg)
struct rfcomm_dev_list_req *dl;
struct rfcomm_dev_info *di;
struct list_head *p;
int n = 0, size;
int n = 0, size, err;
u16 dev_num;
BT_DBG("");
......@@ -357,14 +357,11 @@ static int rfcomm_get_dev_list(unsigned long arg)
if (get_user(dev_num, (u16 *) arg))
return -EFAULT;
if (!dev_num)
if (!dev_num || dev_num > (PAGE_SIZE * 4) / sizeof(*di))
return -EINVAL;
size = sizeof(*dl) + dev_num * sizeof(*di);
if (verify_area(VERIFY_WRITE, (void *)arg, size))
return -EFAULT;
if (!(dl = kmalloc(size, GFP_KERNEL)))
return -ENOMEM;
......@@ -389,9 +386,10 @@ static int rfcomm_get_dev_list(unsigned long arg)
dl->dev_num = n;
size = sizeof(*dl) + n * sizeof(*di);
copy_to_user((void *) arg, dl, size);
err = copy_to_user((void *) arg, dl, size);
kfree(dl);
return 0;
return err ? -EFAULT : 0;
}
static int rfcomm_get_dev_info(unsigned long arg)
......@@ -563,8 +561,10 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel);
if (err < 0)
if (err < 0) {
rfcomm_dev_put(dev);
return err;
}
/* Wait for DLC to connect */
add_wait_queue(&dev->wait, &wait);
......@@ -589,6 +589,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->wait, &wait);
if (err < 0)
rfcomm_dev_put(dev);
return err;
}
......
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