summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Guenthe <guenther@cvs.openbsd.org>2009-11-21 13:05:33 +0000
committerPhilip Guenthe <guenther@cvs.openbsd.org>2009-11-21 13:05:33 +0000
commit9495e9003ab6bf557833fa1b2641293d748bcd9a (patch)
tree815ae731d25a84f7109a260d17e54c18273ae869
parentcb9e8f5ce6398bbf3a336d8b9169f5222ed6501c (diff)
User triggerable KASSERT()s and NULL dereferences in netbt setsockopt()s,
found by Clement LECIGNE, localhost DoS everywhere. Also, don't leak the mbuf when the wrong level is used. ok claudio@, "just commit" deraadt@
-rw-r--r--sys/dev/bluetooth/bthidev.c10
-rw-r--r--sys/netbt/hci_socket.c43
-rw-r--r--sys/netbt/l2cap.h7
-rw-r--r--sys/netbt/l2cap_socket.c14
-rw-r--r--sys/netbt/l2cap_upper.c60
-rw-r--r--sys/netbt/rfcomm.h6
-rw-r--r--sys/netbt/rfcomm_dlc.c4
-rw-r--r--sys/netbt/rfcomm_socket.c14
-rw-r--r--sys/netbt/rfcomm_upper.c45
-rw-r--r--sys/netbt/sco.h4
-rw-r--r--sys/netbt/sco_socket.c14
-rw-r--r--sys/netbt/sco_upper.c6
12 files changed, 135 insertions, 92 deletions
diff --git a/sys/dev/bluetooth/bthidev.c b/sys/dev/bluetooth/bthidev.c
index 32d88a637e0..9908d971d67 100644
--- a/sys/dev/bluetooth/bthidev.c
+++ b/sys/dev/bluetooth/bthidev.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bthidev.c,v 1.5 2008/11/24 08:49:22 uwe Exp $ */
+/* $OpenBSD: bthidev.c,v 1.6 2009/11/21 13:05:32 guenther Exp $ */
/* $NetBSD: bthidev.c,v 1.16 2008/08/06 15:01:23 plunky Exp $ */
/*-
@@ -451,7 +451,7 @@ bthidev_listen(struct bthidev_softc *sc)
if (err)
return err;
- err = l2cap_setopt(sc->sc_ctl_l, SO_L2CAP_LM, &sc->sc_mode);
+ err = l2cap_setlinkmode(sc->sc_ctl_l, sc->sc_mode);
if (err)
return err;
@@ -471,7 +471,7 @@ bthidev_listen(struct bthidev_softc *sc)
if (err)
return err;
- err = l2cap_setopt(sc->sc_int_l, SO_L2CAP_LM, &sc->sc_mode);
+ err = l2cap_setlinkmode(sc->sc_int_l, sc->sc_mode);
if (err)
return err;
@@ -512,7 +512,7 @@ bthidev_connect(struct bthidev_softc *sc)
return err;
}
- err = l2cap_setopt(sc->sc_ctl, SO_L2CAP_LM, &sc->sc_mode);
+ err = l2cap_setlinkmode(sc->sc_ctl, sc->sc_mode);
if (err)
return err;
@@ -570,7 +570,7 @@ bthidev_ctl_connected(void *arg)
if (err)
goto fail;
- err = l2cap_setopt(sc->sc_int, SO_L2CAP_LM, &sc->sc_mode);
+ err = l2cap_setlinkmode(sc->sc_int, sc->sc_mode);
if (err)
goto fail;
diff --git a/sys/netbt/hci_socket.c b/sys/netbt/hci_socket.c
index ca5aa5f14a3..d9d161cd185 100644
--- a/sys/netbt/hci_socket.c
+++ b/sys/netbt/hci_socket.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: hci_socket.c,v 1.7 2008/11/22 04:42:58 uwe Exp $ */
+/* $OpenBSD: hci_socket.c,v 1.8 2009/11/21 13:05:32 guenther Exp $ */
/* $NetBSD: hci_socket.c,v 1.17 2008/08/06 15:01:24 plunky Exp $ */
/*-
@@ -755,10 +755,11 @@ hci_ctloutput(int req, struct socket *so, int level,
if (pcb == NULL)
return EINVAL;
- if (level != BTPROTO_HCI)
- return ENOPROTOOPT;
-
- switch(req) {
+ if (level != BTPROTO_HCI) {
+ err = EINVAL;
+ if (req == PRCO_SETOPT && *opt)
+ m_free(*opt);
+ } else switch(req) {
case PRCO_GETOPT:
m = m_get(M_WAIT, MT_SOOPTS);
switch (optname) {
@@ -793,20 +794,36 @@ hci_ctloutput(int req, struct socket *so, int level,
m = *opt;
if (m) switch (optname) {
case SO_HCI_EVT_FILTER: /* set event filter */
- m->m_len = min(m->m_len, sizeof(struct hci_filter));
- memcpy(&pcb->hp_efilter, mtod(m, void *), m->m_len);
+ if (m == NULL || m->m_len > sizeof(struct hci_filter))
+ err = EINVAL;
+ else {
+ memcpy(&pcb->hp_efilter, mtod(m, void *),
+ m->m_len);
+ memset((char *)&pcb->hp_efilter + m->m_len,
+ 0, sizeof(struct hci_filter) - m->m_len);
+ }
break;
case SO_HCI_PKT_FILTER: /* set packet filter */
- m->m_len = min(m->m_len, sizeof(struct hci_filter));
- memcpy(&pcb->hp_pfilter, mtod(m, void *), m->m_len);
+ if (m == NULL || m->m_len > sizeof(struct hci_filter))
+ err = EINVAL;
+ else {
+ memcpy(&pcb->hp_pfilter, mtod(m, void *),
+ m->m_len);
+ memset((char *)&pcb->hp_pfilter + m->m_len,
+ 0, sizeof(struct hci_filter) - m->m_len);
+ }
break;
case SO_HCI_DIRECTION: /* request direction ctl messages */
- if (*mtod(m, int *))
- pcb->hp_flags |= HCI_DIRECTION;
- else
- pcb->hp_flags &= ~HCI_DIRECTION;
+ if (m == NULL || m->m_len != sizeof(int))
+ err = EINVAL;
+ else {
+ if (*mtod(m, int *))
+ pcb->hp_flags |= HCI_DIRECTION;
+ else
+ pcb->hp_flags &= ~HCI_DIRECTION;
+ }
break;
default:
diff --git a/sys/netbt/l2cap.h b/sys/netbt/l2cap.h
index d92c3e90348..8a9b2d52104 100644
--- a/sys/netbt/l2cap.h
+++ b/sys/netbt/l2cap.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: l2cap.h,v 1.7 2008/11/22 04:42:58 uwe Exp $ */
+/* $OpenBSD: l2cap.h,v 1.8 2009/11/21 13:05:32 guenther Exp $ */
/* $NetBSD: l2cap.h,v 1.8 2008/09/08 23:36:55 gmcgarry Exp $ */
/*-
@@ -55,7 +55,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: l2cap.h,v 1.7 2008/11/22 04:42:58 uwe Exp $
+ * $Id: l2cap.h,v 1.8 2009/11/21 13:05:32 guenther Exp $
* $FreeBSD: src/sys/netgraph/bluetooth/include/l2cap.h,v 1.4 2005/08/31 18:13:23 emax Exp $
*/
@@ -481,7 +481,8 @@ int l2cap_disconnect(struct l2cap_channel *, int);
int l2cap_detach(struct l2cap_channel **);
int l2cap_listen(struct l2cap_channel *);
int l2cap_send(struct l2cap_channel *, struct mbuf *);
-int l2cap_setopt(struct l2cap_channel *, int, void *);
+int l2cap_setlinkmode(struct l2cap_channel *, int);
+int l2cap_setopt(struct l2cap_channel *, int, struct mbuf *);
int l2cap_getopt(struct l2cap_channel *, int, void *);
#endif /* _KERNEL */
diff --git a/sys/netbt/l2cap_socket.c b/sys/netbt/l2cap_socket.c
index b67838481a6..11f3f818398 100644
--- a/sys/netbt/l2cap_socket.c
+++ b/sys/netbt/l2cap_socket.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: l2cap_socket.c,v 1.3 2008/11/22 04:42:58 uwe Exp $ */
+/* $OpenBSD: l2cap_socket.c,v 1.4 2009/11/21 13:05:32 guenther Exp $ */
/* $NetBSD: l2cap_socket.c,v 1.9 2008/08/06 15:01:24 plunky Exp $ */
/*-
@@ -278,10 +278,11 @@ l2cap_ctloutput(int req, struct socket *so, int level,
if (pcb == NULL)
return EINVAL;
- if (level != BTPROTO_L2CAP)
- return ENOPROTOOPT;
-
- switch(req) {
+ if (level != BTPROTO_L2CAP) {
+ err = EINVAL;
+ if (req == PRCO_SETOPT && *opt)
+ m_free(*opt);
+ } else switch(req) {
case PRCO_GETOPT:
m = m_get(M_WAIT, MT_SOOPTS);
m->m_len = l2cap_getopt(pcb, optname, mtod(m, void *));
@@ -295,8 +296,7 @@ l2cap_ctloutput(int req, struct socket *so, int level,
case PRCO_SETOPT:
m = *opt;
- KASSERT(m != NULL);
- err = l2cap_setopt(pcb, optname, mtod(m, void *));
+ err = l2cap_setopt(pcb, optname, m);
m_freem(m);
break;
diff --git a/sys/netbt/l2cap_upper.c b/sys/netbt/l2cap_upper.c
index 4ce612f661e..773c8e0d58c 100644
--- a/sys/netbt/l2cap_upper.c
+++ b/sys/netbt/l2cap_upper.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: l2cap_upper.c,v 1.3 2008/11/22 04:42:58 uwe Exp $ */
+/* $OpenBSD: l2cap_upper.c,v 1.4 2009/11/21 13:05:32 guenther Exp $ */
/* $NetBSD: l2cap_upper.c,v 1.9 2008/08/06 15:01:24 plunky Exp $ */
/*-
@@ -403,6 +403,26 @@ l2cap_send(struct l2cap_channel *chan, struct mbuf *m)
return 0;
}
+int
+l2cap_setlinkmode(struct l2cap_channel *chan, int mode)
+{
+ int err = 0;
+
+ mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH);
+
+ if (mode & L2CAP_LM_SECURE)
+ mode |= L2CAP_LM_ENCRYPT;
+
+ if (mode & L2CAP_LM_ENCRYPT)
+ mode |= L2CAP_LM_AUTH;
+
+ chan->lc_mode = mode;
+
+ if (chan->lc_state == L2CAP_OPEN)
+ err = l2cap_setmode(chan);
+ return (err);
+}
+
/*
* l2cap_setopt(l2cap_channel, opt, addr)
*
@@ -417,37 +437,33 @@ l2cap_send(struct l2cap_channel *chan, struct mbuf *m)
* will be made when the change is complete.
*/
int
-l2cap_setopt(struct l2cap_channel *chan, int opt, void *addr)
+l2cap_setopt(struct l2cap_channel *chan, int opt, struct mbuf *m)
{
- int mode, err = 0;
+ int err = 0;
uint16_t mtu;
switch (opt) {
case SO_L2CAP_IMTU: /* set Incoming MTU */
- mtu = *(uint16_t *)addr;
- if (mtu < L2CAP_MTU_MINIMUM)
+ if (m == NULL || m->m_len != sizeof(uint16_t))
err = EINVAL;
- else if (chan->lc_state == L2CAP_CLOSED)
- chan->lc_imtu = mtu;
- else
- err = EBUSY;
+ else {
+ mtu = *mtod(m, uint16_t *);
+ if (mtu < L2CAP_MTU_MINIMUM)
+ err = EINVAL;
+ else if (chan->lc_state == L2CAP_CLOSED)
+ chan->lc_imtu = mtu;
+ else
+ err = EBUSY;
+ }
break;
case SO_L2CAP_LM: /* set link mode */
- mode = *(int *)addr;
- mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH);
-
- if (mode & L2CAP_LM_SECURE)
- mode |= L2CAP_LM_ENCRYPT;
-
- if (mode & L2CAP_LM_ENCRYPT)
- mode |= L2CAP_LM_AUTH;
-
- chan->lc_mode = mode;
-
- if (chan->lc_state == L2CAP_OPEN)
- err = l2cap_setmode(chan);
+ if (m == NULL || m->m_len != sizeof(int))
+ err = EINVAL;
+ else {
+ err = l2cap_setlinkmode(chan, *mtod(m, int *));
+ }
break;
diff --git a/sys/netbt/rfcomm.h b/sys/netbt/rfcomm.h
index 2b82380c865..ba7149e3ef3 100644
--- a/sys/netbt/rfcomm.h
+++ b/sys/netbt/rfcomm.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rfcomm.h,v 1.4 2008/11/22 04:42:58 uwe Exp $ */
+/* $OpenBSD: rfcomm.h,v 1.5 2009/11/21 13:05:32 guenther Exp $ */
/* $NetBSD: rfcomm.h,v 1.8 2008/09/08 23:36:55 gmcgarry Exp $ */
/*-
@@ -56,7 +56,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: rfcomm.h,v 1.4 2008/11/22 04:42:58 uwe Exp $
+ * $Id: rfcomm.h,v 1.5 2009/11/21 13:05:32 guenther Exp $
* $FreeBSD: src/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h,v 1.4 2005/01/11 01:39:53 emax Exp $
*/
@@ -419,7 +419,7 @@ int rfcomm_detach(struct rfcomm_dlc **);
int rfcomm_listen(struct rfcomm_dlc *);
int rfcomm_send(struct rfcomm_dlc *, struct mbuf *);
int rfcomm_rcvd(struct rfcomm_dlc *, size_t);
-int rfcomm_setopt(struct rfcomm_dlc *, int, void *);
+int rfcomm_setopt(struct rfcomm_dlc *, int, struct mbuf *);
int rfcomm_getopt(struct rfcomm_dlc *, int, void *);
#endif /* _KERNEL */
diff --git a/sys/netbt/rfcomm_dlc.c b/sys/netbt/rfcomm_dlc.c
index 7777b2b18cb..843474c8ca1 100644
--- a/sys/netbt/rfcomm_dlc.c
+++ b/sys/netbt/rfcomm_dlc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rfcomm_dlc.c,v 1.4 2008/11/22 04:42:58 uwe Exp $ */
+/* $OpenBSD: rfcomm_dlc.c,v 1.5 2009/11/21 13:05:32 guenther Exp $ */
/* $NetBSD: rfcomm_dlc.c,v 1.6 2008/08/06 15:01:24 plunky Exp $ */
/*-
@@ -232,7 +232,7 @@ rfcomm_dlc_setmode(struct rfcomm_dlc *dlc)
if (dlc->rd_mode & RFCOMM_LM_SECURE)
mode |= L2CAP_LM_SECURE;
- return l2cap_setopt(dlc->rd_session->rs_l2cap, SO_L2CAP_LM, &mode);
+ return l2cap_setlinkmode(dlc->rd_session->rs_l2cap, mode);
}
/*
diff --git a/sys/netbt/rfcomm_socket.c b/sys/netbt/rfcomm_socket.c
index 1ade1aacc99..951d15fe5dc 100644
--- a/sys/netbt/rfcomm_socket.c
+++ b/sys/netbt/rfcomm_socket.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rfcomm_socket.c,v 1.4 2008/11/22 04:42:58 uwe Exp $ */
+/* $OpenBSD: rfcomm_socket.c,v 1.5 2009/11/21 13:05:32 guenther Exp $ */
/* $NetBSD: rfcomm_socket.c,v 1.10 2008/08/06 15:01:24 plunky Exp $ */
/*-
@@ -277,10 +277,11 @@ rfcomm_ctloutput(int req, struct socket *so, int level,
if (pcb == NULL)
return EINVAL;
- if (level != BTPROTO_RFCOMM)
- return ENOPROTOOPT;
-
- switch(req) {
+ if (level != BTPROTO_RFCOMM) {
+ err = EINVAL;
+ if (req == PRCO_SETOPT && *opt)
+ m_free(*opt);
+ } else switch(req) {
case PRCO_GETOPT:
m = m_get(M_WAIT, MT_SOOPTS);
m->m_len = rfcomm_getopt(pcb, optname, mtod(m, void *));
@@ -294,8 +295,7 @@ rfcomm_ctloutput(int req, struct socket *so, int level,
case PRCO_SETOPT:
m = *opt;
- KASSERT(m != NULL);
- err = rfcomm_setopt(pcb, optname, mtod(m, void *));
+ err = rfcomm_setopt(pcb, optname, m);
m_freem(m);
break;
diff --git a/sys/netbt/rfcomm_upper.c b/sys/netbt/rfcomm_upper.c
index b6b95feba5b..19635350362 100644
--- a/sys/netbt/rfcomm_upper.c
+++ b/sys/netbt/rfcomm_upper.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rfcomm_upper.c,v 1.6 2008/11/22 04:42:58 uwe Exp $ */
+/* $OpenBSD: rfcomm_upper.c,v 1.7 2009/11/21 13:05:32 guenther Exp $ */
/* $NetBSD: rfcomm_upper.c,v 1.11 2008/08/06 15:01:24 plunky Exp $ */
/*-
@@ -429,42 +429,51 @@ rfcomm_rcvd(struct rfcomm_dlc *dlc, size_t space)
}
/*
- * rfcomm_setopt(dlc, option, addr)
+ * rfcomm_setopt(dlc, option, m)
*
* set DLC options
*/
int
-rfcomm_setopt(struct rfcomm_dlc *dlc, int opt, void *addr)
+rfcomm_setopt(struct rfcomm_dlc *dlc, int opt, struct mbuf *m)
{
int mode, err = 0;
uint16_t mtu;
switch (opt) {
case SO_RFCOMM_MTU:
- mtu = *(uint16_t *)addr;
- if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
+ if (m == NULL || m->m_len != sizeof(uint16_t))
err = EINVAL;
- else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
- dlc->rd_mtu = mtu;
- else
- err = EBUSY;
+ else {
+ mtu = *mtod(m, uint16_t *);
+ if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
+ err = EINVAL;
+ else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
+ dlc->rd_mtu = mtu;
+ else
+ err = EBUSY;
+ }
break;
case SO_RFCOMM_LM:
- mode = *(int *)addr;
- mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
+ if (m == NULL || m->m_len != sizeof(int))
+ err = EINVAL;
+ else {
+ mode = *mtod(m, int *);
+ mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT |
+ RFCOMM_LM_AUTH);
- if (mode & RFCOMM_LM_SECURE)
- mode |= RFCOMM_LM_ENCRYPT;
+ if (mode & RFCOMM_LM_SECURE)
+ mode |= RFCOMM_LM_ENCRYPT;
- if (mode & RFCOMM_LM_ENCRYPT)
- mode |= RFCOMM_LM_AUTH;
+ if (mode & RFCOMM_LM_ENCRYPT)
+ mode |= RFCOMM_LM_AUTH;
- dlc->rd_mode = mode;
+ dlc->rd_mode = mode;
- if (dlc->rd_state == RFCOMM_DLC_OPEN)
- err = rfcomm_dlc_setmode(dlc);
+ if (dlc->rd_state == RFCOMM_DLC_OPEN)
+ err = rfcomm_dlc_setmode(dlc);
+ }
break;
diff --git a/sys/netbt/sco.h b/sys/netbt/sco.h
index 80692420a9c..b93fee7f0f5 100644
--- a/sys/netbt/sco.h
+++ b/sys/netbt/sco.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sco.h,v 1.4 2008/11/22 04:42:58 uwe Exp $ */
+/* $OpenBSD: sco.h,v 1.5 2009/11/21 13:05:32 guenther Exp $ */
/* $NetBSD: sco.h,v 1.3 2008/08/06 15:01:24 plunky Exp $ */
/*-
@@ -78,7 +78,7 @@ int sco_disconnect(struct sco_pcb *, int);
int sco_detach(struct sco_pcb **);
int sco_listen(struct sco_pcb *);
int sco_send(struct sco_pcb *, struct mbuf *);
-int sco_setopt(struct sco_pcb *, int, void *);
+int sco_setopt(struct sco_pcb *, int, struct mbuf *);
int sco_getopt(struct sco_pcb *, int, void *);
#endif /* _KERNEL */
diff --git a/sys/netbt/sco_socket.c b/sys/netbt/sco_socket.c
index 0ee635d4f13..766f5e384e5 100644
--- a/sys/netbt/sco_socket.c
+++ b/sys/netbt/sco_socket.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sco_socket.c,v 1.3 2008/11/22 04:42:58 uwe Exp $ */
+/* $OpenBSD: sco_socket.c,v 1.4 2009/11/21 13:05:32 guenther Exp $ */
/* $NetBSD: sco_socket.c,v 1.11 2008/08/06 15:01:24 plunky Exp $ */
/*-
@@ -264,10 +264,11 @@ sco_ctloutput(int req, struct socket *so, int level,
if (pcb == NULL)
return EINVAL;
- if (level != BTPROTO_SCO)
- return ENOPROTOOPT;
-
- switch(req) {
+ if (level != BTPROTO_SCO) {
+ err = EINVAL;
+ if (req == PRCO_SETOPT && *opt)
+ m_free(*opt);
+ } else switch(req) {
case PRCO_GETOPT:
m = m_get(M_WAIT, MT_SOOPTS);
m->m_len = sco_getopt(pcb, optname, mtod(m, uint8_t *));
@@ -281,8 +282,7 @@ sco_ctloutput(int req, struct socket *so, int level,
case PRCO_SETOPT:
m = *opt;
- KASSERT(m != NULL);
- err = sco_setopt(pcb, optname, mtod(m, uint8_t *));
+ err = sco_setopt(pcb, optname, m);
m_freem(m);
break;
diff --git a/sys/netbt/sco_upper.c b/sys/netbt/sco_upper.c
index f53585d7303..a4c16b40fe9 100644
--- a/sys/netbt/sco_upper.c
+++ b/sys/netbt/sco_upper.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sco_upper.c,v 1.3 2008/11/22 04:42:58 uwe Exp $ */
+/* $OpenBSD: sco_upper.c,v 1.4 2009/11/21 13:05:32 guenther Exp $ */
/* $NetBSD: sco_upper.c,v 1.8 2008/08/06 15:01:24 plunky Exp $ */
/*-
@@ -310,12 +310,12 @@ sco_send(struct sco_pcb *pcb, struct mbuf *m)
}
/*
- * sco_setopt(pcb, option, addr)
+ * sco_setopt(pcb, option, m)
*
* Set SCO pcb options
*/
int
-sco_setopt(struct sco_pcb *pcb, int opt, void *addr)
+sco_setopt(struct sco_pcb *pcb, int opt, struct mbuf *m)
{
int err = 0;