hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IB20ED
--------------------------------
Commit b5e9ee1ed8bb("[Huawei] NFSv4: release seqid when open failed for nfs4.0") describes a scenario where a file system is forcibly unmounted when different files are opened concurrently. There is another similar issue where performing concurrent operations of opening file B, closing file A, and unmounting while file A is open which can trigger a UAF of rpc_task.
T1: OPEN fileB T2: CLOSE fileA nfs4_do_open ... .rpc_call_prepare nfs_wait_on_sequence // insert to sequence list(T1) // This is the first entry, // and continue. nfs4_do_close .rpc_call_prepare nfs_wait_on_sequence // insert to sequence list(T2) // This is the second entry, // and wait. [T3 wake up T2 here] ... rpc_put_task // finish rpc_task and free it .rpc_call_done nfs_release_seqid list_first_entry // get T1 from list rpc_wake_up_queued_task // wake up T1, UAF _nfs4_open_and_get_state _nfs4_open_and_get_state _nfs4_opendata_to_nfs4_state nfs_release_seqid // remove T1 from list
T3: UMOUNT nfs_umount_begin rpc_killall_tasks rpc_signal_task // get T2 from clnt->cl_tasks rpc_wake_up_queued_task_set_status rpc_wake_up_task_queue_set_status_locked rpc_wake_up_task_on_wq_queue_action_locked __rpc_do_wake_up_task_on_wq rpc_make_runnable wake_up_bit // wake up T2
Although the rpc_task corresponding to T1 has been freed, its seqid has not been removed from the sequence list. Additionally, even though T2 is the last task in the list, the current logic of nfs_release_seqid allows T2 to access tasks inserted before it, which can trigger UAF.
Fix it by using nfs_release_seqid_inorder instead of nfs_release_seqid in nfs4_close_done.
Fixes: 72211dbe727f ("NFSv4: Release the sequence id before restarting a CLOSE rpc call") Link: https://lore.kernel.org/all/b9924cd2-253a-6c44-3331-56310f13df0b@huawei.com/ Signed-off-by: Li Lingfeng lilingfeng3@huawei.com --- 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 944edd332309..8e57c396fd37 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(calldata->arg.seqid); + nfs_release_seqid_inorder(calldata->arg.seqid); nfs_refresh_inode(calldata->inode, &calldata->fattr); dprintk("%s: ret = %d\n", __func__, task->tk_status); return;