From: Chuck Lever chuck.lever@oracle.com
mainline inclusion from mainline-v6.12-rc1 commit aadc3bbea163b6caaaebfdd2b6c4667fbc726752 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/IAYR9C CVE: CVE-2024-49974
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
----------------------------------------------------------------------
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 jlayton@kernel.org Signed-off-by: Chuck Lever chuck.lever@oracle.com
Conflicts: fs/nfsd/nfs4proc.c fs/nfsd/xdr4.h [Commit 87689df69491("NFSD: Shrink size of struct nfsd4_copy") add freeing of copy->cp_src in nfs4_put_copy; Commit 1913cdf56cb5("NFSD: Replace boolean fields in struct nfsd4_copy") replace copy->cp_synchronous with nfsd4_copy_is_async in nfsd4_copy; Commit 9ed666eba4e0("NFSD: Async COPY result needs to return a write verifier") move net_generic to the begining of nfsd4_copy; Commit 81e722978ad2("NFSD: fix problems with cleanup on errors in nfsd4_copy") add the initialization of async_copy->copies in nfsd4_copy; Commit 34e8f9ec4c9a("NFSD: fix leaked reference count of nfsd4_ssc_umount_item") remove the comment at the end of nfsd4_copy; Commit df24ac7a2e3a("NFSD: enhance inter-server copy cleanup") removed ss_mnt and add ss_nsui in nfsd4_copy; Commit 1913cdf56cb5("NFSD: Replace boolean fields in struct nfsd4_copy") add nfsd4_copy_set_sync after nfsd4_copy; Commit 75333d48f922("NFSD: fix use-after-free in __nfs42_ssc_open()") remove nfsd4_interssc_disconnect(); Commit 34e8f9ec4c9a("NFSD: fix leaked reference count of nfsd4_ssc_umount_item") moved the position of the comment.] Signed-off-by: Li Lingfeng lilingfeng3@huawei.com --- 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 7346acda9d76..04360a51a16f 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -128,6 +128,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 4344b5d98318..7bca44450d27 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1111,6 +1111,7 @@ void nfs4_put_copy(struct nfsd4_copy *copy) { if (!refcount_dec_and_test(©->refcount)) return; + atomic_dec(©->cp_nn->pending_async_copies); kfree(copy); }
@@ -1534,10 +1535,16 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (!copy->cp_synchronous) { struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
- 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; + } if (!nfs4_init_copy_state(nn, copy)) goto out_err; refcount_set(&async_copy->refcount, 1); @@ -1562,7 +1569,7 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, out_err: if (async_copy) cleanup_async_copy(async_copy); - status = nfserrno(-ENOMEM); + status = nfserr_jukebox; if (!copy->cp_intra) nfsd4_interssc_disconnect(copy->ss_mnt); goto out; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 665d0eaeb8db..36d1ee0d7846 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -7327,6 +7327,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 679d40af1bbb..1ced060704a3 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -579,6 +579,7 @@ struct nfsd4_copy { struct vfsmount *ss_mnt; struct nfs_fh c_fh; nfs4_stateid stateid; + struct nfsd_net *cp_nn; }; extern bool inter_copy_offload_enable;
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/12657 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/B...
FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/12657 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/B...