Skip to content

Commit 287a06c

Browse files
ordexNipaLocal
authored andcommitted
ovpn: ensure sk is still valid during cleanup
In case of UDP peer timeout, an openvpn client (userspace) performs the following actions: 1. receives the peer deletion notification (reason=timeout) 2. closes the socket Upon 1. we have the following: - ovpn_peer_keepalive_work() - ovpn_socket_release() - synchronize_rcu() At this point, 2. gets a chance to complete and ovpn_sock->sock->sk becomes NULL. ovpn_socket_release() will then attempt dereferencing it, resulting in the following crash log: Oops: general protection fault, probably for non-canonical address 0xdffffc0000000077: 0000 [kernel-patches#1] SMP KASAN KASAN: null-ptr-deref in range [0x00000000000003b8-0x00000000000003bf] CPU: 12 UID: 0 PID: 162 Comm: kworker/12:1 Tainted: G O 6.15.0-rc2-00635-g521139ac3840 kernel-patches#272 PREEMPT(full) Tainted: [O]=OOT_MODULE Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-20240910_120124-localhost 04/01/2014 Workqueue: events ovpn_peer_keepalive_work [ovpn] RIP: 0010:ovpn_socket_release+0x23c/0x500 [ovpn] Code: ea 03 80 3c 02 00 0f 85 71 02 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 64 24 18 49 8d bc 24 be 03 00 00 48 89 fa 48 c1 ea 03 <0f> b6 14 02 48 89 f8 83 e0 07 83 c0 01 38 d0 7c 08 84 d2 0f 85 30 RSP: 0018:ffffc90000c9fb18 EFLAGS: 00010217 RAX: dffffc0000000000 RBX: ffff8881148d7940 RCX: ffffffff817787bb RDX: 0000000000000077 RSI: 0000000000000008 RDI: 00000000000003be RBP: ffffc90000c9fb30 R08: 0000000000000000 R09: fffffbfff0d3e840 R10: ffffffff869f4207 R11: 0000000000000000 R12: 0000000000000000 R13: ffff888115eb9300 R14: ffffc90000c9fbc8 R15: 000000000000000c FS: 0000000000000000(0000) GS:ffff8882b0151000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f37266b6114 CR3: 00000000054a8000 CR4: 0000000000750ef0 PKRU: 55555554 Call Trace: <TASK> unlock_ovpn+0x8b/0xe0 [ovpn] ovpn_peer_keepalive_work+0xe3/0x540 [ovpn] ? ovpn_peers_free+0x780/0x780 [ovpn] ? lock_acquire+0x56/0x70 ? process_one_work+0x888/0x1740 process_one_work+0x933/0x1740 ? pwq_dec_nr_in_flight+0x10b0/0x10b0 ? move_linked_works+0x12d/0x2c0 ? assign_work+0x163/0x270 worker_thread+0x4d6/0xd90 ? preempt_count_sub+0x4c/0x70 ? process_one_work+0x1740/0x1740 kthread+0x36c/0x710 ? trace_preempt_on+0x8c/0x1e0 ? kthread_is_per_cpu+0xc0/0xc0 ? preempt_count_sub+0x4c/0x70 ? _raw_spin_unlock_irq+0x36/0x60 ? calculate_sigpending+0x7b/0xa0 ? kthread_is_per_cpu+0xc0/0xc0 ret_from_fork+0x3a/0x80 ? kthread_is_per_cpu+0xc0/0xc0 ret_from_fork_asm+0x11/0x20 </TASK> Modules linked in: ovpn(O) Reason for accessing sk is ithat we need to retrieve its protocol and continue the cleanup routine accordingly. Fix the crash by grabbing a reference to sk before proceeding with the cleanup. If the refcounter has reached zero, we know that the socket is being destroyed and thus we skip the cleanup in ovpn_socket_release(). Fixes: 11851cb ("ovpn: implement TCP transport") Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Eric Dumazet <edumazet@google.com> Reported-by: Qingfang Deng <dqfext@gmail.com> Tested-By: Gert Doering <gert@greenie.muc.de> Signed-off-by: Antonio Quartulli <antonio@openvpn.net> Signed-off-by: NipaLocal <nipa@local>
1 parent d66db5c commit 287a06c

File tree

1 file changed

+12
-9
lines changed

1 file changed

+12
-9
lines changed

drivers/net/ovpn/socket.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ static bool ovpn_socket_put(struct ovpn_peer *peer, struct ovpn_socket *sock)
6666
void ovpn_socket_release(struct ovpn_peer *peer)
6767
{
6868
struct ovpn_socket *sock;
69+
struct sock *sk;
6970
bool released;
7071

7172
might_sleep();
@@ -75,13 +76,14 @@ void ovpn_socket_release(struct ovpn_peer *peer)
7576
if (!sock)
7677
return;
7778

78-
/* sanity check: we should not end up here if the socket
79-
* was already closed
79+
/* sock->sk may be released concurrently, therefore we
80+
* first attempt grabbing a reference.
81+
* if sock->sk is NULL it means it is already being
82+
* destroyed and we don't need any further cleanup
8083
*/
81-
if (!sock->sock->sk) {
82-
DEBUG_NET_WARN_ON_ONCE(1);
84+
sk = sock->sock->sk;
85+
if (!sk || !refcount_inc_not_zero(&sk->sk_refcnt))
8386
return;
84-
}
8587

8688
/* Drop the reference while holding the sock lock to avoid
8789
* concurrent ovpn_socket_new call to mess up with a partially
@@ -90,18 +92,18 @@ void ovpn_socket_release(struct ovpn_peer *peer)
9092
* Holding the lock ensures that a socket with refcnt 0 is fully
9193
* detached before it can be picked by a concurrent reader.
9294
*/
93-
lock_sock(sock->sock->sk);
95+
lock_sock(sk);
9496
released = ovpn_socket_put(peer, sock);
95-
release_sock(sock->sock->sk);
97+
release_sock(sk);
9698

9799
/* align all readers with sk_user_data being NULL */
98100
synchronize_rcu();
99101

100102
/* following cleanup should happen with lock released */
101103
if (released) {
102-
if (sock->sock->sk->sk_protocol == IPPROTO_UDP) {
104+
if (sk->sk_protocol == IPPROTO_UDP) {
103105
netdev_put(sock->ovpn->dev, &sock->dev_tracker);
104-
} else if (sock->sock->sk->sk_protocol == IPPROTO_TCP) {
106+
} else if (sk->sk_protocol == IPPROTO_TCP) {
105107
/* wait for TCP jobs to terminate */
106108
ovpn_tcp_socket_wait_finish(sock);
107109
ovpn_peer_put(sock->peer);
@@ -111,6 +113,7 @@ void ovpn_socket_release(struct ovpn_peer *peer)
111113
*/
112114
kfree(sock);
113115
}
116+
sock_put(sk);
114117
}
115118

116119
static bool ovpn_socket_hold(struct ovpn_socket *sock)

0 commit comments

Comments
 (0)