From: Szymon Janc <szymon.janc@tieto.com>
To: johan.hedberg@gmail.com
Cc: linux-bluetooth@vger.kernel.org
Subject: Re: [PATCH 5/7] Bluetooth: Fix locking of the SMP context
Date: Fri, 05 Sep 2014 13:20:55 +0200 [thread overview]
Message-ID: <8600588.nst1WmC3R5@uw000953> (raw)
In-Reply-To: <1409914266-21624-6-git-send-email-johan.hedberg@gmail.com>
Hi Johan,
On Friday 05 of September 2014 13:51:04 johan.hedberg@gmail.com wrote:
> From: Johan Hedberg <johan.hedberg@intel.com>
>
> Before the move the l2cap_chan the SMP context (smp_chan) didn't have
> any kind of proper locking. The best there existed was the
> HCI_CONN_LE_SMP_PEND flag which was used to enable mutual exclusion for
> potential multiple creators of the SMP context.
>
> Now that SMP has been converted to use the l2cap_chan infrastructure and
> since the SMP context is directly mapped to a corresponding l2cap_chan
> we get the SMP context locking essentially for free through the
> l2cap_chan lock. For all callbacks that l2cap_core.c makes for each
> channel implementation (smp.c in the case of SMP) the l2cap_chan lock is
> held through l2cap_chan_lock(chan).
>
> Since the calls from l2cap_core.c to smp.c are covered the only missing
> piece to have the locking implemented properly is to ensure that the
> lock is held for any other call path that may access the SMP context.
> This means user responses through mgmt.c, requests to elevate the
> security of a connection through hci_conn.c, as well as any deferred
> work through workqueues.
>
> This patch adds the necessary locking to all these other code paths that
> try to access the SMP context. Since mutual exclusion for the l2cap_chan
> access is now covered from all directions the patch also removes
> unnecessary HCI_CONN_LE_SMP_PEND flag (once we've acquired the chan lock
> we can simply check whether chan->smp is set to know if there's an SMP
> context).
>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> include/net/bluetooth/hci_core.h | 1 -
> net/bluetooth/smp.c | 73 +++++++++++++++++++++++-----------------
> 2 files changed, 43 insertions(+), 31 deletions(-)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 2b6e04d37593..045d9133d180 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -539,7 +539,6 @@ enum {
> HCI_CONN_RSWITCH_PEND,
> HCI_CONN_MODE_CHANGE_PEND,
> HCI_CONN_SCO_SETUP_PEND,
> - HCI_CONN_LE_SMP_PEND,
> HCI_CONN_MGMT_CONNECTED,
> HCI_CONN_SSP_ENABLED,
> HCI_CONN_SC_ENABLED,
> diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
> index 0b4403f3dce1..7bdc3166db97 100644
> --- a/net/bluetooth/smp.c
> +++ b/net/bluetooth/smp.c
> @@ -409,7 +409,6 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason)
> {
> struct hci_conn *hcon = conn->hcon;
> struct l2cap_chan *chan = conn->smp;
> - struct smp_chan *smp;
>
> if (reason)
> smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
> @@ -419,12 +418,7 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason)
> mgmt_auth_failed(hcon->hdev, &hcon->dst, hcon->type, hcon->dst_type,
> HCI_ERROR_AUTH_FAILURE);
>
> - if (!chan->data)
> - return;
> -
> - smp = chan->data;
> -
> - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
> + if (chan->data)
> smp_chan_destroy(conn);
> }
>
> @@ -706,9 +700,6 @@ static void smp_distribute_keys(struct smp_chan *smp)
>
> BT_DBG("conn %p", conn);
>
> - if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
> - return;
> -
> rsp = (void *) &smp->prsp[1];
>
> /* The responder sends its keys first */
> @@ -801,7 +792,6 @@ static void smp_distribute_keys(struct smp_chan *smp)
> if ((smp->remote_key_dist & 0x07))
> return;
>
> - clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags);
> set_bit(SMP_FLAG_COMPLETE, &smp->flags);
> smp_notify_keys(conn);
>
> @@ -825,16 +815,13 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
> struct smp_chan *smp;
>
> smp = kzalloc(sizeof(*smp), GFP_ATOMIC);
> - if (!smp) {
> - clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
> + if (!smp)
> return NULL;
> - }
>
> smp->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
> if (IS_ERR(smp->tfm_aes)) {
> BT_ERR("Unable to create ECB crypto context");
> kfree(smp);
> - clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
> return NULL;
> }
>
> @@ -854,16 +841,23 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
> struct l2cap_chan *chan;
> struct smp_chan *smp;
> u32 value;
> + int err;
>
> BT_DBG("");
>
> - if (!conn || !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
> + if (!conn)
> return -ENOTCONN;
>
> chan = conn->smp;
> if (!chan)
> return -ENOTCONN;
>
> + l2cap_chan_lock(chan);
> + if (!chan->data) {
> + err = -ENOTCONN;
> + goto unlock;
> + }
> +
> smp = chan->data;
>
> switch (mgmt_op) {
> @@ -879,12 +873,16 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
> case MGMT_OP_USER_PASSKEY_NEG_REPLY:
> case MGMT_OP_USER_CONFIRM_NEG_REPLY:
> smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED);
> - return 0;
> + err = 0;
> + goto unlock;
> default:
> smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED);
> - return -EOPNOTSUPP;
> + err = -EOPNOTSUPP;
> + goto unlock;
> }
>
> + err = 0;
> +
> /* If it is our turn to send Pairing Confirm, do so now */
> if (test_bit(SMP_FLAG_CFM_PENDING, &smp->flags)) {
> u8 rsp = smp_confirm(smp);
> @@ -892,12 +890,15 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
> smp_failure(conn, rsp);
> }
>
> - return 0;
> +unlock:
> + l2cap_chan_unlock(chan);
> + return err;
> }
>
> static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
> {
> struct smp_cmd_pairing rsp, *req = (void *) skb->data;
> + struct l2cap_chan *chan = conn->smp;
> struct hci_dev *hdev = conn->hcon->hdev;
> struct smp_chan *smp;
> u8 key_size, auth, sec_level;
> @@ -911,12 +912,10 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
> if (conn->hcon->role != HCI_ROLE_SLAVE)
> return SMP_CMD_NOTSUPP;
>
> - if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) {
> + if (!chan->data)
> smp = smp_chan_create(conn);
> - } else {
> - struct l2cap_chan *chan = conn->smp;
> + else
> smp = chan->data;
> - }
>
> if (!smp)
> return SMP_UNSPECIFIED;
> @@ -1122,6 +1121,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
> struct smp_cmd_security_req *rp = (void *) skb->data;
> struct smp_cmd_pairing cp;
> struct hci_conn *hcon = conn->hcon;
> + struct l2cap_chan *chan = conn->smp;
> struct smp_chan *smp;
> u8 sec_level;
>
> @@ -1143,7 +1143,8 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
> if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
> return 0;
>
> - if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
> + /* If SMP is already in progress ignore this request */
> + if (chan->data)
> return 0;
>
> smp = smp_chan_create(conn);
> @@ -1170,8 +1171,10 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
> int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
> {
> struct l2cap_conn *conn = hcon->l2cap_data;
> + struct l2cap_chan *chan = conn->smp;
> struct smp_chan *smp;
> __u8 authreq;
> + int ret;
>
> BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
>
> @@ -1192,12 +1195,19 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
> if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
> return 0;
>
> - if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
> - return 0;
> + l2cap_chan_lock(chan);
> +
> + /* If SMP is already in progress ignore this request */
> + if (chan->data) {
> + ret = 0;
> + goto unlock;
> + }
>
> smp = smp_chan_create(conn);
> - if (!smp)
> - return 1;
> + if (!smp) {
> + ret = 1;
> + goto unlock;
> + }
>
> authreq = seclevel_to_authreq(sec_level);
>
> @@ -1223,8 +1233,11 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
> }
>
> set_bit(SMP_FLAG_INITIATOR, &smp->flags);
> + ret = 0;
>
> - return 0;
> +unlock:
> + l2cap_chan_unlock(conn->smp);
I know that this is same data but using chan variable instead of conn->smp will make code
easier to follow since chan was used for locking.
> + return ret;
> }
>
> static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
> @@ -1504,7 +1517,7 @@ static void smp_teardown_cb(struct l2cap_chan *chan, int err)
>
> BT_DBG("chan %p", chan);
>
> - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
> + if (chan->data)
> smp_chan_destroy(conn);
>
> conn->smp = NULL;
>
--
Best regards,
Szymon Janc
next prev parent reply other threads:[~2014-09-05 11:20 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-09-05 10:50 [PATCH 0/7] Bluetooth: SMP fixes/improvements johan.hedberg
2014-09-05 10:51 ` [PATCH 1/7] Bluetooth: Remove unnecessary checks after canceling SMP security timer johan.hedberg
2014-09-05 10:51 ` [PATCH 2/7] Bluetooth: Don't take any action in smp_resume_cb if not encrypted johan.hedberg
2014-09-05 11:19 ` Szymon Janc
2014-09-05 10:51 ` [PATCH 3/7] Bluetooth: Move identity address update behind a workqueue johan.hedberg
2014-09-05 10:51 ` [PATCH 4/7] Bluetooth: Remove unnecessary deferred work for SMP key distribution johan.hedberg
2014-09-05 10:51 ` [PATCH 5/7] Bluetooth: Fix locking of the SMP context johan.hedberg
2014-09-05 11:20 ` Szymon Janc [this message]
2014-09-05 10:51 ` [PATCH 6/7] Bluetooth: Fix calling smp_distribute_keys() when still waiting for keys johan.hedberg
2014-09-05 10:51 ` [PATCH 7/7] Bluetooth: Add strict checks for allowed SMP PDUs johan.hedberg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8600588.nst1WmC3R5@uw000953 \
--to=szymon.janc@tieto.com \
--cc=johan.hedberg@gmail.com \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox