diff options
| author | Johan Hedberg <johan.hedberg@intel.com> | 2013-10-08 07:55:46 -0400 |
|---|---|---|
| committer | Marcel Holtmann <marcel@holtmann.org> | 2013-12-05 10:05:36 -0500 |
| commit | 4946096d43d1d02fb07cc80f82e1747b01571c41 (patch) | |
| tree | 0e18aaed28800e7c4e6ae8b591703742d7eac66a | |
| parent | e77af7559238895ec5fd1706762e1c9f890dcc7e (diff) | |
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>
| -rw-r--r-- | net/bluetooth/l2cap_core.c | 15 | ||||
| -rw-r--r-- | net/bluetooth/l2cap_sock.c | 40 |
2 files changed, 44 insertions, 11 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 76ebd18ff968..5941c65728b2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
| @@ -1861,6 +1861,18 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, | |||
| 1861 | return c1; | 1861 | return c1; |
| 1862 | } | 1862 | } |
| 1863 | 1863 | ||
| 1864 | static bool is_valid_psm(u16 psm, u8 dst_type) | ||
| 1865 | { | ||
| 1866 | if (!psm) | ||
| 1867 | return false; | ||
| 1868 | |||
| 1869 | if (bdaddr_type_is_le(dst_type)) | ||
| 1870 | return (psm < 0x00ff); | ||
| 1871 | |||
| 1872 | /* PSM must be odd and lsb of upper byte must be 0 */ | ||
| 1873 | return ((psm & 0x0101) == 0x0001); | ||
| 1874 | } | ||
| 1875 | |||
| 1864 | int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, | 1876 | int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, |
| 1865 | bdaddr_t *dst, u8 dst_type) | 1877 | bdaddr_t *dst, u8 dst_type) |
| 1866 | { | 1878 | { |
| @@ -1881,8 +1893,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, | |||
| 1881 | 1893 | ||
| 1882 | l2cap_chan_lock(chan); | 1894 | l2cap_chan_lock(chan); |
| 1883 | 1895 | ||
| 1884 | /* PSM must be odd and lsb of upper byte must be 0 */ | 1896 | if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid && |
| 1885 | if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid && | ||
| 1886 | chan->chan_type != L2CAP_CHAN_RAW) { | 1897 | chan->chan_type != L2CAP_CHAN_RAW) { |
| 1887 | err = -EINVAL; | 1898 | err = -EINVAL; |
| 1888 | goto done; | 1899 | goto done; |
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) | |||
| 53 | } | 53 | } |
| 54 | EXPORT_SYMBOL(l2cap_is_socket); | 54 | EXPORT_SYMBOL(l2cap_is_socket); |
| 55 | 55 | ||
| 56 | static int l2cap_validate_bredr_psm(u16 psm) | ||
| 57 | { | ||
| 58 | /* PSM must be odd and lsb of upper byte must be 0 */ | ||
| 59 | if ((psm & 0x0101) != 0x0001) | ||
| 60 | return -EINVAL; | ||
| 61 | |||
| 62 | /* Restrict usage of well-known PSMs */ | ||
| 63 | if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) | ||
| 64 | return -EACCES; | ||
| 65 | |||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | static int l2cap_validate_le_psm(u16 psm) | ||
| 70 | { | ||
| 71 | /* Valid LE_PSM ranges are defined only until 0x00ff */ | ||
| 72 | if (psm > 0x00ff) | ||
| 73 | return -EINVAL; | ||
| 74 | |||
| 75 | /* Restrict fixed, SIG assigned PSM values to CAP_NET_BIND_SERVICE */ | ||
| 76 | if (psm <= 0x007f && !capable(CAP_NET_BIND_SERVICE)) | ||
| 77 | return -EACCES; | ||
| 78 | |||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | |||
| 56 | static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) | 82 | static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) |
| 57 | { | 83 | { |
| 58 | struct sock *sk = sock->sk; | 84 | struct sock *sk = sock->sk; |
| @@ -94,17 +120,13 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) | |||
| 94 | if (la.l2_psm) { | 120 | if (la.l2_psm) { |
| 95 | __u16 psm = __le16_to_cpu(la.l2_psm); | 121 | __u16 psm = __le16_to_cpu(la.l2_psm); |
| 96 | 122 | ||
| 97 | /* PSM must be odd and lsb of upper byte must be 0 */ | 123 | if (la.l2_bdaddr_type == BDADDR_BREDR) |
| 98 | if ((psm & 0x0101) != 0x0001) { | 124 | err = l2cap_validate_bredr_psm(psm); |
| 99 | err = -EINVAL; | 125 | else |
| 100 | goto done; | 126 | err = l2cap_validate_le_psm(psm); |
| 101 | } | ||
| 102 | 127 | ||
| 103 | /* Restrict usage of well-known PSMs */ | 128 | if (err) |
| 104 | if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) { | ||
| 105 | err = -EACCES; | ||
| 106 | goto done; | 129 | goto done; |
| 107 | } | ||
| 108 | } | 130 | } |
| 109 | 131 | ||
| 110 | if (la.l2_cid) | 132 | if (la.l2_cid) |
