The branch main has been updated by kp:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=81877287a99e55b47a7045efa76945f368e90917

commit 81877287a99e55b47a7045efa76945f368e90917
Author:     Kristof Provost <k...@freebsd.org>
AuthorDate: 2023-05-20 17:43:49 +0000
Commit:     Kristof Provost <k...@freebsd.org>
CommitDate: 2023-05-23 14:11:26 +0000

    if_ovpn: ensure we never re-use sequence numbers
    
    if_ovpn already notified userpsace when there was a risk of sequence
    number re-use, but it trusted userspace to actually rotate the key.
    
    Convert the internal sequence number counter to 64 bits so we can detect
    overflows and then refuse to send packets.
    
    Event:          BSDCan 2023
    Reviewed by:    Leon Dang <ld...@netgate.com>
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D40187
---
 sys/net/if_ovpn.c | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/sys/net/if_ovpn.c b/sys/net/if_ovpn.c
index 3aec073c052e..49c8c8e9677a 100644
--- a/sys/net/if_ovpn.c
+++ b/sys/net/if_ovpn.c
@@ -93,7 +93,7 @@ struct ovpn_kkey_dir {
         * strictly higher than this.
         */
        uint32_t                rx_seq;
-       uint32_t                tx_seq;
+       uint64_t                tx_seq;
 
        /* Seen packets, relative to rx_seq. bit(0) will always be 0. */
        uint64_t                rx_window;
@@ -1830,6 +1830,7 @@ ovpn_transmit_to_peer(struct ifnet *ifp, struct mbuf *m,
        struct ovpn_softc *sc;
        struct cryptop *crp;
        uint32_t af, seq;
+       uint64_t seq64;
        size_t len, ovpn_hdr_len;
        int tunnel_len;
        int ret;
@@ -1873,11 +1874,24 @@ ovpn_transmit_to_peer(struct ifnet *ifp, struct mbuf *m,
        ohdr->opcode |= key->peerid;
        ohdr->opcode = htonl(ohdr->opcode);
 
-       seq = 
atomic_fetchadd_32(&peer->keys[OVPN_KEY_SLOT_PRIMARY].encrypt->tx_seq, 1);
-       if (seq == OVPN_SEQ_ROTATE)
+       seq64 = 
atomic_fetchadd_64(&peer->keys[OVPN_KEY_SLOT_PRIMARY].encrypt->tx_seq, 1);
+       if (seq64 == OVPN_SEQ_ROTATE) {
                ovpn_notify_key_rotation(sc, peer);
+       } else if (seq64 > UINT32_MAX) {
+               /* We've wrapped, give up on this packet. */
+               if (_ovpn_lock_trackerp != NULL)
+                       OVPN_RUNLOCK(sc);
+               OVPN_COUNTER_ADD(sc, nomem_data_pkts_out, 1);
+
+               /* Let's avoid (very unlikely, but still) wraparounds of the
+                * 64-bit counter taking us back to 0. */
+               
atomic_set_64(&peer->keys[OVPN_KEY_SLOT_PRIMARY].encrypt->tx_seq,
+                   UINT32_MAX);
+
+               return (ENOBUFS);
+       }
 
-       seq = htonl(seq);
+       seq = htonl(seq64 & UINT32_MAX);
        ohdr->seq = seq;
 
        OVPN_PEER_COUNTER_ADD(peer, pkt_out, 1);

Reply via email to