Skip to content

Commit

Permalink
[Bluetooth] Enforce security for outgoing RFCOMM connections
Browse files Browse the repository at this point in the history
Recent tests with various Bluetooth headsets have shown that some of
them don't enforce authentication and encryption when connecting. All
of them leave it up to the host stack to enforce it. Non of them should
allow unencrypted connections, but that is how it is. So in case the
link mode settings require authentication and/or encryption it will now
also be enforced on outgoing RFCOMM connections. Previously this was
only done for incoming connections.

This support has a small drawback from a protocol level point of view
since the host stack can't really tell with 100% certainty if a remote
side is already authenticated or not. So if both sides are configured
to enforce authentication it will be requested twice. Most Bluetooth
chips are caching this information and thus no extra authentication
procedure has to be triggered over-the-air, but it can happen.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
  • Loading branch information
Marcel Holtmann committed Jul 14, 2008
1 parent 79d554a commit 77db198
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 34 deletions.
1 change: 1 addition & 0 deletions include/net/bluetooth/rfcomm.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ struct rfcomm_dlc {
u8 priority;
u8 v24_sig;
u8 mscex;
u8 out;

u32 link_mode;

Expand Down
77 changes: 46 additions & 31 deletions net/bluetooth/rfcomm/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
#define BT_DBG(D...)
#endif

#define VERSION "1.8"
#define VERSION "1.9"

static int disable_cfc = 0;
static int channel_mtu = -1;
Expand Down Expand Up @@ -230,6 +230,21 @@ static int rfcomm_l2sock_create(struct socket **sock)
return err;
}

static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d)
{
struct sock *sk = d->session->sock->sk;

if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) {
if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon))
return 1;
} else if (d->link_mode & RFCOMM_LM_AUTH) {
if (!hci_conn_auth(l2cap_pi(sk)->conn->hcon))
return 1;
}

return 0;
}

/* ---- RFCOMM DLCs ---- */
static void rfcomm_dlc_timeout(unsigned long arg)
{
Expand Down Expand Up @@ -371,15 +386,23 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
d->addr = __addr(s->initiator, dlci);
d->priority = 7;

d->state = BT_CONFIG;
d->state = BT_CONFIG;
rfcomm_dlc_link(s, d);

d->out = 1;

d->mtu = s->mtu;
d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;

if (s->state == BT_CONNECTED)
rfcomm_send_pn(s, 1, d);
if (s->state == BT_CONNECTED) {
if (rfcomm_check_link_mode(d))
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
else
rfcomm_send_pn(s, 1, d);
}

rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);

return 0;
}

Expand Down Expand Up @@ -1146,21 +1169,6 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
return 0;
}

static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d)
{
struct sock *sk = d->session->sock->sk;

if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) {
if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon))
return 1;
} else if (d->link_mode & RFCOMM_LM_AUTH) {
if (!hci_conn_auth(l2cap_pi(sk)->conn->hcon))
return 1;
}

return 0;
}

static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
{
struct sock *sk = d->session->sock->sk;
Expand Down Expand Up @@ -1205,10 +1213,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
if (rfcomm_check_link_mode(d)) {
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
return 0;
}

rfcomm_dlc_accept(d);
} else
rfcomm_dlc_accept(d);
}
return 0;
}
Expand All @@ -1223,10 +1229,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
if (rfcomm_check_link_mode(d)) {
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
return 0;
}

rfcomm_dlc_accept(d);
} else
rfcomm_dlc_accept(d);
} else {
rfcomm_send_dm(s, dlci);
}
Expand Down Expand Up @@ -1636,7 +1640,11 @@ static void rfcomm_process_connect(struct rfcomm_session *s)
d = list_entry(p, struct rfcomm_dlc, list);
if (d->state == BT_CONFIG) {
d->mtu = s->mtu;
rfcomm_send_pn(s, 1, d);
if (rfcomm_check_link_mode(d)) {
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
} else
rfcomm_send_pn(s, 1, d);
}
}
}
Expand Down Expand Up @@ -1709,15 +1717,22 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)

if (test_and_clear_bit(RFCOMM_AUTH_ACCEPT, &d->flags)) {
rfcomm_dlc_clear_timer(d);
rfcomm_dlc_accept(d);
if (d->out) {
rfcomm_send_pn(s, 1, d);
rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
} else
rfcomm_dlc_accept(d);
if (d->link_mode & RFCOMM_LM_SECURE) {
struct sock *sk = s->sock->sk;
hci_conn_change_link_key(l2cap_pi(sk)->conn->hcon);
}
continue;
} else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) {
rfcomm_dlc_clear_timer(d);
rfcomm_send_dm(s, d->dlci);
if (!d->out)
rfcomm_send_dm(s, d->dlci);
else
d->state = BT_CLOSED;
__rfcomm_dlc_close(d, ECONNREFUSED);
continue;
}
Expand All @@ -1726,7 +1741,7 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
continue;

if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
d->mscex == RFCOMM_MSCEX_OK)
d->mscex == RFCOMM_MSCEX_OK)
rfcomm_process_tx(d);
}
}
Expand Down
8 changes: 5 additions & 3 deletions net/bluetooth/rfcomm/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,13 +309,13 @@ static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int
sk->sk_destruct = rfcomm_sock_destruct;
sk->sk_sndtimeo = RFCOMM_CONN_TIMEOUT;

sk->sk_sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
sk->sk_rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
sk->sk_sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
sk->sk_rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;

sock_reset_flag(sk, SOCK_ZAPPED);

sk->sk_protocol = proto;
sk->sk_state = BT_OPEN;
sk->sk_state = BT_OPEN;

bt_sock_link(&rfcomm_sk_list, sk);

Expand Down Expand Up @@ -413,6 +413,8 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
rfcomm_pi(sk)->channel = sa->rc_channel;

d->link_mode = rfcomm_pi(sk)->link_mode;

err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
if (!err)
err = bt_sock_wait_state(sk, BT_CONNECTED,
Expand Down

0 comments on commit 77db198

Please sign in to comment.