diff options
author | Philip Guenthe <guenther@cvs.openbsd.org> | 2009-11-21 13:05:33 +0000 |
---|---|---|
committer | Philip Guenthe <guenther@cvs.openbsd.org> | 2009-11-21 13:05:33 +0000 |
commit | 9495e9003ab6bf557833fa1b2641293d748bcd9a (patch) | |
tree | 815ae731d25a84f7109a260d17e54c18273ae869 | |
parent | cb9e8f5ce6398bbf3a336d8b9169f5222ed6501c (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.c | 10 | ||||
-rw-r--r-- | sys/netbt/hci_socket.c | 43 | ||||
-rw-r--r-- | sys/netbt/l2cap.h | 7 | ||||
-rw-r--r-- | sys/netbt/l2cap_socket.c | 14 | ||||
-rw-r--r-- | sys/netbt/l2cap_upper.c | 60 | ||||
-rw-r--r-- | sys/netbt/rfcomm.h | 6 | ||||
-rw-r--r-- | sys/netbt/rfcomm_dlc.c | 4 | ||||
-rw-r--r-- | sys/netbt/rfcomm_socket.c | 14 | ||||
-rw-r--r-- | sys/netbt/rfcomm_upper.c | 45 | ||||
-rw-r--r-- | sys/netbt/sco.h | 4 | ||||
-rw-r--r-- | sys/netbt/sco_socket.c | 14 | ||||
-rw-r--r-- | sys/netbt/sco_upper.c | 6 |
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; |