Bluetooth: hidp: verify l2cap sockets

commit b3916db32c upstream.

We need to verify that the given sockets actually are l2cap sockets. If
they aren't, we are not supposed to access bt_sk(sock) and we shouldn't
start the session if the offsets turn out to be valid local BT addresses.

That is, if someone passes a TCP socket to HIDCONNADD, then we access some
random offset in the TCP socket (which isn't even guaranteed to be valid).

Fix this by checking that the socket is an l2cap socket.

Change-Id: I401bca741588b34876a1c835d8d4567852b4ec75
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
This commit is contained in:
David Herrmann 2013-04-05 14:57:34 +02:00 committed by Artem Borisov
parent 3384f8b286
commit 1528eb776d
3 changed files with 9 additions and 0 deletions

View file

@ -667,6 +667,7 @@ extern struct bt_sock_list l2cap_sk_list;
int l2cap_init_sockets(void); int l2cap_init_sockets(void);
void l2cap_cleanup_sockets(void); void l2cap_cleanup_sockets(void);
bool l2cap_is_socket(struct socket *sock);
u8 l2cap_get_ident(struct l2cap_conn *conn); u8 l2cap_get_ident(struct l2cap_conn *conn);
void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data);

View file

@ -834,6 +834,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
BT_DBG(""); BT_DBG("");
if (!l2cap_is_socket(ctrl_sock) || !l2cap_is_socket(intr_sock))
return -EINVAL;
if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) || if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst)) bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
return -ENOTUNIQ; return -ENOTUNIQ;

View file

@ -124,6 +124,12 @@ found:
return sk; return sk;
} }
bool l2cap_is_socket(struct socket *sock)
{
return sock && sock->ops == &l2cap_sock_ops;
}
EXPORT_SYMBOL(l2cap_is_socket);
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;