Skip to content

Commit

Permalink
Bluetooth: notify userspace of security level change
Browse files Browse the repository at this point in the history
It fixes L2CAP socket based security level elevation during a
connection. The HID profile needs this (for keyboards) and it is the only
way to achieve the security level elevation when using the management
interface to talk to the kernel (hence the management enabling patch
being the one that exposes this issue).

It enables the userspace a security level change when the socket is
already connected and create a way to notify the socket the result of the
request. At the moment of the request the socket is made non writable, if
the request fails the connections closes, otherwise the socket is made
writable again, POLL_OUT is emmited.

Signed-off-by: Gustavo Padovan <gustavo@padovan.org>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Gustavo Padovan authored and John W. Linville committed May 14, 2012
1 parent 574e02a commit a7d7723
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 5 deletions.
1 change: 1 addition & 0 deletions include/net/bluetooth/bluetooth.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ struct bt_sock {
struct list_head accept_q;
struct sock *parent;
u32 defer_setup;
bool suspended;
};

struct bt_sock_list {
Expand Down
2 changes: 1 addition & 1 deletion net/bluetooth/af_bluetooth.c
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wa
sk->sk_state == BT_CONFIG)
return mask;

if (sock_writeable(sk))
if (!bt_sk(sk)->suspended && sock_writeable(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else
set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
Expand Down
7 changes: 7 additions & 0 deletions net/bluetooth/hci_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -2039,6 +2039,12 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *

clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);

if (ev->status && conn->state == BT_CONNECTED) {
hci_acl_disconn(conn, 0x13);
hci_conn_put(conn);
goto unlock;
}

if (conn->state == BT_CONFIG) {
if (!ev->status)
conn->state = BT_CONNECTED;
Expand All @@ -2049,6 +2055,7 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
hci_encrypt_cfm(conn, ev->status, ev->encrypt);
}

unlock:
hci_dev_unlock(hdev);
}

Expand Down
5 changes: 5 additions & 0 deletions net/bluetooth/l2cap_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -4589,6 +4589,11 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)

if (!status && (chan->state == BT_CONNECTED ||
chan->state == BT_CONFIG)) {
struct sock *sk = chan->sk;

bt_sk(sk)->suspended = false;
sk->sk_state_change(sk);

l2cap_check_encryption(chan, encrypt);
l2cap_chan_unlock(chan);
continue;
Expand Down
12 changes: 8 additions & 4 deletions net/bluetooth/l2cap_sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -592,10 +592,14 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
sk->sk_state = BT_CONFIG;
chan->state = BT_CONFIG;

/* or for ACL link, under defer_setup time */
} else if (sk->sk_state == BT_CONNECT2 &&
bt_sk(sk)->defer_setup) {
err = l2cap_chan_check_security(chan);
/* or for ACL link */
} else if ((sk->sk_state == BT_CONNECT2 &&
bt_sk(sk)->defer_setup) ||
sk->sk_state == BT_CONNECTED) {
if (!l2cap_chan_check_security(chan))
bt_sk(sk)->suspended = true;
else
sk->sk_state_change(sk);
} else {
err = -EINVAL;
}
Expand Down

0 comments on commit a7d7723

Please sign in to comment.