Bluetooth: Validate data size before accessing mgmt commands
authorSzymon Janc <szymon.janc@tieto.com>
Fri, 25 Feb 2011 18:05:49 +0000 (19:05 +0100)
committerGustavo F. Padovan <padovan@profusion.mobi>
Sun, 27 Feb 2011 19:57:07 +0000 (16:57 -0300)
Crafted (too small) data buffer could result in reading data outside of buffer.
Validate buffer size and return EINVAL if size is wrong.

Signed-off-by: Szymon Janc <szymon.janc@tieto.com>
Acked-by: Johan Hedberg <johan.hedberg@nokia.com>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
net/bluetooth/mgmt.c

index 98c92aee623961ab9fbc266b26dd966b8ae58dfd..16c7a4d0432c52605317b9999abde10b3ed050e6 100644 (file)
@@ -302,6 +302,9 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
        BT_DBG("request for hci%u", index);
 
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
+
        hdev = hci_dev_get(index);
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
@@ -351,6 +354,9 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
 
        BT_DBG("request for hci%u", index);
 
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
+
        hdev = hci_dev_get(index);
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
@@ -409,6 +415,9 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
 
        BT_DBG("request for hci%u", index);
 
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
+
        hdev = hci_dev_get(index);
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
@@ -499,6 +508,9 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
 
        BT_DBG("request for hci%u", index);
 
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
+
        hdev = hci_dev_get(index);
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
@@ -569,6 +581,9 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
        BT_DBG("request for hci%u", index);
 
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
+
        hdev = hci_dev_get(index);
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
@@ -611,6 +626,9 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
        BT_DBG("request for hci%u", index);
 
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
+
        hdev = hci_dev_get(index);
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
@@ -663,6 +681,9 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
 
        BT_DBG("request for hci%u", index);
 
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
+
        hdev = hci_dev_get(index);
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
@@ -692,6 +713,10 @@ static int set_service_cache(struct sock *sk, u16 index,  unsigned char *data,
 
        cp = (void *) data;
 
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE,
+                                                                       EINVAL);
+
        hdev = hci_dev_get(index);
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
@@ -726,6 +751,10 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
        int i;
 
        cp = (void *) data;
+
+       if (len < sizeof(*cp))
+               return -EINVAL;
+
        key_count = get_unaligned_le16(&cp->key_count);
 
        expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
@@ -775,6 +804,9 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
        cp = (void *) data;
 
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
+
        hdev = hci_dev_get(index);
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
@@ -821,6 +853,9 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
        cp = (void *) data;
 
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
+
        hdev = hci_dev_get(index);
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
@@ -931,6 +966,9 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
 
        cp = (void *) data;
 
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
+
        hdev = hci_dev_get(index);
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
@@ -975,6 +1013,10 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
 
        cp = (void *) data;
 
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
+                                                                       EINVAL);
+
        hdev = hci_dev_get(index);
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
@@ -1017,6 +1059,10 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
 
        cp = (void *) data;
 
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
+                                                                       EINVAL);
+
        hdev = hci_dev_get(index);
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
@@ -1107,6 +1153,9 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
        cp = (void *) data;
 
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
+
        hdev = hci_dev_get(index);
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
@@ -1178,6 +1227,9 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
                hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
        }
 
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, mgmt_op, EINVAL);
+
        hdev = hci_dev_get(index);
        if (!hdev)
                return cmd_status(sk, index, mgmt_op, ENODEV);