[PATCH OLK-5.10] ksmbd: fix use-after-free in smb_break_all_levII_oplock()
From: Namjae Jeon <linkinjeon@kernel.org> mainline inclusion from mainline-v6.15-rc3 commit 18b4fac5ef17f77fed9417d22210ceafd6525fc7 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/IC5BMS CVE: CVE-2025-37776 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- There is a room in smb_break_all_levII_oplock that can cause racy issues when unlocking in the middle of the loop. This patch use read lock to protect whole loop. Cc: stable@vger.kernel.org Reported-by: Norbert Szetei <norbert@doyensec.com> Tested-by: Norbert Szetei <norbert@doyensec.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com> Conflicts: fs/smb/server/oplock.c fs/ksmbd/oplock.c fs/smb/server/oplock.h fs/ksmbd/oplock.h [Commit 38c8a9a52082 ("smb: move client and server files to common directory fs/smb") move fs/ksmbd/ to fs/smb/server/; commit 36322523dddb ("ksmbd: fix UAF issue from opinfo->conn") splits the judgment of opinfo and opinfo->refcount, add use of brk_op->conn in smb_break_all_levII_oplock(); commit d1c189c6cb8b ("ksmbd: use rwsem instead of rwlock for lease break") replace write_lock/write_unlock by down_write/up_write; commit c8efcc786146 ("ksmbd: add support for durable handles v1/v2") add check of brk_op->conn in smb_break_all_levII_oplock(); commit bb39ed470654 ("ksmbd: fix use-after-free in ksmbd_free_work_struct") add a parameter for oplock_break().] Signed-off-by: Li Lingfeng <lilingfeng3@huawei.com> --- fs/ksmbd/oplock.c | 28 +++++++++------------------- fs/ksmbd/oplock.h | 1 - 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/fs/ksmbd/oplock.c b/fs/ksmbd/oplock.c index 3324bb226c79..a3066d78e1de 100644 --- a/fs/ksmbd/oplock.c +++ b/fs/ksmbd/oplock.c @@ -126,14 +126,6 @@ static void free_opinfo(struct oplock_info *opinfo) kfree(opinfo); } -static inline void opinfo_free_rcu(struct rcu_head *rcu_head) -{ - struct oplock_info *opinfo; - - opinfo = container_of(rcu_head, struct oplock_info, rcu_head); - free_opinfo(opinfo); -} - struct oplock_info *opinfo_get(struct ksmbd_file *fp) { struct oplock_info *opinfo; @@ -154,12 +146,12 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci) if (list_empty(&ci->m_op_list)) return NULL; - rcu_read_lock(); - opinfo = list_first_or_null_rcu(&ci->m_op_list, struct oplock_info, + read_lock(&ci->m_lock); + opinfo = list_first_entry(&ci->m_op_list, struct oplock_info, op_entry); if (opinfo && !atomic_inc_not_zero(&opinfo->refcount)) opinfo = NULL; - rcu_read_unlock(); + read_unlock(&ci->m_lock); return opinfo; } @@ -169,7 +161,7 @@ void opinfo_put(struct oplock_info *opinfo) if (!atomic_dec_and_test(&opinfo->refcount)) return; - call_rcu(&opinfo->rcu_head, opinfo_free_rcu); + free_opinfo(opinfo); } static void opinfo_add(struct oplock_info *opinfo) @@ -177,7 +169,7 @@ static void opinfo_add(struct oplock_info *opinfo) struct ksmbd_inode *ci = opinfo->o_fp->f_ci; write_lock(&ci->m_lock); - list_add_rcu(&opinfo->op_entry, &ci->m_op_list); + list_add(&opinfo->op_entry, &ci->m_op_list); write_unlock(&ci->m_lock); } @@ -191,7 +183,7 @@ static void opinfo_del(struct oplock_info *opinfo) write_unlock(&lease_list_lock); } write_lock(&ci->m_lock); - list_del_rcu(&opinfo->op_entry); + list_del(&opinfo->op_entry); write_unlock(&ci->m_lock); } @@ -1259,11 +1251,10 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp, ci = fp->f_ci; op = opinfo_get(fp); - rcu_read_lock(); - list_for_each_entry_rcu(brk_op, &ci->m_op_list, op_entry) { + read_lock(&ci->m_lock); + list_for_each_entry(brk_op, &ci->m_op_list, op_entry) { if (!atomic_inc_not_zero(&brk_op->refcount)) continue; - rcu_read_unlock(); if (brk_op->is_lease && (brk_op->o_lease->state & (~(SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_HANDLE_CACHING_LE)))) { @@ -1293,9 +1284,8 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp, oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE); next: opinfo_put(brk_op); - rcu_read_lock(); } - rcu_read_unlock(); + read_unlock(&ci->m_lock); if (op) opinfo_put(op); diff --git a/fs/ksmbd/oplock.h b/fs/ksmbd/oplock.h index e1ba363b412a..98872b7399e1 100644 --- a/fs/ksmbd/oplock.h +++ b/fs/ksmbd/oplock.h @@ -76,7 +76,6 @@ struct oplock_info { struct list_head lease_entry; wait_queue_head_t oplock_q; /* Other server threads */ wait_queue_head_t oplock_brk; /* oplock breaking wait */ - struct rcu_head rcu_head; }; struct lease_break_info { -- 2.46.1
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/19450 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/6JA... 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/19450 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/6JA...
participants (2)
-
Li Lingfeng -
patchwork bot