Re: [RFC v2] Implementation of MGMT_OP_SET_BLOCKED_KEYS.

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

 



Thanks Marcel.

I believe I have addressed all your feedback here.  Will send a patch
after some additional testing.

Thanks,
Alain

On Sun, Dec 8, 2019 at 4:45 AM Marcel Holtmann <marcel@xxxxxxxxxxxx> wrote:
>
> Hi Alain,
>
> > Here's a newer version with most of your feedback addressed.  Others
> > responses sent inline in the v1.
>
> so lets put a proper commit message with all the details here. Don’t forget the Signed-off-by.
>
> >
> > ---
> > include/net/bluetooth/hci_core.h |  9 +++++
> > include/net/bluetooth/mgmt.h     | 17 ++++++++++
> > net/bluetooth/hci_core.c         | 56 ++++++++++++++++++++++++++++++--
> > net/bluetooth/mgmt.c             | 51 +++++++++++++++++++++++++++++
> > net/bluetooth/smp.c              |  8 +++++
> > 5 files changed, 138 insertions(+), 3 deletions(-)
>
> And comments for the reviewer can go here.
>
> > diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> > index b689aceb636b..e9a789e11493 100644
> > --- a/include/net/bluetooth/hci_core.h
> > +++ b/include/net/bluetooth/hci_core.h
> > @@ -118,6 +118,13 @@ struct bt_uuid {
> >       u8 svc_hint;
> > };
> >
> > +struct blocked_key {
> > +     struct list_head list;
> > +     struct rcu_head rcu;
> > +     u8 type;
> > +     u8 val[16];
> > +};
> > +
> > struct smp_csrk {
> >       bdaddr_t bdaddr;
> >       u8 bdaddr_type;
> > @@ -397,6 +404,7 @@ struct hci_dev {
> >       struct list_head        le_conn_params;
> >       struct list_head        pend_le_conns;
> >       struct list_head        pend_le_reports;
> > +     struct list_head        blocked_keys;
> >
> >       struct hci_dev_stats    stat;
> >
> > @@ -1121,6 +1129,7 @@ struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
> > struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr,
> >                           u8 addr_type, u8 val[16], bdaddr_t *rpa);
> > void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type);
> > +bool hci_is_blocked_key(struct hci_dev *hdev, u8 type, u8 val[16]);
> > void hci_smp_irks_clear(struct hci_dev *hdev);
> >
> > bool hci_bdaddr_is_paired(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
> > diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
> > index 9cee7ddc6741..c9b1d39d6d6c 100644
> > --- a/include/net/bluetooth/mgmt.h
> > +++ b/include/net/bluetooth/mgmt.h
> > @@ -654,6 +654,23 @@ struct mgmt_cp_set_phy_confguration {
> > } __packed;
> > #define MGMT_SET_PHY_CONFIGURATION_SIZE       4
> >
> > +#define MGMT_OP_SET_BLOCKED_KEYS     0x0046
> > +
> > +#define HCI_BLOCKED_KEY_TYPE_LINKKEY 0x00
> > +#define HCI_BLOCKED_KEY_TYPE_LTK             0x01
> > +#define HCI_BLOCKED_KEY_TYPE_IRK             0x02
> > +
> > +struct mgmt_blocked_key_info {
> > +     __u8 type;
> > +     __u8 val[16];
> > +} __packed;
> > +
> > +struct mgmt_cp_set_blocked_keys {
> > +     __le16 key_count;
> > +     struct mgmt_blocked_key_info keys[0];
> > +} __packed;
> > +#define MGMT_OP_SET_BLOCKED_KEYS_SIZE 0
> > +
> > #define MGMT_EV_CMD_COMPLETE          0x0001
> > struct mgmt_ev_cmd_complete {
> >       __le16  opcode;
> > diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> > index 9e19d5a3aac8..52e7bf295a51 100644
> > --- a/net/bluetooth/hci_core.c
> > +++ b/net/bluetooth/hci_core.c
> > @@ -2311,6 +2311,35 @@ void hci_smp_irks_clear(struct hci_dev *hdev)
> >       }
> > }
> >
> > +static void hci_blocked_keys_clear(struct hci_dev *hdev)
> > +{
> > +     struct blocked_key *b;
> > +
> > +     list_for_each_entry_rcu(b, &hdev->blocked_keys, list) {
> > +             list_del_rcu(&b->list);
> > +             kfree_rcu(b, rcu);
> > +     }
> > +}
> > +
> > +bool hci_is_blocked_key(struct hci_dev *hdev, u8 type, u8 val[16])
> > +{
> > +     bool blocked = false;
> > +     struct blocked_key *b;
> > +
> > +     rcu_read_lock();
> > +     list_for_each_entry(b, &hdev->blocked_keys, list) {
> > +             if (b->type == type &&
> > +                             !memcmp(b->val, val, sizeof(b->val))) {
>
> Indentation error.
>
> > +                     blocked = true;
> > +                     goto done;
>
> Isn’t break; enough here and we avoid the label.
>
> > +             }
> > +     }
> > +
> > +done:
> > +     rcu_read_unlock();
> > +     return blocked;
> > +}
> > +
> > struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
> > {
> >       struct link_key *k;
> > @@ -2319,6 +2348,16 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
> >       list_for_each_entry_rcu(k, &hdev->link_keys, list) {
> >               if (bacmp(bdaddr, &k->bdaddr) == 0) {
> >                       rcu_read_unlock();
> > +
> > +                     if (hci_is_blocked_key(hdev, HCI_BLOCKED_KEY_TYPE_LINKKEY,
> > +                                             k->val)) {
> > +                             WARN_ONCE(1, "Key blocked for %pMR", &k->bdaddr);
>
> I just realized that I gave bad advice. WARN_ONCE is not going to do the right job. If we have multiple keys in our list it will only ever warn for the initial one.
>
> So it might be better to create a new bt_warn_ratelimited and use that one.
>
> > +
> > +                             /* The device may have refreshed it to a new one which
> > +                              * would imply a second key is in the list */
> > +                             continue;
>
> I am not sure this actually helps. The keys are created by a key agreement function. I would really just ignore this possibility. If the key refresh procedure is used, you can not guess the next key.
>
> > +                     }
> > +
> >                       return k;
> >               }
> >       }
> > @@ -2387,6 +2426,12 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
> >
> >               if (smp_ltk_is_sc(k) || ltk_role(k->type) == role) {
> >                       rcu_read_unlock();
> > +
> > +                     if (hci_is_blocked_key(hdev, HCI_BLOCKED_KEY_TYPE_LTK, k->val)) {
> > +                             WARN_ONCE(1, "Key blocked for %pMR", &k->bdaddr);
>
> See comment above with bt_warn_ratelimited.
>
> > +                             return NULL;
> > +                     }
> > +
> >                       return k;
> >               }
> >       }
> > @@ -2548,10 +2593,13 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
> >       if (!key)
> >               return -ENOENT;
> >
> > -     BT_DBG("%s removing %pMR", hdev->name, bdaddr);
> > +     do {
> > +             BT_DBG("%s removing %pMR", hdev->name, bdaddr);
> >
> > -     list_del_rcu(&key->list);
> > -     kfree_rcu(key, rcu);
> > +             list_del_rcu(&key->list);
> > +             kfree_rcu(key, rcu);
> > +             key = hci_find_link_key(hdev, bdaddr);
> > +     } while (key);
>
> I am still not convinced here. If we have more than one link key for a given address, we do have a problem. We should check that this doesn’t happen in the first place.
>
> >
> >       return 0;
> > }
> > @@ -3244,6 +3292,7 @@ struct hci_dev *hci_alloc_dev(void)
> >       INIT_LIST_HEAD(&hdev->pend_le_reports);
> >       INIT_LIST_HEAD(&hdev->conn_hash.list);
> >       INIT_LIST_HEAD(&hdev->adv_instances);
> > +     INIT_LIST_HEAD(&hdev->blocked_keys);
> >
> >       INIT_WORK(&hdev->rx_work, hci_rx_work);
> >       INIT_WORK(&hdev->cmd_work, hci_cmd_work);
> > @@ -3443,6 +3492,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
> >       hci_bdaddr_list_clear(&hdev->le_resolv_list);
> >       hci_conn_params_clear_all(hdev);
> >       hci_discovery_filter_clear(hdev);
> > +     hci_blocked_keys_clear(hdev);
> >       hci_dev_unlock(hdev);
> >
> >       hci_dev_put(hdev);
> > diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> > index acb7c6d5643f..6fb4ce768863 100644
> > --- a/net/bluetooth/mgmt.c
> > +++ b/net/bluetooth/mgmt.c
> > @@ -106,6 +106,7 @@ static const u16 mgmt_commands[] = {
> >       MGMT_OP_START_LIMITED_DISCOVERY,
> >       MGMT_OP_READ_EXT_INFO,
> >       MGMT_OP_SET_APPEARANCE,
> > +     MGMT_OP_SET_BLOCKED_KEYS,
> > };
>
> Once this patch has made it upstream, you might also want to send a patch to increase the minor version for mgmt interface. While we don’t actually use it, it is an extra precaution to allow distinguishing kernel release if ever needed. And I think the last time I added new commands, I totally forgot it.
>
> >
> > static const u16 mgmt_events[] = {
> > @@ -3531,6 +3532,55 @@ static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
> >       return err;
> > }
> >
> > +static int set_blocked_keys(struct sock *sk, struct hci_dev *hdev, void *data,
> > +                       u16 len)
> > +{
> > +     int err = MGMT_STATUS_SUCCESS;
> > +
> > +     if (len < sizeof (struct mgmt_cp_set_blocked_keys) ||
> > +         ((len - offsetof(struct mgmt_cp_set_blocked_keys, keys)) %
> > +                     sizeof(struct mgmt_blocked_key_info))) {
>
> So I have no idea what the indentation rule is for this. Can we introduce a helper macro for this?
>
> > +             return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
> > +                             MGMT_STATUS_INVALID_PARAMS, NULL, 0);
> > +     }
> > +
> > +     hci_dev_lock(hdev);
> > +     {
> > +             struct mgmt_cp_set_blocked_keys *keys = data;
> > +             int i;
> > +             for (i = 0; i < keys->key_count; ++i) {
> > +                     bool already_blocked = false;
> > +                     struct blocked_key *b;
> > +
> > +                     list_for_each_entry(b, &hdev->blocked_keys, list) {
> > +                             if (keys->keys[i].type == b->type &&
> > +                                     !memcmp(keys->keys[i].val, b->val,
> > +                                                     sizeof(keys->keys[i].val))) {
> > +                                     already_blocked = true;
> > +                                     break;
> > +                             }
> > +                     }
> > +
> > +                     if (already_blocked)
> > +                             continue;
> > +
> > +                     b = kzalloc(sizeof(*b), GFP_KERNEL);
> > +                     if (!b) {
> > +                             err = MGMT_STATUS_NO_RESOURCES;
> > +                             break;
> > +                     }
> > +
> > +                     b->type = keys->keys[i].type;
> > +                     memcpy(b->val, keys->keys[i].val, sizeof(b->val));
> > +                     list_add_rcu(&b->list, &hdev->blocked_keys);
> > +             }
> > +     }
>
> Lets avoid the extra { } and the indentation.
>
> > +     hci_dev_unlock(hdev);
> > +
> > +     return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS,
> > +                             err, NULL, 0);
> > +}
> > +
> > static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
> >                                        u16 opcode, struct sk_buff *skb)
> > {
> > @@ -6914,6 +6964,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
> >       { set_appearance,          MGMT_SET_APPEARANCE_SIZE },
> >       { get_phy_configuration,   MGMT_GET_PHY_CONFIGURATION_SIZE },
> >       { set_phy_configuration,   MGMT_SET_PHY_CONFIGURATION_SIZE },
> > +     { set_blocked_keys,        MGMT_OP_SET_BLOCKED_KEYS_SIZE },
> > };
> >
> > void mgmt_index_added(struct hci_dev *hdev)
> > diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
> > index 6b42be4b5861..f61c78d81168 100644
> > --- a/net/bluetooth/smp.c
> > +++ b/net/bluetooth/smp.c
> > @@ -2453,6 +2453,10 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
> >       if (skb->len < sizeof(*rp))
> >               return SMP_INVALID_PARAMS;
> >
> > +     if (hci_is_blocked_key(conn->hcon->hdev, HCI_BLOCKED_KEY_TYPE_LTK,
> > +                     rp->ltk))
>
> Please fix the indentation here.
>
> > +             return SMP_INVALID_PARAMS;
> > +
> >       SMP_ALLOW_CMD(smp, SMP_CMD_MASTER_IDENT);
> >
> >       skb_pull(skb, sizeof(*rp));
> > @@ -2509,6 +2513,10 @@ static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb)
> >       if (skb->len < sizeof(*info))
> >               return SMP_INVALID_PARAMS;
> >
> > +     if (hci_is_blocked_key(conn->hcon->hdev, HCI_BLOCKED_KEY_TYPE_IRK,
> > +                     info->irk))
>
> Same as above.
>
> > +             return SMP_INVALID_PARAMS;
> > +
> >       SMP_ALLOW_CMD(smp, SMP_CMD_IDENT_ADDR_INFO);
> >
> >       skb_pull(skb, sizeof(*info));
>
> Regards
>
> Marcel
>




[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