From 5287a532fa5f74c6f0685b1d40fe1691f06baa5c Mon Sep 17 00:00:00 2001 From: Li Lingfeng Date: Tue, 31 Dec 2024 09:56:21 +0800 Subject: [PATCH 1/4] Revert "nfs: fix rpc_task use-after-free when open and close different files concurrently" hulk inclusion category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEAFI CVE: CVE-2024-53173 -------------------------------- This reverts commit 4f97f8597cf1cac4dd2a5834197b9a7b221dcaff. The issue is resolved by replace nfs_release_seqid with nfs_release_seqid_inorder. The later patch will change nfs_release_seqid directly and nfs_release_seqid_inorder will be not necessary any more. Fixes: 4f97f8597cf1 ("nfs: fix rpc_task use-after-free when open and close different files concurrently") Signed-off-by: Li Lingfeng --- fs/nfs/nfs4proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8e57c396fd37..944edd332309 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3612,7 +3612,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) res_stateid, calldata->arg.fmode); out_release: task->tk_status = 0; - nfs_release_seqid_inorder(calldata->arg.seqid); + nfs_release_seqid(calldata->arg.seqid); nfs_refresh_inode(calldata->inode, &calldata->fattr); dprintk("%s: ret = %d\n", __func__, task->tk_status); return; -- Gitee From 6994114f2e72314ece9f49c9f2283a995de9ff97 Mon Sep 17 00:00:00 2001 From: Li Lingfeng Date: Tue, 31 Dec 2024 09:56:22 +0800 Subject: [PATCH 2/4] Revert "NFSv4: release seqid when open failed for nfs4.0" hulk inclusion category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEAFI CVE: CVE-2024-53173 -------------------------------- This reverts commit 8a6f6a9db172b695e45be869e515ac87557dbfb7. The issue is resolved by replace nfs_release_seqid with nfs_release_seqid_inorder. The later patch will change nfs_release_seqid directly and nfs_release_seqid_inorder will be not necessary any more. Fixes: 8a6f6a9db172 ("NFSv4: release seqid when open failed for nfs4.0") Signed-off-by: Li Lingfeng --- fs/nfs/nfs4_fs.h | 1 - fs/nfs/nfs4proc.c | 2 -- fs/nfs/nfs4state.c | 18 ------------------ 3 files changed, 21 deletions(-) diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 4187ce22c623..47c5c1f86d66 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -524,7 +524,6 @@ extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_ extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task); extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid); extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid); -extern void nfs_release_seqid_inorder(struct nfs_seqid *seqid); extern void nfs_release_seqid(struct nfs_seqid *seqid); extern void nfs_free_seqid(struct nfs_seqid *seqid); extern int nfs4_setup_sequence(struct nfs_client *client, diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 944edd332309..299ea2b86df6 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2528,8 +2528,6 @@ static void nfs4_open_release(void *calldata) struct nfs4_opendata *data = calldata; struct nfs4_state *state = NULL; - if (data->rpc_status != 0 || !data->rpc_done) - nfs_release_seqid_inorder(data->o_arg.seqid); /* If this request hasn't been cancelled, do nothing */ if (!data->cancelled) goto out_free; diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 099d3d8de779..794bb4aa588d 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1087,24 +1087,6 @@ struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_m return new; } -void nfs_release_seqid_inorder(struct nfs_seqid *seqid) -{ - struct nfs_seqid_counter *sequence; - - if (seqid == NULL || list_empty(&seqid->list)) - return; - sequence = seqid->sequence; - spin_lock(&sequence->lock); - if (!list_is_last(&seqid->list, &sequence->list)) { - struct nfs_seqid *next; - - next = list_next_entry(seqid, list); - rpc_wake_up_queued_task(&sequence->wait, next->task); - } - list_del_init(&seqid->list); - spin_unlock(&sequence->lock); -} - void nfs_release_seqid(struct nfs_seqid *seqid) { struct nfs_seqid_counter *sequence; -- Gitee From 19b015b5b16504e10995396627e565d90882b61d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 31 Dec 2024 09:56:23 +0800 Subject: [PATCH 3/4] NFSv4.0: Fix the wake up of the next waiter in nfs_release_seqid() mainline inclusion from mainline-v6.13-rc1 commit c968fd23c68e9929ab6cad4faffc8ea603e98e5d category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IBBR8I CVE: CVE-2024-53173 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c968fd23c68e9929ab6cad4faffc8ea603e98e5d -------------------------------- There is no need to wake up another waiter on the seqid list unless the seqid being removed is at the head of the list, and so is relinquishing control of the sequence counter to the next entry. Reviewed-by: Yang Erkun Signed-off-by: Trond Myklebust Signed-off-by: Li Lingfeng --- fs/nfs/nfs4state.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 794bb4aa588d..8515d3db7166 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1095,14 +1095,12 @@ void nfs_release_seqid(struct nfs_seqid *seqid) return; sequence = seqid->sequence; spin_lock(&sequence->lock); - list_del_init(&seqid->list); - if (!list_empty(&sequence->list)) { - struct nfs_seqid *next; - - next = list_first_entry(&sequence->list, - struct nfs_seqid, list); + if (list_is_first(&seqid->list, &sequence->list) && + !list_is_singular(&sequence->list)) { + struct nfs_seqid *next = list_next_entry(seqid, list); rpc_wake_up_queued_task(&sequence->wait, next->task); } + list_del_init(&seqid->list); spin_unlock(&sequence->lock); } -- Gitee From e05408647da2a93c59293706c41f0a38cf774918 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 31 Dec 2024 09:56:24 +0800 Subject: [PATCH 4/4] NFSv4.0: Fix a use-after-free problem in the asynchronous open() stable inclusion from stable-v6.6.64 commit 229a30ed42bb87bcb044c5523fabd9e4f0e75648 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IBBR8I CVE: CVE-2024-53173 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=229a30ed42bb87bcb044c5523fabd9e4f0e75648 -------------------------------- [ Upstream commit 2fdb05dc0931250574f0cb0ebeb5ed8e20f4a889 ] Yang Erkun reports that when two threads are opening files at the same time, and are forced to abort before a reply is seen, then the call to nfs_release_seqid() in nfs4_opendata_free() can result in a use-after-free of the pointer to the defunct rpc task of the other thread. The fix is to ensure that if the RPC call is aborted before the call to nfs_wait_on_sequence() is complete, then we must call nfs_release_seqid() in nfs4_open_release() before the rpc_task is freed. Reported-by: Yang Erkun Fixes: 24ac23ab88df ("NFSv4: Convert open() into an asynchronous RPC call") Reviewed-by: Yang Erkun Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin Signed-off-by: Li Lingfeng --- fs/nfs/nfs4proc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 299ea2b86df6..4b12e45f5753 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2528,12 +2528,14 @@ static void nfs4_open_release(void *calldata) struct nfs4_opendata *data = calldata; struct nfs4_state *state = NULL; + /* In case of error, no cleanup! */ + if (data->rpc_status != 0 || !data->rpc_done) { + nfs_release_seqid(data->o_arg.seqid); + goto out_free; + } /* If this request hasn't been cancelled, do nothing */ if (!data->cancelled) goto out_free; - /* In case of error, no cleanup! */ - if (data->rpc_status != 0 || !data->rpc_done) - goto out_free; /* In case we need an open_confirm, no cleanup! */ if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) goto out_free; -- Gitee