• Daniel Borkmann's avatar
    tls: fix use-after-free in tls_push_record · a447da7d
    Daniel Borkmann authored
    syzkaller managed to trigger a use-after-free in tls like the
    following:
    
      BUG: KASAN: use-after-free in tls_push_record.constprop.15+0x6a2/0x810 [tls]
      Write of size 1 at addr ffff88037aa08000 by task a.out/2317
    
      CPU: 3 PID: 2317 Comm: a.out Not tainted 4.17.0+ #144
      Hardware name: LENOVO 20FBCTO1WW/20FBCTO1WW, BIOS N1FET47W (1.21 ) 11/28/2016
      Call Trace:
       dump_stack+0x71/0xab
       print_address_description+0x6a/0x280
       kasan_report+0x258/0x380
       ? tls_push_record.constprop.15+0x6a2/0x810 [tls]
       tls_push_record.constprop.15+0x6a2/0x810 [tls]
       tls_sw_push_pending_record+0x2e/0x40 [tls]
       tls_sk_proto_close+0x3fe/0x710 [tls]
       ? tcp_check_oom+0x4c0/0x4c0
       ? tls_write_space+0x260/0x260 [tls]
       ? kmem_cache_free+0x88/0x1f0
       inet_release+0xd6/0x1b0
       __sock_release+0xc0/0x240
       sock_close+0x11/0x20
       __fput+0x22d/0x660
       task_work_run+0x114/0x1a0
       do_exit+0x71a/0x2780
       ? mm_update_next_owner+0x650/0x650
       ? handle_mm_fault+0x2f5/0x5f0
       ? __do_page_fault+0x44f/0xa50
       ? mm_fault_error+0x2d0/0x2d0
       do_group_exit+0xde/0x300
       __x64_sys_exit_group+0x3a/0x50
       do_syscall_64+0x9a/0x300
       ? page_fault+0x8/0x30
       entry_SYSCALL_64_after_hwframe+0x44/0xa9
    
    This happened through fault injection where aead_req allocation in
    tls_do_encryption() eventually failed and we returned -ENOMEM from
    the function. Turns out that the use-after-free is triggered from
    tls_sw_sendmsg() in the second tls_push_record(). The error then
    triggers a jump to waiting for memory in sk_stream_wait_memory()
    resp. returning immediately in case of MSG_DONTWAIT. What follows is
    the trim_both_sgl(sk, orig_size), which drops elements from the sg
    list added via tls_sw_sendmsg(). Now the use-after-free gets triggered
    when the socket is being closed, where tls_sk_proto_close() callback
    is invoked. The tls_complete_pending_work() will figure that there's
    a pending closed tls record to be flushed and thus calls into the
    tls_push_pending_closed_record() from there. ctx->push_pending_record()
    is called from the latter, which is the tls_sw_push_pending_record()
    from sw path. This again calls into tls_push_record(). And here the
    tls_fill_prepend() will panic since the buffer address has been freed
    earlier via trim_both_sgl(). One way to fix it is to move the aead
    request allocation out of tls_do_encryption() early into tls_push_record().
    This means we don't prep the tls header and advance state to the
    TLS_PENDING_CLOSED_RECORD before allocation which could potentially
    fail happened. That fixes the issue on my side.
    
    Fixes: 3c4d7559 ("tls: kernel TLS support")
    Reported-by: syzbot+5c74af81c547738e1684@syzkaller.appspotmail.com
    Reported-by: syzbot+709f2810a6a05f11d4d3@syzkaller.appspotmail.com
    Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
    Acked-by: default avatarDave Watson <davejwatson@fb.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    a447da7d
tls_sw.c 29.4 KB