aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominique Martinet <dominique.martinet@cea.fr>2018-10-08 22:18:52 -0400
committerDominique Martinet <dominique.martinet@cea.fr>2018-10-09 20:13:30 -0400
commite4ca13f7d075e551dc158df6af18fb412a1dba0a (patch)
treead307b27d11af6952e8494218d03a6c6171ec5ac
parent72ea0321088df2c41eca8cc6160c24bcceb56ac7 (diff)
9p/trans_fd: abort p9_read_work if req status changed
p9_read_work would try to handle an errored req even if it got put to error state by another thread between the lookup (that worked) and the time it had been fully read. The request itself is safe to use because we hold a ref to it from the lookup (for m->rreq, so it was safe to read into the request data buffer until this point), but the req_list has been deleted at the same time status changed, and client_cb already has been called as well, so we should not do either. Link: http://lkml.kernel.org/r/1539057956-23741-1-git-send-email-asmadeus@codewreck.org Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr> Reported-by: syzbot+2222c34dc40b515f30dc@syzkaller.appspotmail.com Cc: Eric Van Hensbergen <ericvh@gmail.com> Cc: Latchesar Ionkov <lucho@ionkov.net>
-rw-r--r--net/9p/trans_fd.c17
1 files changed, 11 insertions, 6 deletions
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index 12559c474dde..a0317d459cde 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -292,7 +292,6 @@ static void p9_read_work(struct work_struct *work)
292 __poll_t n; 292 __poll_t n;
293 int err; 293 int err;
294 struct p9_conn *m; 294 struct p9_conn *m;
295 int status = REQ_STATUS_ERROR;
296 295
297 m = container_of(work, struct p9_conn, rq); 296 m = container_of(work, struct p9_conn, rq);
298 297
@@ -375,11 +374,17 @@ static void p9_read_work(struct work_struct *work)
375 p9_debug(P9_DEBUG_TRANS, "got new packet\n"); 374 p9_debug(P9_DEBUG_TRANS, "got new packet\n");
376 m->rreq->rc.size = m->rc.offset; 375 m->rreq->rc.size = m->rc.offset;
377 spin_lock(&m->client->lock); 376 spin_lock(&m->client->lock);
378 if (m->rreq->status != REQ_STATUS_ERROR) 377 if (m->rreq->status == REQ_STATUS_SENT) {
379 status = REQ_STATUS_RCVD; 378 list_del(&m->rreq->req_list);
380 list_del(&m->rreq->req_list); 379 p9_client_cb(m->client, m->rreq, REQ_STATUS_RCVD);
381 /* update req->status while holding client->lock */ 380 } else {
382 p9_client_cb(m->client, m->rreq, status); 381 spin_unlock(&m->client->lock);
382 p9_debug(P9_DEBUG_ERROR,
383 "Request tag %d errored out while we were reading the reply\n",
384 m->rc.tag);
385 err = -EIO;
386 goto error;
387 }
383 spin_unlock(&m->client->lock); 388 spin_unlock(&m->client->lock);
384 m->rc.sdata = NULL; 389 m->rc.sdata = NULL;
385 m->rc.offset = 0; 390 m->rc.offset = 0;