On Fri, Jul 6, 2018 at 11:37 AM Subash Abhinov Kasiviswanathan <subas...@codeaurora.org> wrote: > > From the call stack, a TCP socket is being destroyed using netlink_diag. > The memory dump showed that the socket was an inet request socket (in > state TCP_NEW_SYN_RECV) with refcount of 0. > [...] > 13232.479820: <2> refcount_t: underflow; use-after-free. > 13232.479838: <6> ------------[ cut here ]------------ > 13232.479843: <6> kernel BUG at kernel/msm-4.14/lib/refcount.c:204! > 13232.479849: <6> Internal error: Oops - BUG: 0 [#1] PREEMPT SMP > [...] > 13232.479996: <6> Process netd (pid: 648, stack limit = > 0xffffff801cf98000) > 13232.479998: <2> Call trace: > 13232.480000: <2> refcount_sub_and_test+0x64/0x78 > 13232.480002: <2> refcount_dec_and_test+0x18/0x24 > 13232.480005: <2> sock_gen_put+0x1c/0xb0 > 13232.480009: <2> tcp_diag_destroy+0x54/0x68 > [...]
Looks like for a TCP_NEW_SYN_RECV socket, sock_diag_destroy essentially ends up doing: struct request_sock *req = inet_reqsk(sk); local_bh_disable(); inet_csk_reqsk_queue_drop_and_put(req->rsk_listener, req); local_bh_enable(); ... sock_gen_put(sk); It looks like inet_csk_reqsk_queue_drop_and_put calls reqsk_put(req), which frees the socket, and at that point sock_gen_put is a UAF. Do we just need: - inet_csk_reqsk_queue_drop_and_put(req->rsk_listener, - req); + inet_csk_reqsk_queue_drop(req->rsk_listener, req); since sock_gen_put will also end up calling reqsk_put() for a TCP_SYN_RECV socket? Alastair - you're able to reproduce this UAF using net_test on qemu, right? If so, could you try that two-line patch above?