Bluetooth: notify userspace of security level change

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>
This commit is contained in:
Gustavo Padovan 2012-05-13 03:20:07 -03:00 коммит произвёл John W. Linville
Родитель 574e02abaf
Коммит a7d7723ae7
5 изменённых файлов: 22 добавлений и 5 удалений

Просмотреть файл

@ -191,6 +191,7 @@ struct bt_sock {
struct list_head accept_q;
struct sock *parent;
u32 defer_setup;
bool suspended;
};
struct bt_sock_list {

Просмотреть файл

@ -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);

Просмотреть файл

@ -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;
@ -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);
}

Просмотреть файл

@ -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;

Просмотреть файл

@ -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;
}