ovpn operates on a userspace-owned UDP socket, which may be manipulated
in various ways by userspace. If the socket is never bound, connected,
or used for communication, it may not have a source port assigned.
Similarly, if the socket was connect()'ed to AF_INET or AF_INET6, it can
be disconnected by connect() with AF_UNSPEC, which resets the source
port unless the socket was explicitly bound.

Since we must not transmit packets with source port 0, gate UDP TX on
the presence of a valid source port and drop packets otherwise. To avoid
ambiguity, sample the current source port once before route lookup and
header build and enforce the check on that value.

Fixes: 08857b5ec5d9 ("ovpn: implement basic TX path (UDP)")
Signed-off-by: Ralf Lici <[email protected]>
---
 drivers/net/ovpn/udp.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c
index 493a5a0744af..2610f3e23bf0 100644
--- a/drivers/net/ovpn/udp.c
+++ b/drivers/net/ovpn/udp.c
@@ -149,13 +149,17 @@ static int ovpn_udp4_output(struct ovpn_peer *peer, 
struct ovpn_bind *bind,
        struct flowi4 fl = {
                .saddr = bind->local.ipv4.s_addr,
                .daddr = bind->remote.in4.sin_addr.s_addr,
-               .fl4_sport = inet_sk(sk)->inet_sport,
+               .fl4_sport = READ_ONCE(inet_sk(sk)->inet_sport),
                .fl4_dport = bind->remote.in4.sin_port,
                .flowi4_proto = sk->sk_protocol,
                .flowi4_mark = sk->sk_mark,
        };
        int ret;
 
+       /* an uninitialized socket or connect(AF_UNSPEC) can cause this */
+       if (unlikely(!fl.fl4_sport))
+               return -EADDRNOTAVAIL;
+
        local_bh_disable();
        rt = dst_cache_get_ip4(cache, &fl.saddr);
        if (rt)
@@ -226,13 +230,17 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, 
struct ovpn_bind *bind,
        struct flowi6 fl = {
                .saddr = bind->local.ipv6,
                .daddr = bind->remote.in6.sin6_addr,
-               .fl6_sport = inet_sk(sk)->inet_sport,
+               .fl6_sport = READ_ONCE(inet_sk(sk)->inet_sport),
                .fl6_dport = bind->remote.in6.sin6_port,
                .flowi6_proto = sk->sk_protocol,
                .flowi6_mark = sk->sk_mark,
                .flowi6_oif = bind->remote.in6.sin6_scope_id,
        };
 
+       /* an uninitialized socket or connect(AF_UNSPEC) can cause this */
+       if (unlikely(!fl.fl6_sport))
+               return -EADDRNOTAVAIL;
+
        local_bh_disable();
        dst = dst_cache_get_ip6(cache, &fl.saddr);
        if (dst)
-- 
2.54.0



_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to