From patchwork Tue Nov 19 00:47:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuck Lever X-Patchwork-Id: 13879323 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6502E25634; Tue, 19 Nov 2024 00:47:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731977257; cv=none; b=MXa70MVnDuMJr9UtxK9uOMbZtHWc6Y79p8tmCM2cz0PV5jPNrvxOmOAOtPNv/HzHPmCFAT1MmDwljf+9/rZgHLgQRmQoIE8c502aXJ93fJNiOoiIcqTM5t8IkcDQcRlFvgg3U6eGB/yx/BH8N1iM7kVxq/C4NB/iNu6dpJ3eOc8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731977257; c=relaxed/simple; bh=azDb3efhWoEbDpj2uvsfbeMcNcSSybcxGfwNnl/LbgI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tD3jCw/BZw4js3FXTnIrXSrJhndKSfogS5QudpN2LK56jXRVZM2rlQHp40YkKrkXmgjDAZkoouhxhW5goiONDQ0x9WA5Jot7iRj8R0fbFT5s9180bRmHD364rDtiTeHzZftvGxStPjDe36Lg4oxFl8OCdJo5eISNRK5ieAQYSfQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=oT6QTF75; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="oT6QTF75" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CC2BCC4CECF; Tue, 19 Nov 2024 00:47:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1731977257; bh=azDb3efhWoEbDpj2uvsfbeMcNcSSybcxGfwNnl/LbgI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oT6QTF75J7yUrZ80RndjWF2m5lRkP+XwYOyKfPhGpBaEOnl1H38c5T903jS9DNOg7 PHBfbx1ZK9VG4PjJc3RXMOybDg6iRV5VAJn02CzuH4HkNL5yNHZlOlVBE4zEV5SD3e MbnP9PhPC4NqXKIeTzaKnOabaN/G1BRA4oogp25hqVoGmr0CWtf4T+8b2M8ZUkgzom x8XcbogiCKcii+om81pz2jlLazqUuWMebNvqVjxnM3AczdgHgQTm87EvOqU0qvwvtK E1iga99kOCx1c/BICmcIIKfwXglN3skO07oPvi2m3Rs+5qxv6sUao9oiCic5YUWYI4 QOwU+RADuDLrg== From: cel@kernel.org To: Cc: , Jeff Layton , Chuck Lever Subject: [PATCH 5.10 3/5] NFSD: Limit the number of concurrent async COPY operations Date: Mon, 18 Nov 2024 19:47:30 -0500 Message-ID: <20241119004732.4703-4-cel@kernel.org> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20241119004732.4703-1-cel@kernel.org> References: <20241119004732.4703-1-cel@kernel.org> Precedence: bulk X-Mailing-List: linux-nfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Chuck Lever [ Upstream commit aadc3bbea163b6caaaebfdd2b6c4667fbc726752 ] Nothing appears to limit the number of concurrent async COPY operations that clients can start. In addition, AFAICT each async COPY can copy an unlimited number of 4MB chunks, so can run for a long time. Thus IMO async COPY can become a DoS vector. Add a restriction mechanism that bounds the number of concurrent background COPY operations. Start simple and try to be fair -- this patch implements a per-namespace limit. An async COPY request that occurs while this limit is exceeded gets NFS4ERR_DELAY. The requesting client can choose to send the request again after a delay or fall back to a traditional read/write style copy. If there is need to make the mechanism more sophisticated, we can visit that in future patches. Cc: stable@vger.kernel.org Reviewed-by: Jeff Layton Link: https://nvd.nist.gov/vuln/detail/CVE-2024-49974 Signed-off-by: Chuck Lever --- fs/nfsd/netns.h | 1 + fs/nfsd/nfs4proc.c | 11 +++++++++-- fs/nfsd/nfs4state.c | 1 + fs/nfsd/xdr4.h | 1 + 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 548422b24a7d..41c750f34473 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -152,6 +152,7 @@ struct nfsd_net { u32 s2s_cp_cl_id; struct idr s2s_cp_stateids; spinlock_t s2s_cp_lock; + atomic_t pending_async_copies; /* * Version information diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 3a445b78edd5..9718af3c2611 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1244,6 +1244,7 @@ static void nfs4_put_copy(struct nfsd4_copy *copy) { if (!refcount_dec_and_test(©->refcount)) return; + atomic_dec(©->cp_nn->pending_async_copies); kfree(copy->cp_src); kfree(copy); } @@ -1782,10 +1783,16 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, memcpy(©->fh, &cstate->current_fh.fh_handle, sizeof(struct knfsd_fh)); if (nfsd4_copy_is_async(copy)) { - status = nfserrno(-ENOMEM); async_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL); if (!async_copy) goto out_err; + async_copy->cp_nn = nn; + /* Arbitrary cap on number of pending async copy operations */ + if (atomic_inc_return(&nn->pending_async_copies) > + (int)rqstp->rq_pool->sp_nrthreads) { + atomic_dec(&nn->pending_async_copies); + goto out_err; + } INIT_LIST_HEAD(&async_copy->copies); refcount_set(&async_copy->refcount, 1); async_copy->cp_src = kmalloc(sizeof(*async_copy->cp_src), GFP_KERNEL); @@ -1824,7 +1831,7 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, } if (async_copy) cleanup_async_copy(async_copy); - status = nfserrno(-ENOMEM); + status = nfserr_jukebox; goto out; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 18d64a9312a7..5547db4db8e6 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -8088,6 +8088,7 @@ static int nfs4_state_create_net(struct net *net) spin_lock_init(&nn->client_lock); spin_lock_init(&nn->s2s_cp_lock); idr_init(&nn->s2s_cp_stateids); + atomic_set(&nn->pending_async_copies, 0); spin_lock_init(&nn->blocked_locks_lock); INIT_LIST_HEAD(&nn->blocked_locks_lru); diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index a034b9b62137..15a617bece00 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -574,6 +574,7 @@ struct nfsd4_copy { struct nfsd4_ssc_umount_item *ss_nsui; struct nfs_fh c_fh; nfs4_stateid stateid; + struct nfsd_net *cp_nn; }; static inline void nfsd4_copy_set_sync(struct nfsd4_copy *copy, bool sync)