aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2021-04-28 21:17:19 -0400
committerJason A. Donenfeld <Jason@zx2c4.com>2021-04-28 21:28:28 -0400
commita1fdf6646b16ec26c741089102346f5455dc5fed (patch)
treee83d112f93e754beb3305fee098c498346f014c8
parentif_wg: enter net epoch for isr dispatch (diff)
downloadwireguard-freebsd-a1fdf6646b16ec26c741089102346f5455dc5fed.tar.xz
wireguard-freebsd-a1fdf6646b16ec26c741089102346f5455dc5fed.zip
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 <Jason@zx2c4.com>
-rw-r--r--src/if_wg.c31
1 files changed, 13 insertions, 18 deletions
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);