diff options
author | Cong Wang <xiyou.wangcong@gmail.com> | 2018-04-18 14:51:56 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-04-19 13:54:53 -0400 |
commit | f7e43672683b097bb074a8fe7af9bc600a23f231 (patch) | |
tree | f0177814d3113c0e7672a9d725d7a676d08e397b | |
parent | 02b94fc70ffe320a7799c35e09372809e40b7131 (diff) |
llc: hold llc_sap before release_sock()
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>
-rw-r--r-- | net/llc/af_llc.c | 7 |
1 files changed, 7 insertions, 0 deletions
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 01dcc0823d1f..6d29b2b94e84 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c | |||
@@ -189,6 +189,7 @@ static int llc_ui_release(struct socket *sock) | |||
189 | { | 189 | { |
190 | struct sock *sk = sock->sk; | 190 | struct sock *sk = sock->sk; |
191 | struct llc_sock *llc; | 191 | struct llc_sock *llc; |
192 | struct llc_sap *sap; | ||
192 | 193 | ||
193 | if (unlikely(sk == NULL)) | 194 | if (unlikely(sk == NULL)) |
194 | goto out; | 195 | goto out; |
@@ -199,9 +200,15 @@ static int llc_ui_release(struct socket *sock) | |||
199 | llc->laddr.lsap, llc->daddr.lsap); | 200 | llc->laddr.lsap, llc->daddr.lsap); |
200 | if (!llc_send_disc(sk)) | 201 | if (!llc_send_disc(sk)) |
201 | llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); | 202 | llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); |
203 | sap = llc->sap; | ||
204 | /* Hold this for release_sock(), so that llc_backlog_rcv() could still | ||
205 | * use it. | ||
206 | */ | ||
207 | llc_sap_hold(sap); | ||
202 | if (!sock_flag(sk, SOCK_ZAPPED)) | 208 | if (!sock_flag(sk, SOCK_ZAPPED)) |
203 | llc_sap_remove_socket(llc->sap, sk); | 209 | llc_sap_remove_socket(llc->sap, sk); |
204 | release_sock(sk); | 210 | release_sock(sk); |
211 | llc_sap_put(sap); | ||
205 | if (llc->dev) | 212 | if (llc->dev) |
206 | dev_put(llc->dev); | 213 | dev_put(llc->dev); |
207 | sock_put(sk); | 214 | sock_put(sk); |