aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Dunwoodie <ncon@mail.noconroy.net>2019-09-25 21:47:32 +0100
committerMatt Dunwoodie <ncon@mail.noconroy.net>2019-09-25 21:47:32 +0100
commitb4cf1398419fb77ba8537a457bb732a2ce65073f (patch)
treeed9e64f4388c5af6c471f1ff24cce7bcd292e813
parentI accidentally deleted these lines (diff)
downloadwireguard-openbsd-b4cf1398419fb77ba8537a457bb732a2ce65073f.tar.xz
wireguard-openbsd-b4cf1398419fb77ba8537a457bb732a2ce65073f.zip
Adjust wg_encrypt
There was a nasty bug where TCP connections would reset after a retransmission. I figured out this is probably because the mbuf storage is overwritten during encryption and the storage points to the TCP buffer. Therefore, when the retransmission is sent, it send the previously encrypted data. This was validated by running the following commands: s1 $ nc -l 4567 | hexdump -C s2 $ cat /dev/zero | nc s1 4567 It was observed that the hexdump contained seemingly random data. After this patch, the behaviour was not observed.
-rw-r--r--src/if_wg.c19
1 files changed, 12 insertions, 7 deletions
diff --git a/src/if_wg.c b/src/if_wg.c
index df3cef5..751072a 100644
--- a/src/if_wg.c
+++ b/src/if_wg.c
@@ -625,6 +625,7 @@ wg_encrypt_hs(struct mbuf *m)
panic("invalid packet type: %d\n", tag->t_type);
}
+ m->m_pkthdr.ph_cookie = m;
tag->t_state = WG_PKT_STATE_DONE;
return;
bad:
@@ -649,6 +650,9 @@ wg_encrypt(struct mbuf *m)
panic("not a new/pass state packet: %d\n", tag->t_state);
em = m_clget(NULL, M_WAITOK, total_len);
+ em->m_len = total_len;
+ m_calchdrlen(em);
+
msg = mtod(em, struct wg_msg_transport *);
m_copydata(m, 0, plain_len, msg->data);
bzero(msg->data + plain_len, padding_len);
@@ -681,13 +685,10 @@ wg_encrypt(struct mbuf *m)
wg_timer_broken_flag(&p->p_timers);
}
- if (m_copyback(m, 0, total_len, mtod(em, caddr_t), M_WAIT))
- goto free;
-
wg_timer_keepalive_unflag(&p->p_timers);
wg_timer_persistent_keepalive_tick(&p->p_timers);
- m_freem(em);
+ m->m_pkthdr.ph_cookie = em;
tag->t_state = WG_PKT_STATE_DONE;
return;
free:
@@ -1029,7 +1030,7 @@ wg_output_deliver(struct mbuf *m)
{
int error;
struct socket *so;
- struct mbuf peernam;
+ struct mbuf peernam, *em;
struct wg_tag *tag = wg_mbuf_get_tag(m);
struct wg_peer *p = tag->t_peer;
struct wg_softc *sc = p->p_sc;
@@ -1041,6 +1042,10 @@ wg_output_deliver(struct mbuf *m)
else if (tag->t_state == WG_PKT_STATE_REQUEUED)
DPRINTF(sc, "did not output packet\n");
else if (tag->t_state == WG_PKT_STATE_DONE) {
+ em = m->m_pkthdr.ph_cookie;
+ if (em != m)
+ m_freem(m);
+
bzero(&peernam, sizeof(struct mbuf));
peernam.m_type = MT_SONAME;
@@ -1050,11 +1055,11 @@ wg_output_deliver(struct mbuf *m)
so = AF_VAL(p->p_ip.sa.sa_family, sc->sc_so4, sc->sc_so6);
int s = solock(so);
if (so) {
- if ((error = so->so_proto->pr_usrreq(so, PRU_SEND, m,
+ if ((error = so->so_proto->pr_usrreq(so, PRU_SEND, em,
&peernam, NULL, NULL)) != 0)
DPRINTF(sc, "unable to send: %d\n", error);
} else {
- m_freem(m);
+ m_freem(em);
}
sounlock(so, s);
} else {