net: qrtr: fix refcount saturation and potential UAF in qrtr_port_remove

JIRA: https://issues.redhat.com/browse/RHEL-184812
CVE: CVE-2026-52947

commit a2171131ecda1ed61a594a1eb715e75fdad0fef5
Author: Mingyu Wang <25181214217@stu.xidian.edu.cn>
Date:   Thu Jun 4 14:48:01 2026 +0800

    net: qrtr: fix refcount saturation and potential UAF in qrtr_port_remove
    
    In qrtr_port_remove(), the socket reference count is decremented via
    __sock_put() before the port is removed from the qrtr_ports XArray and
    before the RCU grace period elapses.
    
    This breaks the fundamental RCU update paradigm. It exposes a race
    window where a concurrent RCU reader (such as qrtr_reset_ports() or
    qrtr_port_lookup()) can obtain a pointer to the socket from the XArray,
    and attempt to call sock_hold() on a socket whose reference count has
    already dropped to zero.
    
    This exact race condition was hit during syzkaller fuzzing, leading to
    the following refcount saturation warning and a potential Use-After-Free:
    
      refcount_t: saturated; leaking memory.
      WARNING: CPU: 3 PID: 1273 at lib/refcount.c:22 refcount_warn_saturate+0xae/0x1d0
      Modules linked in: qrtr(+) bochs drm_shmem_helper ...
      Call Trace:
       <TASK>
       qrtr_reset_ports net/qrtr/af_qrtr.c:768 [inline] [qrtr]
       __qrtr_bind.isra.0+0x48b/0x570 net/qrtr/af_qrtr.c:805 [qrtr]
       qrtr_bind+0x17d/0x210 net/qrtr/af_qrtr.c:901 [qrtr]
       kernel_bind+0xe4/0x120 net/socket.c:3592
       qrtr_ns_init+0x1a6/0x380 net/qrtr/ns.c:715 [qrtr]
       qrtr_proto_init+0x3b/0xff0 net/qrtr/af_qrtr.c:169 [qrtr]
       do_one_initcall+0xf5/0x5e0 init/main.c:1283
       ...
       </TASK>
    
    Fix this by deferring the reference count decrement until after the
    xa_erase() and the synchronize_rcu() complete.
    
    (Note: The v1 of this patch incorrectly replaced __sock_put() with
    sock_put(). As Simon Horman pointed out, the callers of qrtr_port_remove()
    still hold a reference to the socket, so freeing the socket memory here
    would lead to a subsequent UAF in the caller. Thus, the __sock_put() is
    kept, but only repositioned to close the RCU race.)
    
    Fixes: bdabad3e36 ("net: Add Qualcomm IPC router")
    Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn>
    Reviewed-by: Simon Horman <horms@kernel.org>
    Link: https://patch.msgid.link/20260604064801.1180388-1-w15303746062@163.com
    Signed-off-by: Jakub Kicinski <kuba@kernel.org>

Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
This commit is contained in:
Jose Ignacio Tornos Martinez
2026-07-12 07:54:39 +02:00
parent fec9264f23
commit 5ebb6282b1
+2 -2
View File
@@ -712,13 +712,13 @@ static void qrtr_port_remove(struct qrtr_sock *ipc)
if (port == QRTR_PORT_CTRL)
port = 0;
__sock_put(&ipc->sk);
xa_erase(&qrtr_ports, port);
/* Ensure that if qrtr_port_lookup() did enter the RCU read section we
* wait for it to up increment the refcount */
synchronize_rcu();
__sock_put(&ipc->sk);
}
/* Assign port number to socket.