From: Antonio Quartulli <[email protected]> Memcg accounting bounds user-driven peer creation only when the calling cgroup has memory.max set; on unconstrained hosts it isn't a hard limit.
Track the live peer count in ovpn_peer_collection::n_peers under the existing ovpn->lock and reject OVPN_CMD_PEER_NEW with -ENOSPC once OVPN_MAX_PEERS (65535) is reached. 65535 matches what userspace OpenVPN servers configure via --max-clients. P2P mode is unaffected. The same cap also bounds the unaccounted RX-float bind allocations, since binds are owned by peers. Signed-off-by: Antonio Quartulli <[email protected]> --- drivers/net/ovpn/ovpnpriv.h | 3 +++ drivers/net/ovpn/peer.c | 9 +++++++++ drivers/net/ovpn/peer.h | 8 ++++++++ 3 files changed, 20 insertions(+) diff --git a/drivers/net/ovpn/ovpnpriv.h b/drivers/net/ovpn/ovpnpriv.h index 5898f6adada7..113f5f493575 100644 --- a/drivers/net/ovpn/ovpnpriv.h +++ b/drivers/net/ovpn/ovpnpriv.h @@ -24,12 +24,15 @@ * rehashed on the fly due to peer IP change) * @by_transp_addr: table of peers indexed by transport address (items can be * rehashed on the fly due to peer IP change) + * @n_peers: number of peers currently in the collection, protected by + * ovpn_priv->lock */ struct ovpn_peer_collection { DECLARE_HASHTABLE(by_id, 12); struct hlist_nulls_head by_vpn_addr4[1 << 12]; struct hlist_nulls_head by_vpn_addr6[1 << 12]; struct hlist_nulls_head by_transp_addr[1 << 12]; + u32 n_peers; }; /** diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c index 511a7ce9b32b..1d564888479a 100644 --- a/drivers/net/ovpn/peer.c +++ b/drivers/net/ovpn/peer.c @@ -286,6 +286,8 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb) /* RX float path runs in softirq context: __GFP_ACCOUNT would charge * whatever cgroup is on-CPU when the packet arrives, not the userns * owner, so pass plain GFP_ATOMIC and skip accounting on this path. + * The number of bind objects that can accumulate via float events is + * bounded by the per-MP peer cap, since binds are owned by peers. */ if (unlikely(ovpn_peer_reset_sockaddr(peer, (struct sockaddr_storage *)&ss, @@ -703,6 +705,7 @@ static void ovpn_peer_remove(struct ovpn_peer *peer, hlist_nulls_del_init_rcu(&peer->hash_entry_addr4); hlist_nulls_del_init_rcu(&peer->hash_entry_addr6); hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr); + peer->ovpn->peers->n_peers--; break; case OVPN_MODE_P2P: /* prevent double remove */ @@ -959,6 +962,11 @@ static int ovpn_peer_add_mp(struct ovpn_priv *ovpn, struct ovpn_peer *peer) goto out; } + if (ovpn->peers->n_peers >= OVPN_MAX_PEERS) { + ret = -ENOSPC; + goto out; + } + bind = rcu_dereference_protected(peer->bind, true); /* peers connected via TCP have bind == NULL */ if (bind) { @@ -994,6 +1002,7 @@ static int ovpn_peer_add_mp(struct ovpn_priv *ovpn, struct ovpn_peer *peer) sizeof(peer->id))); ovpn_peer_hash_vpn_ip(peer); + ovpn->peers->n_peers++; out: spin_unlock_bh(&ovpn->lock); return ret; diff --git a/drivers/net/ovpn/peer.h b/drivers/net/ovpn/peer.h index 1bfc66821739..2efc782130f3 100644 --- a/drivers/net/ovpn/peer.h +++ b/drivers/net/ovpn/peer.h @@ -17,6 +17,14 @@ #include "socket.h" #include "stats.h" +/* Hard cap on number of peers per MP-mode interface. Caps the worst-case + * kernel memory an unprivileged userns owner driving OVPN_CMD_PEER_NEW can + * pin even when memcg accounting is unconstrained. 65535 matches what + * mainstream userspace OpenVPN servers configure via --max-clients, so + * legitimate deployments never hit this. + */ +#define OVPN_MAX_PEERS 65535 + /** * struct ovpn_peer - the main remote peer object * @ovpn: main openvpn instance this peer belongs to -- 2.53.0 _______________________________________________ Openvpn-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openvpn-devel
