The patch titled Subject: fs/proc/vmcore: disallow vmcore modifications while the vmcore is open has been added to the -mm mm-unstable branch. Its filename is fs-proc-vmcore-disallow-vmcore-modifications-while-the-vmcore-is-open.patch This patch will shortly appear at https://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new.git/tree/patches/fs-proc-vmcore-disallow-vmcore-modifications-while-the-vmcore-is-open.patch This patch will later appear in the mm-unstable branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/process/submit-checklist.rst when testing your code *** The -mm tree is included into linux-next via the mm-everything branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm and is updated there every 2-3 working days ------------------------------------------------------ From: David Hildenbrand <david@xxxxxxxxxx> Subject: fs/proc/vmcore: disallow vmcore modifications while the vmcore is open Date: Wed, 4 Dec 2024 13:54:34 +0100 The vmcoredd_update_size() call and its effects (size/offset changes) are currently completely unsynchronized, and will cause trouble when performed concurrently, or when done while someone is already reading the vmcore. Let's protect all vmcore modifications by the vmcore_mutex, disallow vmcore modifications while the vmcore is open, and warn on vmcore modifications after the vmcore was already opened once: modifications while the vmcore is open are unsafe, and modifications after the vmcore was opened indicates trouble. Properly synchronize against concurrent opening of the vmcore. No need to grab the mutex during mmap()/read(): after we opened the vmcore, modifications are impossible. It's worth noting that modifications after the vmcore was opened are completely unexpected, so failing if open, and warning if already opened (+closed again) is good enough. This change not only handles concurrent adding of device dumps + concurrent reading of the vmcore properly, it also prepares for other mechanisms that will modify the vmcore. Link: https://lkml.kernel.org/r/20241204125444.1734652-4-david@xxxxxxxxxx Signed-off-by: David Hildenbrand <david@xxxxxxxxxx> Cc: Alexander Gordeev <agordeev@xxxxxxxxxxxxx> Cc: Baoquan He <bhe@xxxxxxxxxx> Cc: Christian Borntraeger <borntraeger@xxxxxxxxxxxxx> Cc: Claudio Imbrenda <imbrenda@xxxxxxxxxxxxx> Cc: Cornelia Huck <cohuck@xxxxxxxxxx> Cc: Dave Young <dyoung@xxxxxxxxxx> Cc: Eric Farman <farman@xxxxxxxxxxxxx> Cc: Eugenio Pérez <eperezma@xxxxxxxxxx> Cc: Heiko Carstens <hca@xxxxxxxxxxxxx> Cc: Janosch Frank <frankja@xxxxxxxxxxxxx> Cc: Jason Wang <jasowang@xxxxxxxxxx> Cc: Michael S. Tsirkin <mst@xxxxxxxxxx> Cc: Sven Schnelle <svens@xxxxxxxxxxxxx> Cc: Thomas Huth <thuth@xxxxxxxxxx> Cc: Vasily Gorbik <gor@xxxxxxxxxxxxx> Cc: Vivek Goyal <vgoyal@xxxxxxxxxx> Cc: Xuan Zhuo <xuanzhuo@xxxxxxxxxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- fs/proc/vmcore.c | 57 ++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 23 deletions(-) --- a/fs/proc/vmcore.c~fs-proc-vmcore-disallow-vmcore-modifications-while-the-vmcore-is-open +++ a/fs/proc/vmcore.c @@ -68,6 +68,8 @@ DEFINE_STATIC_SRCU(vmcore_cb_srcu); static LIST_HEAD(vmcore_cb_list); /* Whether the vmcore has been opened once. */ static bool vmcore_opened; +/* Whether the vmcore is currently open. */ +static unsigned int vmcore_open; void register_vmcore_cb(struct vmcore_cb *cb) { @@ -122,6 +124,20 @@ static int open_vmcore(struct inode *ino { mutex_lock(&vmcore_mutex); vmcore_opened = true; + if (vmcore_open + 1 == 0) { + mutex_unlock(&vmcore_mutex); + return -EBUSY; + } + vmcore_open++; + mutex_unlock(&vmcore_mutex); + + return 0; +} + +static int release_vmcore(struct inode *inode, struct file *file) +{ + mutex_lock(&vmcore_mutex); + vmcore_open--; mutex_unlock(&vmcore_mutex); return 0; @@ -243,33 +259,27 @@ static int vmcoredd_copy_dumps(struct io { struct vmcoredd_node *dump; u64 offset = 0; - int ret = 0; size_t tsz; char *buf; - mutex_lock(&vmcore_mutex); list_for_each_entry(dump, &vmcoredd_list, list) { if (start < offset + dump->size) { tsz = min(offset + (u64)dump->size - start, (u64)size); buf = dump->buf + start - offset; - if (copy_to_iter(buf, tsz, iter) < tsz) { - ret = -EFAULT; - goto out_unlock; - } + if (copy_to_iter(buf, tsz, iter) < tsz) + return -EFAULT; size -= tsz; start += tsz; /* Leave now if buffer filled already */ if (!size) - goto out_unlock; + return 0; } offset += dump->size; } -out_unlock: - mutex_unlock(&vmcore_mutex); - return ret; + return 0; } #ifdef CONFIG_MMU @@ -278,20 +288,16 @@ static int vmcoredd_mmap_dumps(struct vm { struct vmcoredd_node *dump; u64 offset = 0; - int ret = 0; size_t tsz; char *buf; - mutex_lock(&vmcore_mutex); list_for_each_entry(dump, &vmcoredd_list, list) { if (start < offset + dump->size) { tsz = min(offset + (u64)dump->size - start, (u64)size); buf = dump->buf + start - offset; if (remap_vmalloc_range_partial(vma, dst, buf, 0, - tsz)) { - ret = -EFAULT; - goto out_unlock; - } + tsz)) + return -EFAULT; size -= tsz; start += tsz; @@ -299,14 +305,12 @@ static int vmcoredd_mmap_dumps(struct vm /* Leave now if buffer filled already */ if (!size) - goto out_unlock; + return 0; } offset += dump->size; } -out_unlock: - mutex_unlock(&vmcore_mutex); - return ret; + return 0; } #endif /* CONFIG_MMU */ #endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */ @@ -691,6 +695,7 @@ static int mmap_vmcore(struct file *file static const struct proc_ops vmcore_proc_ops = { .proc_open = open_vmcore, + .proc_release = release_vmcore, .proc_read_iter = read_vmcore, .proc_lseek = default_llseek, .proc_mmap = mmap_vmcore, @@ -1516,12 +1521,18 @@ int vmcore_add_device_dump(struct vmcore dump->buf = buf; dump->size = data_size; - /* Add the dump to driver sysfs list */ + /* Add the dump to driver sysfs list and update the elfcore hdr */ mutex_lock(&vmcore_mutex); - list_add_tail(&dump->list, &vmcoredd_list); - mutex_unlock(&vmcore_mutex); + if (vmcore_opened) + pr_warn_once("Unexpected adding of device dump\n"); + if (vmcore_open) { + ret = -EBUSY; + goto out_err; + } + list_add_tail(&dump->list, &vmcoredd_list); vmcoredd_update_size(data_size); + mutex_unlock(&vmcore_mutex); return 0; out_err: _ Patches currently in -mm which might be from david@xxxxxxxxxx are mm-mempolicy-fix-migrate_to_node-assuming-there-is-at-least-one-vma-in-a-mm.patch mm-filemap-dont-call-folio_test_locked-without-a-reference-in-next_uptodate_folio.patch docs-tmpfs-update-the-large-folios-policy-for-tmpfs-and-shmem.patch mm-memory_hotplug-move-debug_pagealloc_map_pages-into-online_pages_range.patch mm-page_isolation-dont-pass-gfp-flags-to-isolate_single_pageblock.patch mm-page_isolation-dont-pass-gfp-flags-to-start_isolate_page_range.patch mm-page_alloc-make-__alloc_contig_migrate_range-static.patch mm-page_alloc-sort-out-the-alloc_contig_range-gfp-flags-mess.patch mm-page_alloc-forward-the-gfp-flags-from-alloc_contig_range-to-post_alloc_hook.patch powernv-memtrace-use-__gfp_zero-with-alloc_contig_pages.patch mm-hugetlb-dont-map-folios-writable-without-vm_write-when-copying-during-fork.patch fs-proc-vmcore-convert-vmcore_cb_lock-into-vmcore_mutex.patch fs-proc-vmcore-replace-vmcoredd_mutex-by-vmcore_mutex.patch fs-proc-vmcore-disallow-vmcore-modifications-while-the-vmcore-is-open.patch fs-proc-vmcore-prefix-all-pr_-with-vmcore.patch fs-proc-vmcore-move-vmcore-definitions-out-of-kcoreh.patch fs-proc-vmcore-factor-out-allocating-a-vmcore-range-and-adding-it-to-a-list.patch fs-proc-vmcore-factor-out-freeing-a-list-of-vmcore-ranges.patch fs-proc-vmcore-introduce-proc_vmcore_device_ram-to-detect-device-ram-ranges-in-2nd-kernel.patch virtio-mem-mark-device-ready-before-registering-callbacks-in-kdump-mode.patch virtio-mem-remember-usable-region-size.patch virtio-mem-support-config_proc_vmcore_device_ram.patch s390-kdump-virtio-mem-kdump-support-config_proc_vmcore_device_ram.patch