[PATCH 6.1] efivars: Fix "BUG: corrupted list in efivar_entry_remove"
From: Alexey Nepomnyashih
Date: Mon Feb 03 2025 - 10:11:45 EST
Prevent list corruption in efivar_entry_remove() and efivar_entry_list_del_unlock()
by verifying that an entry is still in the list (list_empty() == false) before calling
list_del(). Also reset the list pointers with INIT_LIST_HEAD() to avoid potential double-removal issues.
Ensure robust handling of entries and prevent the kernel BUG observed when list_del() was called on an
already-removed entry.
Fix https://syzkaller.appspot.com/bug?extid=246ea4feed277471958a
Syzkaller report:
list_del corruption. prev->next should be ffff0000d86d6828, but was ffff800016216e60. (prev=ffff800016216e60)
------------[ cut here ]------------
kernel BUG at lib/list_debug.c:61!
Internal error: Oops - BUG: 00000000f2000800 [#1] PREEMPT SMP
Modules linked in:
CPU: 0 PID: 4299 Comm: syz-executor237 Not tainted 6.1.119-syzkaller #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/13/2024
pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
pc : __list_del_entry_valid+0x13c/0x158 lib/list_debug.c:59
lr : __list_del_entry_valid+0x13c/0x158 lib/list_debug.c:59
Call trace:
__list_del_entry_valid+0x13c/0x158 lib/list_debug.c:59
__list_del_entry include/linux/list.h:134 [inline]
list_del include/linux/list.h:148 [inline]
efivar_entry_remove+0x38/0x110 fs/efivarfs/vars.c:493
efivarfs_destroy+0x20/0x3c fs/efivarfs/super.c:184
efivar_entry_iter+0x94/0xdc fs/efivarfs/vars.c:720
efivarfs_kill_sb+0x58/0x70 fs/efivarfs/super.c:258
deactivate_locked_super+0xac/0x124 fs/super.c:332
deactivate_super+0xf0/0x110 fs/super.c:363
cleanup_mnt+0x394/0x41c fs/namespace.c:1186
__cleanup_mnt+0x20/0x30 fs/namespace.c:1193
task_work_run+0x240/0x2f0 kernel/task_work.c:203
resume_user_mode_work include/linux/resume_user_mode.h:49 [inline]
do_notify_resume+0x2080/0x2cb8 arch/arm64/kernel/signal.c:1132
prepare_exit_to_user_mode arch/arm64/kernel/entry-common.c:137 [inline]
exit_to_user_mode arch/arm64/kernel/entry-common.c:142 [inline]
el0_svc+0x9c/0x168 arch/arm64/kernel/entry-common.c:638
el0t_64_sync_handler+0x84/0xf0 arch/arm64/kernel/entry-common.c:655
el0t_64_sync+0x18c/0x190 arch/arm64/kernel/entry.S:585
Reported-by: syzbot+75dc11...@xxxxxxxxxxxxxxxxxxxxxxxxx
Fixes: 2d82e6227ea1 ("efi: vars: Move efivar caching layer into efivarfs")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Alexey Nepomnyashih <sdl@xxxxxxxx>
---
fs/efivarfs/vars.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/fs/efivarfs/vars.c b/fs/efivarfs/vars.c
index 13bc60698955..42977138e30b 100644
--- a/fs/efivarfs/vars.c
+++ b/fs/efivarfs/vars.c
@@ -490,7 +490,10 @@ void __efivar_entry_add(struct efivar_entry *entry, struct list_head *head)
*/
void efivar_entry_remove(struct efivar_entry *entry)
{
- list_del(&entry->list);
+ if (!list_empty(&entry->list)) {
+ list_del(&entry->list);
+ INIT_LIST_HEAD(&entry->list);
+ }
}
/*
@@ -506,7 +509,10 @@ void efivar_entry_remove(struct efivar_entry *entry)
*/
static void efivar_entry_list_del_unlock(struct efivar_entry *entry)
{
- list_del(&entry->list);
+ if (!list_empty(&entry->list)) {
+ list_del(&entry->list);
+ INIT_LIST_HEAD(&entry->list);
+ }
efivar_unlock();
}
--
2.43.0