summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorDominique Martinet <dominique.martinet@cea.fr>2018-10-09 05:18:52 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-08-05 11:06:49 +0300
commitd1f7217b7a75cb7f59b295d7ceab1776a0affe95 (patch)
tree726b37f3d35a2e83c6aedf2a566df4298a6549c9 /net
parent6a27f426266ac0d29faa95bed8934afeef1f9d13 (diff)
downloadlinux-d1f7217b7a75cb7f59b295d7ceab1776a0affe95.tar.xz
9p/trans_fd: abort p9_read_work if req status changed
[ Upstream commit e4ca13f7d075e551dc158df6af18fb412a1dba0a ] 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> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to '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 a9c65f13b7f5..cbd8cfafb794 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -301,7 +301,6 @@ static void p9_read_work(struct work_struct *work)
{
int n, err;
struct p9_conn *m;
- int status = REQ_STATUS_ERROR;
m = container_of(work, struct p9_conn, rq);
@@ -381,11 +380,17 @@ static void p9_read_work(struct work_struct *work)
if ((m->req) && (m->rc.offset == m->rc.capacity)) {
p9_debug(P9_DEBUG_TRANS, "got new packet\n");
spin_lock(&m->client->lock);
- if (m->req->status != REQ_STATUS_ERROR)
- status = REQ_STATUS_RCVD;
- list_del(&m->req->req_list);
- /* update req->status while holding client->lock */
- p9_client_cb(m->client, m->req, status);
+ if (m->req->status == REQ_STATUS_SENT) {
+ list_del(&m->req->req_list);
+ p9_client_cb(m->client, m->req, REQ_STATUS_RCVD);
+ } else {
+ spin_unlock(&m->client->lock);
+ p9_debug(P9_DEBUG_ERROR,
+ "Request tag %d errored out while we were reading the reply\n",
+ m->rc.tag);
+ err = -EIO;
+ goto error;
+ }
spin_unlock(&m->client->lock);
m->rc.sdata = NULL;
m->rc.offset = 0;