| From: Cong Wang <xiyou.wangcong@gmail.com> |
| Date: Wed, 18 Apr 2018 11:51:56 -0700 |
| Subject: llc: hold llc_sap before release_sock() |
| |
| commit f7e43672683b097bb074a8fe7af9bc600a23f231 upstream. |
| |
| syzbot reported we still access llc->sap in llc_backlog_rcv() |
| after it is freed in llc_sap_remove_socket(): |
| |
| Call Trace: |
| __dump_stack lib/dump_stack.c:77 [inline] |
| dump_stack+0x1b9/0x294 lib/dump_stack.c:113 |
| print_address_description+0x6c/0x20b mm/kasan/report.c:256 |
| kasan_report_error mm/kasan/report.c:354 [inline] |
| kasan_report.cold.7+0x242/0x2fe mm/kasan/report.c:412 |
| __asan_report_load1_noabort+0x14/0x20 mm/kasan/report.c:430 |
| llc_conn_ac_send_sabme_cmd_p_set_x+0x3a8/0x460 net/llc/llc_c_ac.c:785 |
| llc_exec_conn_trans_actions net/llc/llc_conn.c:475 [inline] |
| llc_conn_service net/llc/llc_conn.c:400 [inline] |
| llc_conn_state_process+0x4e1/0x13a0 net/llc/llc_conn.c:75 |
| llc_backlog_rcv+0x195/0x1e0 net/llc/llc_conn.c:891 |
| sk_backlog_rcv include/net/sock.h:909 [inline] |
| __release_sock+0x12f/0x3a0 net/core/sock.c:2335 |
| release_sock+0xa4/0x2b0 net/core/sock.c:2850 |
| llc_ui_release+0xc8/0x220 net/llc/af_llc.c:204 |
| |
| llc->sap is refcount'ed and llc_sap_remove_socket() is paired |
| with llc_sap_add_socket(). This can be amended by holding its refcount |
| before llc_sap_remove_socket() and releasing it after release_sock(). |
| |
| Reported-by: <syzbot+6e181fc95081c2cf9051@syzkaller.appspotmail.com> |
| Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| net/llc/af_llc.c | 7 +++++++ |
| 1 file changed, 7 insertions(+) |
| |
| --- a/net/llc/af_llc.c |
| +++ b/net/llc/af_llc.c |
| @@ -187,6 +187,7 @@ static int llc_ui_release(struct socket |
| { |
| struct sock *sk = sock->sk; |
| struct llc_sock *llc; |
| + struct llc_sap *sap; |
| |
| if (unlikely(sk == NULL)) |
| goto out; |
| @@ -197,9 +198,15 @@ static int llc_ui_release(struct socket |
| llc->laddr.lsap, llc->daddr.lsap); |
| if (!llc_send_disc(sk)) |
| llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); |
| + sap = llc->sap; |
| + /* Hold this for release_sock(), so that llc_backlog_rcv() could still |
| + * use it. |
| + */ |
| + llc_sap_hold(sap); |
| if (!sock_flag(sk, SOCK_ZAPPED)) |
| llc_sap_remove_socket(llc->sap, sk); |
| release_sock(sk); |
| + llc_sap_put(sap); |
| if (llc->dev) |
| dev_put(llc->dev); |
| sock_put(sk); |