lkml.org 
[lkml]   [2019]   [Jun]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.1 111/121] Bluetooth: Fix regression with minimum encryption key size alignment
    Date
    From: Marcel Holtmann <marcel@holtmann.org>

    commit 693cd8ce3f882524a5d06f7800dd8492411877b3 upstream.

    When trying to align the minimum encryption key size requirement for
    Bluetooth connections, it turns out doing this in a central location in
    the HCI connection handling code is not possible.

    Original Bluetooth version up to 2.0 used a security model where the
    L2CAP service would enforce authentication and encryption. Starting
    with Bluetooth 2.1 and Secure Simple Pairing that model has changed into
    that the connection initiator is responsible for providing an encrypted
    ACL link before any L2CAP communication can happen.

    Now connecting Bluetooth 2.1 or later devices with Bluetooth 2.0 and
    before devices are causing a regression. The encryption key size check
    needs to be moved out of the HCI connection handling into the L2CAP
    channel setup.

    To achieve this, the current check inside hci_conn_security() has been
    moved into l2cap_check_enc_key_size() helper function and then called
    from four decisions point inside L2CAP to cover all combinations of
    Secure Simple Pairing enabled devices and device using legacy pairing
    and legacy service security model.

    Fixes: d5bb334a8e17 ("Bluetooth: Align minimum encryption key size for LE and BR/EDR connections")
    Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=203643
    Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
    Cc: stable@vger.kernel.org
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    net/bluetooth/hci_conn.c | 18 +++++++++---------
    net/bluetooth/l2cap_core.c | 33 ++++++++++++++++++++++++++++-----
    2 files changed, 37 insertions(+), 14 deletions(-)

    --- a/net/bluetooth/hci_conn.c
    +++ b/net/bluetooth/hci_conn.c
    @@ -1276,14 +1276,6 @@ int hci_conn_check_link_mode(struct hci_
    !test_bit(HCI_CONN_ENCRYPT, &conn->flags))
    return 0;

    - /* The minimum encryption key size needs to be enforced by the
    - * host stack before establishing any L2CAP connections. The
    - * specification in theory allows a minimum of 1, but to align
    - * BR/EDR and LE transports, a minimum of 7 is chosen.
    - */
    - if (conn->enc_key_size < HCI_MIN_ENC_KEY_SIZE)
    - return 0;
    -
    return 1;
    }

    @@ -1400,8 +1392,16 @@ auth:
    return 0;

    encrypt:
    - if (test_bit(HCI_CONN_ENCRYPT, &conn->flags))
    + if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) {
    + /* Ensure that the encryption key size has been read,
    + * otherwise stall the upper layer responses.
    + */
    + if (!conn->enc_key_size)
    + return 0;
    +
    + /* Nothing else needed, all requirements are met */
    return 1;
    + }

    hci_conn_encrypt(conn);
    return 0;
    --- a/net/bluetooth/l2cap_core.c
    +++ b/net/bluetooth/l2cap_core.c
    @@ -1341,6 +1341,21 @@ static void l2cap_request_info(struct l2
    sizeof(req), &req);
    }

    +static bool l2cap_check_enc_key_size(struct hci_conn *hcon)
    +{
    + /* The minimum encryption key size needs to be enforced by the
    + * host stack before establishing any L2CAP connections. The
    + * specification in theory allows a minimum of 1, but to align
    + * BR/EDR and LE transports, a minimum of 7 is chosen.
    + *
    + * This check might also be called for unencrypted connections
    + * that have no key size requirements. Ensure that the link is
    + * actually encrypted before enforcing a key size.
    + */
    + return (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags) ||
    + hcon->enc_key_size > HCI_MIN_ENC_KEY_SIZE);
    +}
    +
    static void l2cap_do_start(struct l2cap_chan *chan)
    {
    struct l2cap_conn *conn = chan->conn;
    @@ -1358,9 +1373,14 @@ static void l2cap_do_start(struct l2cap_
    if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
    return;

    - if (l2cap_chan_check_security(chan, true) &&
    - __l2cap_no_conn_pending(chan))
    + if (!l2cap_chan_check_security(chan, true) ||
    + !__l2cap_no_conn_pending(chan))
    + return;
    +
    + if (l2cap_check_enc_key_size(conn->hcon))
    l2cap_start_connection(chan);
    + else
    + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
    }

    static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
    @@ -1439,7 +1459,10 @@ static void l2cap_conn_start(struct l2ca
    continue;
    }

    - l2cap_start_connection(chan);
    + if (l2cap_check_enc_key_size(conn->hcon))
    + l2cap_start_connection(chan);
    + else
    + l2cap_chan_close(chan, ECONNREFUSED);

    } else if (chan->state == BT_CONNECT2) {
    struct l2cap_conn_rsp rsp;
    @@ -7490,7 +7513,7 @@ static void l2cap_security_cfm(struct hc
    }

    if (chan->state == BT_CONNECT) {
    - if (!status)
    + if (!status && l2cap_check_enc_key_size(hcon))
    l2cap_start_connection(chan);
    else
    __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
    @@ -7499,7 +7522,7 @@ static void l2cap_security_cfm(struct hc
    struct l2cap_conn_rsp rsp;
    __u16 res, stat;

    - if (!status) {
    + if (!status && l2cap_check_enc_key_size(hcon)) {
    if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
    res = L2CAP_CR_PEND;
    stat = L2CAP_CS_AUTHOR_PEND;

    \
     
     \ /
      Last update: 2019-06-24 12:22    [W:4.037 / U:0.372 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site