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