Re: [Bluez PATCH v2] shared/gatt-server: Fix read multiple charc values

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Archie,

On Wed, May 6, 2020 at 11:38 PM Archie Pusaka <apusaka@xxxxxxxxxx> wrote:
>
> From: Archie Pusaka <apusaka@xxxxxxxxxxxx>
>
> According to bluetooth spec Ver 5.2, Vol 3, Part G, 4.8.4, An
> ATT_ERROR_RSP PDU shall be sent by the server in response to the
> ATT_READ_MULTIPLE_RSP PDU if insufficient authentication,
> insufficient authorization, insufficient encryption key size, or
> insufficient encryption is used by the client, or if a read operation
> is not permitted on any of the Characteristic Values.
>
> Currently if the size of the response grows larger than the MTU size,
> BlueZ does an early return and not check the permission for the rest
> of the characteristics. This patch forces BlueZ to check for possible
> errors even though we already reach MTU size.
>
> This patch also moves the read permission check for read multiple
> characteristics so it is done before actually retrieving the
> characteristics.
> ---
>
> Changes in v2:
> - Fix error underflowing unsigned int
>
>  src/shared/gatt-server.c | 88 ++++++++++++++++++++--------------------
>  1 file changed, 45 insertions(+), 43 deletions(-)
>
> diff --git a/src/shared/gatt-server.c b/src/shared/gatt-server.c
> index 4e07398d2..28ac2d68d 100644
> --- a/src/shared/gatt-server.c
> +++ b/src/shared/gatt-server.c
> @@ -1057,33 +1057,23 @@ static void read_multiple_complete_cb(struct gatt_db_attribute *attr, int err,
>         uint16_t length;
>
>         if (err != 0) {
> -               bt_att_chan_send_error_rsp(data->chan, data->opcode, handle,
> -                                                                       err);
> -               read_mult_data_free(data);
> -               return;
> -       }
> -
> -       ecode = check_permissions(data->server, attr, BT_ATT_PERM_READ |
> -                                               BT_ATT_PERM_READ_AUTHEN |
> -                                               BT_ATT_PERM_READ_ENCRYPT);
> -       if (ecode) {
> -               bt_att_chan_send_error_rsp(data->chan, data->opcode, handle,
> -                                                                       ecode);
> -               read_mult_data_free(data);
> -               return;
> +               ecode = err;
> +               goto error;
>         }
>
>         length = data->opcode == BT_ATT_OP_READ_MULT_VL_REQ ?
> -                       MIN(len, data->mtu - data->length - 3) :
> +                       MIN(len, MAX(data->mtu - data->length, 3) - 3) :
>                         MIN(len, data->mtu - data->length - 1);
>
>         if (data->opcode == BT_ATT_OP_READ_MULT_VL_REQ) {
>                 /* The Length Value Tuple List may be truncated within the first
>                  * two octets of a tuple due to the size limits of the current
> -                * ATT_MTU.
> +                * ATT_MTU, but the first two octets cannot be separated.
>                  */
> -               put_le16(len, data->rsp_data + data->length);
> -               data->length += 2;
> +               if (data->mtu - data->length >= 3) {
> +                       put_le16(len, data->rsp_data + data->length);
> +                       data->length += 2;
> +               }
>         }
>
>         memcpy(data->rsp_data + data->length, value, length);
> @@ -1091,45 +1081,46 @@ static void read_multiple_complete_cb(struct gatt_db_attribute *attr, int err,
>
>         data->cur_handle++;
>
> -       len = data->opcode == BT_ATT_OP_READ_MULT_VL_REQ ?
> -               data->mtu - data->length - 3 : data->mtu - data->length - 1;
> -
> -       if (!len || (data->cur_handle == data->num_handles)) {
> +       if (data->cur_handle == data->num_handles) {
>                 bt_att_chan_send_rsp(data->chan, data->opcode + 1,
>                                                 data->rsp_data, data->length);
>                 read_mult_data_free(data);
>                 return;
>         }
>
> +       handle = data->handles[data->cur_handle];
> +
>         util_debug(data->server->debug_callback, data->server->debug_data,
>                                 "%s Req - #%zu of %zu: 0x%04x",
>                                 data->opcode == BT_ATT_OP_READ_MULT_REQ ?
>                                 "Read Multiple" :
>                                 "Read Multiple Variable Length",
>                                 data->cur_handle + 1, data->num_handles,
> -                               data->handles[data->cur_handle]);
> +                               handle);
>
> -       next_attr = gatt_db_get_attribute(data->server->db,
> -                                       data->handles[data->cur_handle]);
> +       next_attr = gatt_db_get_attribute(data->server->db, handle);
>
>         if (!next_attr) {
> -               bt_att_chan_send_error_rsp(data->chan,
> -                                       BT_ATT_OP_READ_MULT_REQ,
> -                                       data->handles[data->cur_handle],
> -                                       BT_ATT_ERROR_INVALID_HANDLE);
> -               read_mult_data_free(data);
> -               return;
> +               ecode = BT_ATT_ERROR_INVALID_HANDLE;
> +               goto error;
>         }
>
> -       if (!gatt_db_attribute_read(next_attr, 0, BT_ATT_OP_READ_MULT_REQ,
> +       ecode = check_permissions(data->server, next_attr, BT_ATT_PERM_READ |
> +                                               BT_ATT_PERM_READ_AUTHEN |
> +                                               BT_ATT_PERM_READ_ENCRYPT);
> +       if (ecode)
> +               goto error;
> +
> +       if (gatt_db_attribute_read(next_attr, 0, data->opcode,
>                                         data->server->att,
> -                                       read_multiple_complete_cb, data)) {
> -               bt_att_chan_send_error_rsp(data->chan,
> -                                               BT_ATT_OP_READ_MULT_REQ,
> -                                               data->handles[data->cur_handle],
> -                                               BT_ATT_ERROR_UNLIKELY);
> -               read_mult_data_free(data);
> -       }
> +                                       read_multiple_complete_cb, data))
> +               return;
> +
> +       ecode = BT_ATT_ERROR_UNLIKELY;
> +
> +error:
> +       bt_att_chan_send_error_rsp(data->chan, data->opcode, handle, ecode);
> +       read_mult_data_free(data);
>  }
>
>  static struct read_mult_data *read_mult_data_new(struct bt_gatt_server *server,
> @@ -1161,8 +1152,9 @@ static void read_multiple_cb(struct bt_att_chan *chan, uint8_t opcode,
>         struct bt_gatt_server *server = user_data;
>         struct gatt_db_attribute *attr;
>         struct read_mult_data *data = NULL;
> -       uint8_t ecode = BT_ATT_ERROR_UNLIKELY;
> +       uint8_t ecode;
>         size_t i = 0;
> +       uint16_t handle = 0;
>
>         if (length < 4) {
>                 ecode = BT_ATT_ERROR_INVALID_PDU;
> @@ -1176,28 +1168,38 @@ static void read_multiple_cb(struct bt_att_chan *chan, uint8_t opcode,
>         for (i = 0; i < data->num_handles; i++)
>                 data->handles[i] = get_le16(pdu + i * 2);
>
> +       handle = data->handles[0];
> +
>         util_debug(server->debug_callback, server->debug_data,
>                         "%s Req - %zu handles, 1st: 0x%04x",
>                         data->opcode == BT_ATT_OP_READ_MULT_REQ ?
>                         "Read Multiple" : "Read Multiple Variable Length",
> -                       data->num_handles, data->handles[0]);
> +                       data->num_handles, handle);
>
> -       attr = gatt_db_get_attribute(server->db, data->handles[0]);
> +       attr = gatt_db_get_attribute(server->db, handle);
>
>         if (!attr) {
>                 ecode = BT_ATT_ERROR_INVALID_HANDLE;
>                 goto error;
>         }
>
> +       ecode = check_permissions(data->server, attr, BT_ATT_PERM_READ |
> +                                               BT_ATT_PERM_READ_AUTHEN |
> +                                               BT_ATT_PERM_READ_ENCRYPT);
> +       if (ecode)
> +               goto error;
> +
>         if (gatt_db_attribute_read(attr, 0, opcode, server->att,
>                                         read_multiple_complete_cb, data))
>                 return;
>
> +       ecode = BT_ATT_ERROR_UNLIKELY;
> +
>  error:
>         if (data)
>                 read_mult_data_free(data);
>
> -       bt_att_chan_send_error_rsp(chan, opcode, 0, ecode);
> +       bt_att_chan_send_error_rsp(chan, opcode, handle, ecode);
>  }
>
>  static bool append_prep_data(struct prep_write_data *prep_data, uint16_t handle,
> --
> 2.26.2.526.g744177e7f7-goog

Applied, thanks.

-- 
Luiz Augusto von Dentz



[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux