FAILED: patch "[PATCH] procfs: avoid fetching build ID while holding VMA lock" failed to apply to 6.12-stable tree
Subsystems (6)
[email protected]
maintainerThe patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x b5cbacd7f86f4f62b8813688c8e73be94e8e1951
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026020723-clumsily-tying-5d25@gregkh' --subject-prefix 'PATCH 6.12.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From b5cbacd7f86f4f62b8813688c8e73be94e8e1951 Mon Sep 17 00:00:00 2001
From: Andrii Nakryiko <[email protected]>
Date: Thu, 29 Jan 2026 13:53:40 -0800
Subject: [PATCH] procfs: avoid fetching build ID while holding VMA lock
Fix PROCMAP_QUERY to fetch optional build ID only after dropping mmap_lock or per-VMA lock, whichever was used to lock VMA under question, to avoid deadlock reported by syzbot:
-> #1 (&mm->mmap_lock){++++}-{4:4}:
__might_fault+0xed/0x170
_copy_to_iter+0x118/0x1720
copy_page_to_iter+0x12d/0x1e0
filemap_read+0x720/0x10a0
blkdev_read_iter+0x2b5/0x4e0
vfs_read+0x7f4/0xae0
ksys_read+0x12a/0x250
do_syscall_64+0xcb/0xf80
entry_SYSCALL_64_after_hwframe+0x77/0x7f-> #0 (&sb->s_type->i_mutex_key#8){++++}-{4:4}:
__lock_acquire+0x1509/0x26d0
lock_acquire+0x185/0x340
down_read+0x98/0x490
blkdev_read_iter+0x2a7/0x4e0
__kernel_read+0x39a/0xa90
freader_fetch+0x1d5/0xa80
__build_id_parse.isra.0+0xea/0x6a0
do_procmap_query+0xd75/0x1050
procfs_procmap_ioctl+0x7a/0xb0
__x64_sys_ioctl+0x18e/0x210
do_syscall_64+0xcb/0xf80
entry_SYSCALL_64_after_hwframe+0x77/0x7fother info that might help us debug this:
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
rlock(&mm->mmap_lock);
lock(&sb->s_type->i_mutex_key#8);
lock(&mm->mmap_lock); rlock(&sb->s_type->i_mutex_key#8);
*** DEADLOCK ***
This seems to be exacerbated (as we haven't seen these syzbot reports before that) by the recent:
777a8560fd29 ("lib/buildid: use __kernel_read() for sleepable context")To make this safe, we need to grab file refcount while VMA is still locked, but other than that everything is pretty straightforward. Internal build_id_parse() API assumes VMA is passed, but it only needs the underlying file reference, so just add another variant build_id_parse_file() that expects file passed directly.
fs/proc/task_mmu.c +27 -15
@@ -656,6 +656,7 @@ static int do_procmap_query(struct mm_struct *mm, void __user *uarg)struct proc_maps_locking_ctx lock_ctx = { .mm = mm };struct procmap_query karg;struct vm_area_struct *vma; +struct file *vm_file =NULL ;const char *name =NULL ;char build_id_buf[BUILD_ID_SIZE_MAX ], *name_buf =NULL ;__u64 usize;
@@ -727,21 +728,6 @@ static int do_procmap_query(struct mm_struct *mm, void __user *uarg) karg.inode =0 ; } -if (karg.build_id_size) { -__u32 build_id_sz; - - err =build_id_parse (vma, build_id_buf, &build_id_sz); -if (err) { - karg.build_id_size =0 ; - }else { -if (karg.build_id_size < build_id_sz) { - err = -ENAMETOOLONG ; - goto out; - } - karg.build_id_size = build_id_sz; - } - } -if (karg.vma_name_size) {size_t name_buf_sz =min_t (size_t,PATH_MAX , karg.vma_name_size);const struct path *path;
@@ -775,10 +761,34 @@ static int do_procmap_query(struct mm_struct *mm, void __user *uarg) karg.vma_name_size = name_sz; } +if (karg.build_id_size && vma->vm_file) + vm_file =get_file (vma->vm_file); +/* unlock vma or mmap_lock, and put mm_struct before copying data to user */ query_vma_teardown (&lock_ctx);mmput (mm); +if (karg.build_id_size) { +__u32 build_id_sz; + +if (vm_file) + err =build_id_parse_file (vm_file, build_id_buf, &build_id_sz); +else + err = -ENOENT ; +if (err) { + karg.build_id_size =0 ; + }else { +if (karg.build_id_size < build_id_sz) { + err = -ENAMETOOLONG ; + goto out; + } + karg.build_id_size = build_id_sz; + } + } + +if (vm_file) +fput (vm_file); +if (karg.vma_name_size &©_to_user (u64_to_user_ptr (karg.vma_name_addr), name, karg.vma_name_size)) {kfree (name_buf);
@@ -798,6 +808,8 @@ static int do_procmap_query(struct mm_struct *mm, void __user *uarg) out:query_vma_teardown (&lock_ctx);mmput (mm); +if (vm_file) +fput (vm_file);kfree (name_buf);return err; }
include/linux/buildid.h +3 -0
@@ -7,7 +7,10 @@#define BUILD_ID_SIZE_MAX 20struct vm_area_struct ; +struct file ; +int build_id_parse (struct vm_area_struct *vma,unsigned char *build_id,__u32 *size); +int build_id_parse_file (struct file *file,unsigned char *build_id,__u32 *size);int build_id_parse_nofault (struct vm_area_struct *vma,unsigned char *build_id,__u32 *size);int build_id_parse_buf (const void *buf,unsigned char *build_id,u32 buf_size);
lib/buildid.c +30 -12
74 lines not on this page · raw message
Sasha Levin
maintainerPATCH 1/1 procfs: avoid fetching build ID while holding VMA lock
From: Andrii Nakryiko <[email protected]>
[ Upstream commit b5cbacd7f86f4f62b8813688c8e73be94e8e1951 ]
Fix PROCMAP_QUERY to fetch optional build ID only after dropping mmap_lock or per-VMA lock, whichever was used to lock VMA under question, to avoid deadlock reported by syzbot:
-> #1 (&mm->mmap_lock){++++}-{4:4}:
__might_fault+0xed/0x170
_copy_to_iter+0x118/0x1720
copy_page_to_iter+0x12d/0x1e0
filemap_read+0x720/0x10a0
blkdev_read_iter+0x2b5/0x4e0
vfs_read+0x7f4/0xae0
ksys_read+0x12a/0x250
do_syscall_64+0xcb/0xf80
entry_SYSCALL_64_after_hwframe+0x77/0x7f-> #0 (&sb->s_type->i_mutex_key#8){++++}-{4:4}:
__lock_acquire+0x1509/0x26d0
lock_acquire+0x185/0x340
down_read+0x98/0x490
blkdev_read_iter+0x2a7/0x4e0
__kernel_read+0x39a/0xa90
freader_fetch+0x1d5/0xa80
__build_id_parse.isra.0+0xea/0x6a0
do_procmap_query+0xd75/0x1050
procfs_procmap_ioctl+0x7a/0xb0
__x64_sys_ioctl+0x18e/0x210
do_syscall_64+0xcb/0xf80
entry_SYSCALL_64_after_hwframe+0x77/0x7fother info that might help us debug this:
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
rlock(&mm->mmap_lock);
lock(&sb->s_type->i_mutex_key#8);
lock(&mm->mmap_lock); rlock(&sb->s_type->i_mutex_key#8);
*** DEADLOCK ***
This seems to be exacerbated (as we haven't seen these syzbot reports before that) by the recent:
777a8560fd29 ("lib/buildid: use __kernel_read() for sleepable context")To make this safe, we need to grab file refcount while VMA is still locked, but other than that everything is pretty straightforward. Internal build_id_parse() API assumes VMA is passed, but it only needs the underlying file reference, so just add another variant build_id_parse_file() that expects file passed directly.
--- fs/proc/task_mmu.c | 42 ++++++++++++++++++++++++++--------------- include/linux/buildid.h | 3 +++ lib/buildid.c | 42 +++++++++++++++++++++++++++++------------ 3 files changed, 60 insertions(+), 27 deletions(-)
fs/proc/task_mmu.c +27 -15
@@ -456,6 +456,7 @@ static int do_procmap_query(struct proc_maps_private *priv, void __user *uarg)struct procmap_query karg;struct vm_area_struct *vma;struct mm_struct *mm; +struct file *vm_file =NULL ;const char *name =NULL ;char build_id_buf[BUILD_ID_SIZE_MAX ], *name_buf =NULL ;__u64 usize;
@@ -528,21 +529,6 @@ static int do_procmap_query(struct proc_maps_private *priv, void __user *uarg) karg.inode =0 ; } -if (karg.build_id_size) { -__u32 build_id_sz; - - err =build_id_parse (vma, build_id_buf, &build_id_sz); -if (err) { - karg.build_id_size =0 ; - }else { -if (karg.build_id_size < build_id_sz) { - err = -ENAMETOOLONG ; - goto out; - } - karg.build_id_size = build_id_sz; - } - } -if (karg.vma_name_size) {size_t name_buf_sz =min_t (size_t,PATH_MAX , karg.vma_name_size);const struct path *path;
@@ -576,10 +562,34 @@ static int do_procmap_query(struct proc_maps_private *priv, void __user *uarg) karg.vma_name_size = name_sz; } +if (karg.build_id_size && vma->vm_file) + vm_file =get_file (vma->vm_file); +/* unlock vma or mmap_lock, and put mm_struct before copying data to user */ query_vma_teardown (mm, vma);mmput (mm); +if (karg.build_id_size) { +__u32 build_id_sz; + +if (vm_file) + err =build_id_parse_file (vm_file, build_id_buf, &build_id_sz); +else + err = -ENOENT ; +if (err) { + karg.build_id_size =0 ; + }else { +if (karg.build_id_size < build_id_sz) { + err = -ENAMETOOLONG ; + goto out; + } + karg.build_id_size = build_id_sz; + } + } + +if (vm_file) +fput (vm_file); +if (karg.vma_name_size &©_to_user (u64_to_user_ptr (karg.vma_name_addr), name, karg.vma_name_size)) {kfree (name_buf);
@@ -599,6 +609,8 @@ static int do_procmap_query(struct proc_maps_private *priv, void __user *uarg) out:query_vma_teardown (mm, vma);mmput (mm); +if (vm_file) +fput (vm_file);kfree (name_buf);return err; }
include/linux/buildid.h +3 -0
@@ -7,7 +7,10 @@#define BUILD_ID_SIZE_MAX 20struct vm_area_struct ; +struct file ; +int build_id_parse (struct vm_area_struct *vma,unsigned char *build_id,__u32 *size); +int build_id_parse_file (struct file *file,unsigned char *build_id,__u32 *size);int build_id_parse_nofault (struct vm_area_struct *vma,unsigned char *build_id,__u32 *size);int build_id_parse_buf (const void *buf,unsigned char *build_id,u32 buf_size);
lib/buildid.c +30 -12
74 lines not on this page · raw message
Signature · 1 line
2.51.0