Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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.

Signed-off-by: Mateusz Jurczyk <mjurczyk@google.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

authored by

Mateusz Jurczyk and committed by
Marcel Holtmann
d2ecfa76 29e2dd0d

+7 -7
+3 -2
net/bluetooth/l2cap_sock.c
··· 87 87 88 88 BT_DBG("sk %p", sk); 89 89 90 - if (!addr || addr->sa_family != AF_BLUETOOTH) 90 + if (!addr || alen < offsetofend(struct sockaddr, sa_family) || 91 + addr->sa_family != AF_BLUETOOTH) 91 92 return -EINVAL; 92 93 93 94 memset(&la, 0, sizeof(la)); ··· 182 181 183 182 BT_DBG("sk %p", sk); 184 183 185 - if (!addr || alen < sizeof(addr->sa_family) || 184 + if (!addr || alen < offsetofend(struct sockaddr, sa_family) || 186 185 addr->sa_family != AF_BLUETOOTH) 187 186 return -EINVAL; 188 187
+2 -1
net/bluetooth/rfcomm/sock.c
··· 339 339 struct sock *sk = sock->sk; 340 340 int len, err = 0; 341 341 342 - if (!addr || addr->sa_family != AF_BLUETOOTH) 342 + if (!addr || addr_len < offsetofend(struct sockaddr, sa_family) || 343 + addr->sa_family != AF_BLUETOOTH) 343 344 return -EINVAL; 344 345 345 346 memset(&sa, 0, sizeof(sa));
+2 -4
net/bluetooth/sco.c
··· 524 524 525 525 BT_DBG("sk %p %pMR", sk, &sa->sco_bdaddr); 526 526 527 - if (!addr || addr->sa_family != AF_BLUETOOTH) 528 - return -EINVAL; 529 - 530 - if (addr_len < sizeof(struct sockaddr_sco)) 527 + if (!addr || addr_len < sizeof(struct sockaddr_sco) || 528 + addr->sa_family != AF_BLUETOOTH) 531 529 return -EINVAL; 532 530 533 531 lock_sock(sk);