>From 0b28c2c7d0fa9df936995019522f887e9d743ef2 Mon Sep 17 00:00:00 2001 From: Ville Tervo Date: Mon, 22 Dec 2008 15:22:23 +0200 Subject: [PATCH 2/7] bluetooth: Introduce security levels This patch introduces security levels for RFCOMM sockets. --- include/net/bluetooth/bluetooth.h | 9 +++++++++ include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/l2cap.h | 2 ++ include/net/bluetooth/rfcomm.h | 2 ++ net/bluetooth/rfcomm/core.c | 36 ++++++++++++++++++++++++++++++++---- net/bluetooth/rfcomm/sock.c | 34 +++++++++++++++++++++++++++++++++- 6 files changed, 79 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 1a0fa21..b5af61c 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -57,6 +57,15 @@ #define BT_DEFER_SETUP 0x02 +#define BT_SECURITY 0x03 +struct bt_security { + __u8 level; +}; +#define BT_SECURITY_SDP 0 +#define BT_SECURITY_LOW 1 +#define BT_SECURITY_MEDIUM 2 +#define BT_SECURITY_HIGH 3 + #define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg) #define BT_DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" , __FUNCTION__ , ## arg) #define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __FUNCTION__ , ## arg) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 019cd93..419c518 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -169,6 +169,7 @@ struct hci_conn { __u16 link_policy; __u32 link_mode; __u8 auth_type; + __u8 seclevel; __u8 power_save; unsigned long pend; diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 73e115b..a178778 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -234,10 +234,12 @@ struct l2cap_pinfo { __u16 dcid; __u16 scid; + __u8 seclevel; __u16 imtu; __u16 omtu; __u16 flush_to; + __u32 defer_setup; __u32 link_mode; __u8 conf_req[64]; diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index eaa1365..7161def 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -186,6 +186,7 @@ struct rfcomm_dlc { u32 defer_setup; u32 link_mode; + u8 seclevel; uint mtu; uint cfc; @@ -309,6 +310,7 @@ struct rfcomm_pinfo { u8 channel; u32 link_mode; u32 defer_setup; + u8 seclevel; }; int rfcomm_init_sockets(void); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 7878e3c..f0cd6ee 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -239,6 +239,20 @@ static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d) { struct sock *sk = d->session->sock->sk; + if (d->seclevel == BT_SECURITY_HIGH) + if (!hci_conn_auth(l2cap_pi(sk)->conn->hcon)) + return 1; + + if (d->seclevel == BT_SECURITY_MEDIUM) + if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon)) + return 1; + + if (d->seclevel == BT_SECURITY_LOW) + if (l2cap_pi(sk)->conn->hcon->hdev->ssp_mode > 0 && + l2cap_pi(sk)->conn->hcon->ssp_mode > 0) + if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon)) + return 1; + if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) { if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon)) return 1; @@ -2007,17 +2021,21 @@ static void rfcomm_auth_cfm(struct hci_conn *conn, u8 status) list_for_each_safe(p, n, &s->dlcs) { d = list_entry(p, struct rfcomm_dlc, list); + if (d->seclevel == BT_SECURITY_HIGH || + d->seclevel == BT_SECURITY_MEDIUM) + continue; + if ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) && - !(conn->link_mode & HCI_LM_ENCRYPT) && !status) + (conn->link_mode & HCI_LM_ENCRYPT) && !status) continue; if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags)) continue; - if (!status) - set_bit(RFCOMM_AUTH_ACCEPT, &d->flags); - else + if (status) set_bit(RFCOMM_AUTH_REJECT, &d->flags); + else + set_bit(RFCOMM_AUTH_ACCEPT, &d->flags); } rfcomm_session_put(s); @@ -2030,6 +2048,7 @@ static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt) struct rfcomm_session *s; struct rfcomm_dlc *d; struct list_head *p, *n; + int sec; BT_DBG("conn %p status 0x%02x encrypt 0x%02x", conn, status, encrypt); @@ -2041,6 +2060,15 @@ static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt) list_for_each_safe(p, n, &s->dlcs) { d = list_entry(p, struct rfcomm_dlc, list); + sec = d->seclevel; + + if ((sec == BT_SECURITY_HIGH || sec == BT_SECURITY_MEDIUM) && + (d->state == BT_CONNECTED || + d->state == BT_CONFIG) && + !status && encrypt == 0x00) { + __rfcomm_dlc_close(d, ECONNREFUSED); + continue; + } if ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) && (d->state == BT_CONNECTED || diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 0ffe813..cb4f7ba 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -268,13 +268,16 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent) sk->sk_type = parent->sk_type; pi->link_mode = rfcomm_pi(parent)->link_mode; pi->defer_setup = rfcomm_pi(parent)->defer_setup; + pi->seclevel = rfcomm_pi(parent)->seclevel; } else { pi->link_mode = 0; pi->defer_setup = 0; + pi->seclevel = BT_SECURITY_LOW; } pi->dlc->link_mode = pi->link_mode; pi->dlc->defer_setup = pi->defer_setup; + pi->dlc->seclevel = pi->seclevel; } static struct proto rfcomm_proto = { @@ -415,6 +418,7 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a rfcomm_pi(sk)->channel = sa->rc_channel; d->link_mode = rfcomm_pi(sk)->link_mode; + d->link_mode = rfcomm_pi(sk)->seclevel; err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel); if (!err) @@ -728,7 +732,8 @@ out: static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) { struct sock *sk = sock->sk; - int err = 0; + struct bt_security sec; + int len, err = 0; u32 opt; BT_DBG("sk %p", sk); @@ -737,6 +742,23 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c if (level == SOL_BLUETOOTH) { switch (optname) { + case BT_SECURITY: + sec.level = BT_SECURITY_LOW; + + len = min_t(unsigned int, sizeof(sec), optlen); + if (copy_from_user((char *) &sec, optval, len)) { + err = -EFAULT; + break; + } + + if (sec.level > 3) { + err = -EINVAL; + break; + } + + rfcomm_pi(sk)->seclevel = sec.level; + break; + case BT_DEFER_SETUP: if (get_user(opt, (u32 __user *) optval)) { err = -EFAULT; @@ -775,6 +797,7 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; + struct bt_security sec; struct sock *l2cap_sk; struct rfcomm_conninfo cinfo; int len, err = 0; @@ -816,6 +839,15 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c } } else if (level == SOL_BLUETOOTH) { switch (optname) { + case BT_SECURITY: + sec.level = rfcomm_pi(sk)->seclevel; + + len = min_t(unsigned int, len, sizeof(sec)); + if (copy_to_user(optval, (char *) &sec, len)) + err = -EFAULT; + + break; + case BT_DEFER_SETUP: if (put_user(rfcomm_pi(sk)->defer_setup, (u32 __user *) optval)) err = -EFAULT; -- 1.6.0.4