From a1fdf6646b16ec26c741089102346f5455dc5fed Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Wed, 28 Apr 2021 21:17:19 -0400 Subject: if_wg: do not double-free after m_pullup Either m_pullup reallocates, in which case wg_packet_free winds up freeing something that's already been freed, or it fails and frees m, and then wg_packet_free tries to free it again. In both cases, massive memory corruption ensues. Signed-off-by: Jason A. Donenfeld --- src/if_wg.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/if_wg.c b/src/if_wg.c index 8eb142e..cde9511 100644 --- a/src/if_wg.c +++ b/src/if_wg.c @@ -1305,9 +1305,7 @@ wg_handshake(struct wg_softc *sc, struct wg_packet *pkt) struct wg_pkt_initiation *init; struct wg_pkt_response *resp; struct wg_pkt_cookie *cook; - struct wg_endpoint *e; struct wg_peer *peer; - struct mbuf *m; struct noise_remote *remote = NULL; int res; bool underload = false; @@ -1322,19 +1320,16 @@ wg_handshake(struct wg_softc *sc, struct wg_packet *pkt) wg_last_underload = 0; } - m = pkt->p_mbuf; - e = &pkt->p_endpoint; - - if ((m = m_pullup(m, m->m_pkthdr.len)) == NULL) + if ((pkt->p_mbuf = m_pullup(pkt->p_mbuf, pkt->p_mbuf->m_pkthdr.len)) == NULL) goto error; - switch (*mtod(m, uint32_t *)) { + switch (*mtod(pkt->p_mbuf, uint32_t *)) { case WG_PKT_INITIATION: - init = mtod(m, struct wg_pkt_initiation *); + init = mtod(pkt->p_mbuf, struct wg_pkt_initiation *); res = cookie_checker_validate_macs(&sc->sc_cookie, &init->m, init, sizeof(*init) - sizeof(init->m), - underload, &e->e_remote.r_sa, + underload, &pkt->p_endpoint.e_remote.r_sa, sc->sc_ifp->if_vnet); if (res == EINVAL) { @@ -1344,7 +1339,7 @@ wg_handshake(struct wg_softc *sc, struct wg_packet *pkt) DPRINTF(sc, "Handshake ratelimited\n"); goto error; } else if (res == EAGAIN) { - wg_send_cookie(sc, &init->m, init->s_idx, e); + wg_send_cookie(sc, &init->m, init->s_idx, &pkt->p_endpoint); goto error; } else if (res != 0) { panic("unexpected response: %d\n", res); @@ -1360,15 +1355,15 @@ wg_handshake(struct wg_softc *sc, struct wg_packet *pkt) DPRINTF(sc, "Receiving handshake initiation from peer %" PRIu64 "\n", peer->p_id); - wg_peer_set_endpoint(peer, e); + wg_peer_set_endpoint(peer, &pkt->p_endpoint); wg_send_response(peer); break; case WG_PKT_RESPONSE: - resp = mtod(m, struct wg_pkt_response *); + resp = mtod(pkt->p_mbuf, struct wg_pkt_response *); res = cookie_checker_validate_macs(&sc->sc_cookie, &resp->m, resp, sizeof(*resp) - sizeof(resp->m), - underload, &e->e_remote.r_sa, + underload, &pkt->p_endpoint.e_remote.r_sa, sc->sc_ifp->if_vnet); if (res == EINVAL) { @@ -1378,7 +1373,7 @@ wg_handshake(struct wg_softc *sc, struct wg_packet *pkt) DPRINTF(sc, "Handshake ratelimited\n"); goto error; } else if (res == EAGAIN) { - wg_send_cookie(sc, &resp->m, resp->s_idx, e); + wg_send_cookie(sc, &resp->m, resp->s_idx, &pkt->p_endpoint); goto error; } else if (res != 0) { panic("unexpected response: %d\n", res); @@ -1393,12 +1388,12 @@ wg_handshake(struct wg_softc *sc, struct wg_packet *pkt) peer = noise_remote_arg(remote); DPRINTF(sc, "Receiving handshake response from peer %" PRIu64 "\n", peer->p_id); - wg_peer_set_endpoint(peer, e); + wg_peer_set_endpoint(peer, &pkt->p_endpoint); wg_timers_event_session_derived(peer); wg_timers_event_handshake_complete(peer); break; case WG_PKT_COOKIE: - cook = mtod(m, struct wg_pkt_cookie *); + cook = mtod(pkt->p_mbuf, struct wg_pkt_cookie *); if ((remote = noise_remote_index(sc->sc_local, cook->r_idx)) == NULL) { DPRINTF(sc, "Unknown cookie index\n"); @@ -1424,9 +1419,9 @@ wg_handshake(struct wg_softc *sc, struct wg_packet *pkt) wg_timers_event_any_authenticated_packet_traversal(peer); not_authenticated: - counter_u64_add(peer->p_rx_bytes, m->m_pkthdr.len); + counter_u64_add(peer->p_rx_bytes, pkt->p_mbuf->m_pkthdr.len); if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1); - if_inc_counter(sc->sc_ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); + if_inc_counter(sc->sc_ifp, IFCOUNTER_IBYTES, pkt->p_mbuf->m_pkthdr.len); error: if (remote != NULL) noise_remote_put(remote); -- cgit v1.2.3-59-g8ed1b