]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ovpn: fix use after free in unlock_ovpn()
authorMarco Baffo <marco@mandelbit.com>
Mon, 8 Jun 2026 14:04:46 +0000 (16:04 +0200)
committerAntonio Quartulli <antonio@openvpn.net>
Mon, 20 Jul 2026 13:49:55 +0000 (15:49 +0200)
unlock_ovpn() iterates over the release_list using llist_for_each_entry()
and drops the peer reference inside the loop body via ovpn_peer_put().

If this drops the last reference, the peer is eventually freed. However,
llist_for_each_entry() reads peer->release_entry.next in the loop advance
expression, which runs after the body. By that time the peer may have
already been freed, resulting in a use after free when advancing to the
next list entry.

Fix this by using llist_for_each_entry_safe(), which caches the next
pointer before executing the loop body.

Fixes: 80747caef33d ("ovpn: introduce the ovpn_peer object")
Signed-off-by: Marco Baffo <marco@mandelbit.com>
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
drivers/net/ovpn/peer.c

index 2b6096d8b1cc91437177c4a7ef24bc752fb685d2..8fdbb5050690be23659c7c22939064349596f2ed 100644 (file)
@@ -26,11 +26,12 @@ static void unlock_ovpn(struct ovpn_priv *ovpn,
                         struct llist_head *release_list)
        __releases(&ovpn->lock)
 {
-       struct ovpn_peer *peer;
+       struct ovpn_peer *peer, *next;
 
        spin_unlock_bh(&ovpn->lock);
 
-       llist_for_each_entry(peer, release_list->first, release_entry) {
+       llist_for_each_entry_safe(peer, next, release_list->first,
+                                 release_entry) {
                ovpn_socket_release(peer);
                ovpn_peer_put(peer);
        }