Received: by 2002:ac0:b08d:0:0:0:0:0 with SMTP id l13csp4917543imc; Mon, 25 Feb 2019 13:35:48 -0800 (PST) X-Google-Smtp-Source: AHgI3IbSO2FwgddTHlP8JQOf9bjneMnWBl/Yn6v+RPN1gd6arKeYkBXy1VECgobt7L14xxN3tfii X-Received: by 2002:a63:1a62:: with SMTP id a34mr21206388pgm.60.1551130548364; Mon, 25 Feb 2019 13:35:48 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1551130548; cv=none; d=google.com; s=arc-20160816; b=S3wkk012tPC80GPoHmwqPriMxBL4t0PpQHycbO5xelv0qXhYg+OeJP8SrNIR8/bblM /OFx3QsqKfkrP9Zjq1GAKNyX/WejNSuKXz4JiA+mKSb/43GfjRxVkpyrlGfzgIaH1SEm ZVZatqqCI5ukg7rIk0usCLHCptrm/5delDpFZ97TMrpUJPO5dykJO8vwCbYW67uOfw4l Hufb/2U9D2wHjYAn85QvsZLrHrUfZ7lvisIDfE7KJrgmH749Gj9b086PvQvQdHkkues4 2nyytvcxq5Arc2u69arkXrr7tzytYZ1TptHpYXARaSWE2c8Omg2FDllfpo0I1EXpLDxN 4tyQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=dOfB3TJKRCgQEHsU7s1NzneamUWI/yW4JZGI9gWq6sY=; b=KxQh6aGxN5mCseX5X8VbY3jtnLX4e2qrovtE1gorvBdy8AZffGNPkEZWKCKqDqP80l 3EcqIKSWu6ingH3W4MtQNQWwim3itO87IYFtsGUQaSAAn+iYD3O/LePrJ1StndBHpsyW ejPZxowtLjx84Ig0Diknll3eT2VFYUf54vkO88sQ8VwBf7ldP89+pekZvogYm7KyR360 c8Zd09ME09s34ApwXNZfba1JgPmT67eDDRXEL2d/Pyu+T9S1Kqkh1eRL2RnMNPCT8FFw pwrTBtSTvysXtTMEpRe6GVJLpIfubX6rFJrebaXQ/WN6+KYeXeA/Wkxk6XIe3SSfsiXj vy9A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=uQcMUZXp; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id b30si1712643pla.308.2019.02.25.13.35.33; Mon, 25 Feb 2019 13:35:48 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=uQcMUZXp; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729114AbfBYVfO (ORCPT + 99 others); Mon, 25 Feb 2019 16:35:14 -0500 Received: from mail.kernel.org ([198.145.29.99]:41284 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732305AbfBYVfL (ORCPT ); Mon, 25 Feb 2019 16:35:11 -0500 Received: from localhost (5356596B.cm-6-7b.dynamic.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 902E4217F5; Mon, 25 Feb 2019 21:35:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1551130510; bh=zypTq7TrXKBD/ZFT5L6raSxhy5ouApkzJXffRJ5er14=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uQcMUZXpAG6Q+jhuT5VHUt0ucG7Waw8V2Yx4cOxBmcinllE/+KzMST7XKFVnmw4qx MTyxOq2mxEqOPK6UPn60NcDIe/bY7uPx8mzrvks265PUkweEkZ3KlgaFr/y8bA2jmH J57SZISloEDthHCkI9CfhQGMZ/iFqNmEQRWhJfDw= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, David Howells , Sasha Levin Subject: [PATCH 4.20 105/183] afs: Fix race in async call refcounting Date: Mon, 25 Feb 2019 22:11:18 +0100 Message-Id: <20190225195112.384271892@linuxfoundation.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190225195054.748060397@linuxfoundation.org> References: <20190225195054.748060397@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review X-Patchwork-Hint: ignore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.20-stable review patch. If anyone has any objections, please let me know. ------------------ [ Upstream commit 34fa47612bfe5d7de7fcaf658a6952b6aeec3b13 ] There's a race between afs_make_call() and afs_wake_up_async_call() in the case that an error is returned from rxrpc_kernel_send_data() after it has queued the final packet. afs_make_call() will try and clean up the mess, but the call state may have been moved on thereby causing afs_process_async_call() to also try and to delete the call. Fix this by: (1) Getting an extra ref for an asynchronous call for the call itself to hold. This makes sure the call doesn't evaporate on us accidentally and will allow the call to be retained by the caller in a future patch. The ref is released on leaving afs_make_call() or afs_wait_for_call_to_complete(). (2) In the event of an error from rxrpc_kernel_send_data(): (a) Don't set the call state to AFS_CALL_COMPLETE until *after* the call has been aborted and ended. This prevents afs_deliver_to_call() from doing anything with any notifications it gets. (b) Explicitly end the call immediately to prevent further callbacks. (c) Cancel any queued async_work and wait for the work if it's executing. This allows us to be sure the race won't recur when we change the state. We put the work queue's ref on the call if we managed to cancel it. (d) Put the call's ref that we got in (1). This belongs to us as long as the call is in state AFS_CALL_CL_REQUESTING. Fixes: 341f741f04be ("afs: Refcount the afs_call struct") Signed-off-by: David Howells Signed-off-by: Sasha Levin --- fs/afs/rxrpc.c | 35 ++++++++++++++++++++++++++++++----- include/trace/events/afs.h | 2 ++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 4830e0a6bf1d1..2c588f9bbbda2 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -23,6 +23,7 @@ struct workqueue_struct *afs_async_calls; static void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long); static long afs_wait_for_call_to_complete(struct afs_call *, struct afs_addr_cursor *); static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long); +static void afs_delete_async_call(struct work_struct *); static void afs_process_async_call(struct work_struct *); static void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long); static void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long); @@ -404,6 +405,12 @@ long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, } } + /* If the call is going to be asynchronous, we need an extra ref for + * the call to hold itself so the caller need not hang on to its ref. + */ + if (call->async) + afs_get_call(call, afs_call_trace_get); + /* create a call */ rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key, (unsigned long)call, @@ -444,15 +451,17 @@ long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, goto error_do_abort; } - /* at this point, an async call may no longer exist as it may have - * already completed */ - if (call->async) + /* Note that at this point, we may have received the reply or an abort + * - and an asynchronous call may already have completed. + */ + if (call->async) { + afs_put_call(call); return -EINPROGRESS; + } return afs_wait_for_call_to_complete(call, ac); error_do_abort: - call->state = AFS_CALL_COMPLETE; if (ret != -ECONNABORTED) { rxrpc_kernel_abort_call(call->net->socket, rxcall, RX_USER_ABORT, ret, "KSD"); @@ -469,8 +478,24 @@ long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, error_kill_call: if (call->type->done) call->type->done(call); - afs_put_call(call); + + /* We need to dispose of the extra ref we grabbed for an async call. + * The call, however, might be queued on afs_async_calls and we need to + * make sure we don't get any more notifications that might requeue it. + */ + if (call->rxcall) { + rxrpc_kernel_end_call(call->net->socket, call->rxcall); + call->rxcall = NULL; + } + if (call->async) { + if (cancel_work_sync(&call->async_work)) + afs_put_call(call); + afs_put_call(call); + } + ac->error = ret; + call->state = AFS_CALL_COMPLETE; + afs_put_call(call); _leave(" = %d", ret); return ret; } diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h index 33d291888ba9c..e3f005eae1f76 100644 --- a/include/trace/events/afs.h +++ b/include/trace/events/afs.h @@ -25,6 +25,7 @@ enum afs_call_trace { afs_call_trace_alloc, afs_call_trace_free, + afs_call_trace_get, afs_call_trace_put, afs_call_trace_wake, afs_call_trace_work, @@ -159,6 +160,7 @@ enum afs_file_error { #define afs_call_traces \ EM(afs_call_trace_alloc, "ALLOC") \ EM(afs_call_trace_free, "FREE ") \ + EM(afs_call_trace_get, "GET ") \ EM(afs_call_trace_put, "PUT ") \ EM(afs_call_trace_wake, "WAKE ") \ E_(afs_call_trace_work, "WORK ") -- 2.19.1