vsock: split dwork to avoid reinitializations

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: d021c34405 ("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>
This commit is contained in:
Cong Wang 2018-08-06 11:06:02 -07:00 committed by David S. Miller
parent a94cead71c
commit 455f05ecd2
3 changed files with 11 additions and 11 deletions

View File

@ -64,7 +64,8 @@ struct vsock_sock {
struct list_head pending_links; struct list_head pending_links;
struct list_head accept_queue; struct list_head accept_queue;
bool rejected; bool rejected;
struct delayed_work dwork; struct delayed_work connect_work;
struct delayed_work pending_work;
struct delayed_work close_work; struct delayed_work close_work;
bool close_work_scheduled; bool close_work_scheduled;
u32 peer_shutdown; u32 peer_shutdown;
@ -77,7 +78,6 @@ struct vsock_sock {
s64 vsock_stream_has_data(struct vsock_sock *vsk); s64 vsock_stream_has_data(struct vsock_sock *vsk);
s64 vsock_stream_has_space(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 sock *__vsock_create(struct net *net,
struct socket *sock, struct socket *sock,
struct sock *parent, struct sock *parent,

View File

@ -451,14 +451,14 @@ static int vsock_send_shutdown(struct sock *sk, int mode)
return transport->shutdown(vsock_sk(sk), mode); 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 *sk;
struct sock *listener; struct sock *listener;
struct vsock_sock *vsk; struct vsock_sock *vsk;
bool cleanup; 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); sk = sk_vsock(vsk);
listener = vsk->listener; listener = vsk->listener;
cleanup = true; cleanup = true;
@ -498,7 +498,6 @@ out:
sock_put(sk); sock_put(sk);
sock_put(listener); sock_put(listener);
} }
EXPORT_SYMBOL_GPL(vsock_pending_work);
/**** SOCKET OPERATIONS ****/ /**** SOCKET OPERATIONS ****/
@ -597,6 +596,8 @@ static int __vsock_bind(struct sock *sk, struct sockaddr_vm *addr)
return retval; return retval;
} }
static void vsock_connect_timeout(struct work_struct *work);
struct sock *__vsock_create(struct net *net, struct sock *__vsock_create(struct net *net,
struct socket *sock, struct socket *sock,
struct sock *parent, struct sock *parent,
@ -638,6 +639,8 @@ struct sock *__vsock_create(struct net *net,
vsk->sent_request = false; vsk->sent_request = false;
vsk->ignore_connecting_rst = false; vsk->ignore_connecting_rst = false;
vsk->peer_shutdown = 0; 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; psk = parent ? vsock_sk(parent) : NULL;
if (parent) { if (parent) {
@ -1117,7 +1120,7 @@ static void vsock_connect_timeout(struct work_struct *work)
struct vsock_sock *vsk; struct vsock_sock *vsk;
int cancel = 0; int cancel = 0;
vsk = container_of(work, struct vsock_sock, dwork.work); vsk = container_of(work, struct vsock_sock, connect_work.work);
sk = sk_vsock(vsk); sk = sk_vsock(vsk);
lock_sock(sk); lock_sock(sk);
@ -1221,9 +1224,7 @@ static int vsock_stream_connect(struct socket *sock, struct sockaddr *addr,
* timeout fires. * timeout fires.
*/ */
sock_hold(sk); sock_hold(sk);
INIT_DELAYED_WORK(&vsk->dwork, schedule_delayed_work(&vsk->connect_work, timeout);
vsock_connect_timeout);
schedule_delayed_work(&vsk->dwork, timeout);
/* Skip ahead to preserve error code set above. */ /* Skip ahead to preserve error code set above. */
goto out_wait; goto out_wait;

View File

@ -1094,8 +1094,7 @@ static int vmci_transport_recv_listen(struct sock *sk,
vpending->listener = sk; vpending->listener = sk;
sock_hold(sk); sock_hold(sk);
sock_hold(pending); sock_hold(pending);
INIT_DELAYED_WORK(&vpending->dwork, vsock_pending_work); schedule_delayed_work(&vpending->pending_work, HZ);
schedule_delayed_work(&vpending->dwork, HZ);
out: out:
return err; return err;