From: David Hildenbrand <hidden> Date: 2021-05-26 09:31:02
Looking for places where the kernel might unconditionally read
PageOffline() pages, I stumbled over /proc/kcore; turns out /proc/kcore
needs some more love to not touch some other pages we really don't want to
read -- i.e., hwpoisoned ones.
Examples for PageOffline() pages are pages inflated in a balloon,
memory unplugged via virtio-mem, and partially-present sections in
memory added by the Hyper-V balloon.
When reading pages inflated in a balloon, we essentially produce
unnecessary load in the hypervisor; holes in partially present sections in
case of Hyper-V are not accessible and already were a problem for
/proc/vmcore, fixed in makedumpfile by detecting PageOffline() pages. In
the future, virtio-mem might disallow reading unplugged memory -- marked
as PageOffline() -- in some environments, resulting in undefined behavior
when accessed; therefore, I'm trying to identify and rework all these
(corner) cases.
With this series, there is really only access via /dev/mem, /proc/vmcore
and kdb left after I ripped out /dev/kmem. kdb is an advanced corner-case
use case -- we won't care for now if someone explicitly tries to do nasty
things by reading from/writing to physical addresses we better not touch.
/dev/mem is a use case we won't support for virtio-mem, at least for now,
so we'll simply disallow mapping any virtio-mem memory via /dev/mem next.
/proc/vmcore is really only a problem when dumping the old kernel via
something that's not makedumpfile (read: basically never), however, we'll
try sanitizing that as well in the second kernel in the future.
Tested via kcore_dump:
https://github.com/schlafwandler/kcore_dump
v2 -> v3:
- "mm: introduce page_offline_(begin|end|freeze|thaw) to synchronize
setting PageOffline()"
-- Rephrased a comment as suggested by Mike
- Collected acks and rbs
v1 -> v2:
- Dropped "mm: rename and move page_is_poisoned()"
- "fs/proc/kcore: don't read offline sections, logically offline pages ..."
-- Add is_page_hwpoison() in page-flags.h along with a comment
- "mm: introduce page_offline_(begin|end|freeze|thaw) to ..."
-- s/unfreeze/thaw/
-- Add a comment to PageOffline documentation in page-flags.h
- "virtio-mem: use page_offline_(start|end) when setting PageOffline()"
-- Extend patch description
- "fs/proc/kcore: use page_offline_(freeze|thaw)"
-- Simplify freeze/thaw logic
- Collected acks/rbs
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Jason Wang <redacted>
Cc: Alexey Dobriyan <redacted>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Roman Gushchin <redacted>
Cc: Alex Shi <redacted>
Cc: Steven Price <steven.price@arm.com>
Cc: Mike Kravetz <redacted>
Cc: Aili Yao <redacted>
Cc: Jiri Bohac <redacted>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Cc: Stephen Hemminger <redacted>
Cc: Wei Liu <wei.liu@kernel.org>
Cc: Naoya Horiguchi <redacted>
Cc: linux-hyperv@vger.kernel.org
Cc: virtualization@lists.linux-foundation.org
Cc: linux-fsdevel@vger.kernel.org
Cc: linux-mm@kvack.org
David Hildenbrand (6):
fs/proc/kcore: drop KCORE_REMAP and KCORE_OTHER
fs/proc/kcore: pfn_is_ram check only applies to KCORE_RAM
fs/proc/kcore: don't read offline sections, logically offline pages
and hwpoisoned pages
mm: introduce page_offline_(begin|end|freeze|thaw) to synchronize
setting PageOffline()
virtio-mem: use page_offline_(start|end) when setting PageOffline()
fs/proc/kcore: use page_offline_(freeze|thaw)
drivers/virtio/virtio_mem.c | 2 ++
fs/proc/kcore.c | 67 ++++++++++++++++++++++++++++++-------
include/linux/kcore.h | 3 --
include/linux/page-flags.h | 22 ++++++++++++
mm/util.c | 40 ++++++++++++++++++++++
5 files changed, 118 insertions(+), 16 deletions(-)
base-commit: 6efb943b8616ec53a5e444193dccf1af9ad627b5
--
2.31.1
From: David Hildenbrand <hidden> Date: 2021-05-26 09:31:08
Commit db779ef67ffe ("proc/kcore: Remove unused kclist_add_remap()")
removed the last user of KCORE_REMAP.
Commit 595dd46ebfc1 ("vfs/proc/kcore, x86/mm/kcore: Fix SMAP fault when
dumping vsyscall user page") removed the last user of KCORE_OTHER.
Let's drop both types. While at it, also drop vaddr in "struct
kcore_list", used by KCORE_REMAP only.
Reviewed-by: Mike Rapoport <redacted>
Signed-off-by: David Hildenbrand <redacted>
---
fs/proc/kcore.c | 7 ++-----
include/linux/kcore.h | 3 ---
2 files changed, 2 insertions(+), 8 deletions(-)
From: David Hildenbrand <hidden> Date: 2021-05-26 09:31:23
Let's resturcture the code, using switch-case, and checking pfn_is_ram()
only when we are dealing with KCORE_RAM.
Reviewed-by: Mike Rapoport <redacted>
Signed-off-by: David Hildenbrand <redacted>
---
fs/proc/kcore.c | 35 +++++++++++++++++++++++++++--------
1 file changed, 27 insertions(+), 8 deletions(-)
@@ -483,25 +483,36 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)gotoout;}m=NULL;/* skip the list anchor */-}elseif(!pfn_is_ram(__pa(start)>>PAGE_SHIFT)){-if(clear_user(buffer,tsz)){-ret=-EFAULT;-gotoout;-}-}elseif(m->type==KCORE_VMALLOC){+gotoskip;+}++switch(m->type){+caseKCORE_VMALLOC:vread(buf,(char*)start,tsz);/* we have to zero-fill user buffer even if no read */if(copy_to_user(buffer,buf,tsz)){ret=-EFAULT;gotoout;}-}elseif(m->type==KCORE_USER){+break;+caseKCORE_USER:/* User page is handled prior to normal kernel page: */if(copy_to_user(buffer,(char*)start,tsz)){ret=-EFAULT;gotoout;}-}else{+break;+caseKCORE_RAM:+if(!pfn_is_ram(__pa(start)>>PAGE_SHIFT)){+if(clear_user(buffer,tsz)){+ret=-EFAULT;+gotoout;+}+break;+}+fallthrough;+caseKCORE_VMEMMAP:+caseKCORE_TEXT:if(kern_addr_valid(start)){/**Usingbouncebuffertobypassthe
From: David Hildenbrand <hidden> Date: 2021-05-26 09:31:42
A driver might set a page logically offline -- PageOffline() -- and
turn the page inaccessible in the hypervisor; after that, access to page
content can be fatal. One example is virtio-mem; while unplugged memory
-- marked as PageOffline() can currently be read in the hypervisor, this
will no longer be the case in the future; for example, when having
a virtio-mem device backed by huge pages in the hypervisor.
Some special PFN walkers -- i.e., /proc/kcore -- read content of random
pages after checking PageOffline(); however, these PFN walkers can race
with drivers that set PageOffline().
Let's introduce page_offline_(begin|end|freeze|thaw) for
synchronizing.
page_offline_freeze()/page_offline_thaw() allows for a subsystem to
synchronize with such drivers, achieving that a page cannot be set
PageOffline() while frozen.
page_offline_begin()/page_offline_end() is used by drivers that care about
such races when setting a page PageOffline().
For simplicity, use a rwsem for now; neither drivers nor users are
performance sensitive.
Acked-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: Mike Rapoport <redacted>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Signed-off-by: David Hildenbrand <redacted>
---
include/linux/page-flags.h | 10 ++++++++++
mm/util.c | 40 ++++++++++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+)
From: David Hildenbrand <hidden> Date: 2021-05-26 09:31:59
Let's properly use page_offline_(start|end) to synchronize setting
PageOffline(), so we won't have valid page access to unplugged memory
regions from /proc/kcore.
Existing balloon implementations usually allow reading inflated memory;
doing so might result in unnecessary overhead in the hypervisor, which
is currently the case with virtio-mem.
For future virtio-mem use cases, it will be different when using shmem,
huge pages, !anonymous private mappings, ... as backing storage for a VM.
virtio-mem unplugged memory must no longer be accessed and access might
result in undefined behavior. There will be a virtio spec extension to
document this change, including a new feature flag indicating the
changed behavior. We really don't want to race against PFN walkers
reading random page content.
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Mike Rapoport <redacted>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Signed-off-by: David Hildenbrand <redacted>
---
drivers/virtio/virtio_mem.c | 2 ++
1 file changed, 2 insertions(+)
From: David Hildenbrand <hidden> Date: 2021-05-26 09:32:03
Let's properly synchronize with drivers that set PageOffline().
Unfreeze/thaw every now and then, so drivers that want to set PageOffline()
can make progress.
Acked-by: Mike Rapoport <redacted>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Signed-off-by: David Hildenbrand <redacted>
---
fs/proc/kcore.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
From: David Hildenbrand <hidden> Date: 2021-05-26 09:32:22
Let's avoid reading:
1) Offline memory sections: the content of offline memory sections is stale
as the memory is effectively unused by the kernel. On s390x with standby
memory, offline memory sections (belonging to offline storage
increments) are not accessible. With virtio-mem and the hyper-v balloon,
we can have unavailable memory chunks that should not be accessed inside
offline memory sections. Last but not least, offline memory sections
might contain hwpoisoned pages which we can no longer identify
because the memmap is stale.
2) PG_offline pages: logically offline pages that are documented as
"The content of these pages is effectively stale. Such pages should not
be touched (read/write/dump/save) except by their owner.".
Examples include pages inflated in a balloon or unavailble memory
ranges inside hotplugged memory sections with virtio-mem or the hyper-v
balloon.
3) PG_hwpoison pages: Reading pages marked as hwpoisoned can be fatal.
As documented: "Accessing is not safe since it may cause another machine
check. Don't touch!"
Introduce is_page_hwpoison(), adding a comment that it is inherently
racy but best we can really do.
Reading /proc/kcore now performs similar checks as when reading
/proc/vmcore for kdump via makedumpfile: problematic pages are exclude.
It's also similar to hibernation code, however, we don't skip hwpoisoned
pages when processing pages in kernel/power/snapshot.c:saveable_page() yet.
Note 1: we can race against memory offlining code, especially
memory going offline and getting unplugged: however, we will properly tear
down the identity mapping and handle faults gracefully when accessing
this memory from kcore code.
Note 2: we can race against drivers setting PageOffline() and turning
memory inaccessible in the hypervisor. We'll handle this in a follow-up
patch.
Reviewed-by: Mike Rapoport <redacted>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Signed-off-by: David Hildenbrand <redacted>
---
fs/proc/kcore.c | 14 +++++++++++++-
include/linux/page-flags.h | 12 ++++++++++++
2 files changed, 25 insertions(+), 1 deletion(-)