| From: Cong Wang <xiyou.wangcong@gmail.com> |
| Date: Mon, 6 Aug 2018 11:06:02 -0700 |
| Subject: vsock: split dwork to avoid reinitializations |
| |
| commit 455f05ecd2b219e9a216050796d30c830d9bc393 upstream. |
| |
| syzbot reported that we reinitialize an active delayed |
| work in vsock_stream_connect(): |
| |
| ODEBUG: init active (active state 0) object type: timer_list hint: |
| delayed_work_timer_fn+0x0/0x90 kernel/workqueue.c:1414 |
| WARNING: CPU: 1 PID: 11518 at lib/debugobjects.c:329 |
| debug_print_object+0x16a/0x210 lib/debugobjects.c:326 |
| |
| The pattern is apparently wrong, we should only initialize |
| the dealyed work once and could repeatly schedule it. So we |
| have to move out the initializations to allocation side. |
| And to avoid confusion, we can split the shared dwork |
| into two, instead of re-using the same one. |
| |
| Fixes: d021c344051a ("VSOCK: Introduce VM Sockets") |
| Reported-by: <syzbot+8a9b1bd330476a4f3db6@syzkaller.appspotmail.com> |
| Cc: Andy king <acking@vmware.com> |
| Cc: Stefan Hajnoczi <stefanha@redhat.com> |
| Cc: Jorgen Hansen <jhansen@vmware.com> |
| Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| [bwh: Backported to 3.16: adjust context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| include/net/af_vsock.h | 4 ++-- |
| net/vmw_vsock/af_vsock.c | 15 ++++++++------- |
| net/vmw_vsock/vmci_transport.c | 3 +-- |
| 3 files changed, 11 insertions(+), 11 deletions(-) |
| |
| --- a/include/net/af_vsock.h |
| +++ b/include/net/af_vsock.h |
| @@ -59,7 +59,8 @@ struct vsock_sock { |
| struct list_head pending_links; |
| struct list_head accept_queue; |
| bool rejected; |
| - struct delayed_work dwork; |
| + struct delayed_work connect_work; |
| + struct delayed_work pending_work; |
| u32 peer_shutdown; |
| bool sent_request; |
| bool ignore_connecting_rst; |
| @@ -70,7 +71,6 @@ struct vsock_sock { |
| |
| s64 vsock_stream_has_data(struct vsock_sock *vsk); |
| s64 vsock_stream_has_space(struct vsock_sock *vsk); |
| -void vsock_pending_work(struct work_struct *work); |
| struct sock *__vsock_create(struct net *net, |
| struct socket *sock, |
| struct sock *parent, |
| --- a/net/vmw_vsock/af_vsock.c |
| +++ b/net/vmw_vsock/af_vsock.c |
| @@ -431,14 +431,14 @@ static int vsock_send_shutdown(struct so |
| return transport->shutdown(vsock_sk(sk), mode); |
| } |
| |
| -void vsock_pending_work(struct work_struct *work) |
| +static void vsock_pending_work(struct work_struct *work) |
| { |
| struct sock *sk; |
| struct sock *listener; |
| struct vsock_sock *vsk; |
| bool cleanup; |
| |
| - vsk = container_of(work, struct vsock_sock, dwork.work); |
| + vsk = container_of(work, struct vsock_sock, pending_work.work); |
| sk = sk_vsock(vsk); |
| listener = vsk->listener; |
| cleanup = true; |
| @@ -478,7 +478,6 @@ out: |
| sock_put(sk); |
| sock_put(listener); |
| } |
| -EXPORT_SYMBOL_GPL(vsock_pending_work); |
| |
| /**** SOCKET OPERATIONS ****/ |
| |
| @@ -577,6 +576,8 @@ static int __vsock_bind(struct sock *sk, |
| return retval; |
| } |
| |
| +static void vsock_connect_timeout(struct work_struct *work); |
| + |
| struct sock *__vsock_create(struct net *net, |
| struct socket *sock, |
| struct sock *parent, |
| @@ -618,6 +619,8 @@ struct sock *__vsock_create(struct net * |
| vsk->sent_request = false; |
| vsk->ignore_connecting_rst = false; |
| vsk->peer_shutdown = 0; |
| + INIT_DELAYED_WORK(&vsk->connect_work, vsock_connect_timeout); |
| + INIT_DELAYED_WORK(&vsk->pending_work, vsock_pending_work); |
| |
| psk = parent ? vsock_sk(parent) : NULL; |
| if (parent) { |
| @@ -1095,7 +1098,7 @@ static void vsock_connect_timeout(struct |
| struct sock *sk; |
| struct vsock_sock *vsk; |
| |
| - vsk = container_of(work, struct vsock_sock, dwork.work); |
| + vsk = container_of(work, struct vsock_sock, connect_work.work); |
| sk = sk_vsock(vsk); |
| |
| lock_sock(sk); |
| @@ -1196,9 +1199,7 @@ static int vsock_stream_connect(struct s |
| * timeout fires. |
| */ |
| sock_hold(sk); |
| - INIT_DELAYED_WORK(&vsk->dwork, |
| - vsock_connect_timeout); |
| - schedule_delayed_work(&vsk->dwork, timeout); |
| + schedule_delayed_work(&vsk->connect_work, timeout); |
| |
| /* Skip ahead to preserve error code set above. */ |
| goto out_wait; |
| --- a/net/vmw_vsock/vmci_transport.c |
| +++ b/net/vmw_vsock/vmci_transport.c |
| @@ -1101,8 +1101,7 @@ static int vmci_transport_recv_listen(st |
| vpending->listener = sk; |
| sock_hold(sk); |
| sock_hold(pending); |
| - INIT_DELAYED_WORK(&vpending->dwork, vsock_pending_work); |
| - schedule_delayed_work(&vpending->dwork, HZ); |
| + schedule_delayed_work(&vpending->pending_work, HZ); |
| |
| out: |
| return err; |