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

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

 



Hi Luiz,

On Thu, 7 May 2020 at 01:28, Luiz Augusto von Dentz
<luiz.dentz@xxxxxxxxx> wrote:
>
> Hi Archie,
>
> On Wed, May 6, 2020 at 4:45 AM 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.
>
> Is there a test failing because of this? If there is not I would have
> thought this is actually a prefered behavior since the subsequent read
> would cause an error at least the client would be able to the data it
> could read in the beginning otherwise this will be imposing the
> database to read all the handles discarding the data that don't fit
> just to propagate the errors before the data can actually be read.
>

I was running the qualification test GATT/SR/GAR/BI-18-C to BI-22-C,
and sometimes this issue pops out.
It looks like PTS runs these tests by randomly selecting 1 readable
characteristic and 1 other characteristic which is known to be
unauthorized, nonexistent, or with other types of errors. If the 1
readable characteristic is too long, then BlueZ will not return the
expected error, which upsets PTS.

The core spec also describes this behavior in Vol 3, Part F, 3.4.4.7:
"The server shall respond with an ATT_READ_MULTIPLE_RSP PDU if all the
handles are valid and all attributes have sufficient permissions to
allow reading."

> > ---
> >
> >  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..e937d80a8 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(0, data->mtu - data->length - 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
> >
>
>
> --
> 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