From 09c8028e8e61e6c9dfb008d608f1a719eb02e985 Mon Sep 17 00:00:00 2001 From: Mateusz Jurczyk Date: Thu, 29 Jun 2017 14:04:59 +0200 Subject: [PATCH] Bluetooth: Add sockaddr length checks before accessing sa_family in bind and connect handlers Verify that the caller-provided sockaddr structure is large enough to contain the sa_family field, before accessing it in bind() and connect() handlers of the Bluetooth sockets. Since neither syscall enforces a minimum size of the corresponding memory region, very short sockaddrs (zero or one byte long) result in operating on uninitialized memory while referencing sa_family. Change-Id: I3c3bf3c9fa16abfb65f41e55c89c1ffcce2f58e7 Signed-off-by: Mateusz Jurczyk Signed-off-by: Marcel Holtmann Signed-off-by: Kevin F. Haggerty --- include/linux/stddef.h | 9 +++++++++ net/bluetooth/l2cap_sock.c | 5 +++-- net/bluetooth/rfcomm/sock.c | 3 ++- net/bluetooth/sco.c | 3 ++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/linux/stddef.h b/include/linux/stddef.h index 1747b6787b9..4998515d3ea 100644 --- a/include/linux/stddef.h +++ b/include/linux/stddef.h @@ -21,4 +21,13 @@ enum { #endif #endif /* __KERNEL__ */ +/** + * offsetofend(TYPE, MEMBER) + * + * @TYPE: The type of the structure + * @MEMBER: The member within the structure to get the end offset of + */ +#define offsetofend(TYPE, MEMBER) \ + (offsetof(TYPE, MEMBER) + sizeof(((TYPE *)0)->MEMBER)) + #endif diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index baf1af7b0c0..9cd15f1ae98 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -132,7 +132,8 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) BT_DBG("sk %p", sk); - if (!addr || addr->sa_family != AF_BLUETOOTH) + if (!addr || alen < offsetofend(struct sockaddr, sa_family) || + addr->sa_family != AF_BLUETOOTH) return -EINVAL; memset(&la, 0, sizeof(la)); @@ -200,7 +201,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al BT_DBG("sk %p type %d mode %d state %d", sk, sk->sk_type, l2cap_pi(sk)->mode, sk->sk_state); - if (!addr || alen < sizeof(addr->sa_family) || + if (!addr || alen < offsetofend(struct sockaddr, sa_family) || addr->sa_family != AF_BLUETOOTH) return -EINVAL; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index ed4637cbcb6..36288ebcad8 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -350,7 +350,8 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr struct sock *sk = sock->sk; int len, err = 0; - if (!addr || addr->sa_family != AF_BLUETOOTH) + if (!addr || addr_len < offsetofend(struct sockaddr, sa_family) || + addr->sa_family != AF_BLUETOOTH) return -EINVAL; memset(&sa, 0, sizeof(sa)); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index d1fb5d21e37..f671da4dcdd 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -497,7 +497,8 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) BT_DBG("sk %p %s", sk, batostr(&sa.sco_bdaddr)); - if (!addr || addr->sa_family != AF_BLUETOOTH) + if (!addr || alen < sizeof(struct sockaddr_sco) || + addr->sa_family != AF_BLUETOOTH) return -EINVAL; if (alen < sizeof(struct sockaddr_sco))