summaryrefslogtreecommitdiff
path: root/net/bluetooth/l2cap_sock.c
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2013-10-08 15:55:46 +0400
committerMarcel Holtmann <marcel@holtmann.org>2013-12-05 19:05:36 +0400
commit4946096d43d1d02fb07cc80f82e1747b01571c41 (patch)
tree0e18aaed28800e7c4e6ae8b591703742d7eac66a /net/bluetooth/l2cap_sock.c
parente77af7559238895ec5fd1706762e1c9f890dcc7e (diff)
downloadlinux-4946096d43d1d02fb07cc80f82e1747b01571c41.tar.xz
Bluetooth: Fix validating LE PSM values
LE PSM values have different ranges than those for BR/EDR. The valid ranges for fixed, SIG assigned values is 0x0001-0x007f and for dynamic PSM values 0x0080-0x00ff. We need to ensure that bind() and connect() calls conform to these ranges when operating on LE CoC sockets. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap_sock.c')
-rw-r--r--net/bluetooth/l2cap_sock.c40
1 files changed, 31 insertions, 9 deletions
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index a51844a8c5eb..88fa9c07c503 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -53,6 +53,32 @@ bool l2cap_is_socket(struct socket *sock)
}
EXPORT_SYMBOL(l2cap_is_socket);
+static int l2cap_validate_bredr_psm(u16 psm)
+{
+ /* PSM must be odd and lsb of upper byte must be 0 */
+ if ((psm & 0x0101) != 0x0001)
+ return -EINVAL;
+
+ /* Restrict usage of well-known PSMs */
+ if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE))
+ return -EACCES;
+
+ return 0;
+}
+
+static int l2cap_validate_le_psm(u16 psm)
+{
+ /* Valid LE_PSM ranges are defined only until 0x00ff */
+ if (psm > 0x00ff)
+ return -EINVAL;
+
+ /* Restrict fixed, SIG assigned PSM values to CAP_NET_BIND_SERVICE */
+ if (psm <= 0x007f && !capable(CAP_NET_BIND_SERVICE))
+ return -EACCES;
+
+ return 0;
+}
+
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
{
struct sock *sk = sock->sk;
@@ -94,17 +120,13 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
if (la.l2_psm) {
__u16 psm = __le16_to_cpu(la.l2_psm);
- /* PSM must be odd and lsb of upper byte must be 0 */
- if ((psm & 0x0101) != 0x0001) {
- err = -EINVAL;
- goto done;
- }
+ if (la.l2_bdaddr_type == BDADDR_BREDR)
+ err = l2cap_validate_bredr_psm(psm);
+ else
+ err = l2cap_validate_le_psm(psm);
- /* Restrict usage of well-known PSMs */
- if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) {
- err = -EACCES;
+ if (err)
goto done;
- }
}
if (la.l2_cid)