Message ID | 20211112092750.6921-1-david@redhat.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | [v2] proc/vmcore: fix clearing user buffer by properly using clear_user() | expand |
On Fri, 12 Nov 2021 10:27:50 +0100 David Hildenbrand <david@redhat.com> wrote: > To clear a user buffer we cannot simply use memset, we have to use > clear_user(). With a virtio-mem device that registers a vmcore_cb and has > some logically unplugged memory inside an added Linux memory block, I can > easily trigger a BUG by copying the vmcore via "cp": > > ... > > Some x86-64 CPUs have a CPU feature called "Supervisor Mode Access > Prevention (SMAP)", which is used to detect wrong access from the kernel to > user buffers like this: SMAP triggers a permissions violation on wrong > access. In the x86-64 variant of clear_user(), SMAP is properly > handled via clac()+stac(). > > To fix, properly use clear_user() when we're dealing with a user buffer. > I added cc:stable, OK?
On 15.11.21 23:04, Andrew Morton wrote: > On Fri, 12 Nov 2021 10:27:50 +0100 David Hildenbrand <david@redhat.com> wrote: > >> To clear a user buffer we cannot simply use memset, we have to use >> clear_user(). With a virtio-mem device that registers a vmcore_cb and has >> some logically unplugged memory inside an added Linux memory block, I can >> easily trigger a BUG by copying the vmcore via "cp": >> >> ... >> >> Some x86-64 CPUs have a CPU feature called "Supervisor Mode Access >> Prevention (SMAP)", which is used to detect wrong access from the kernel to >> user buffers like this: SMAP triggers a permissions violation on wrong >> access. In the x86-64 variant of clear_user(), SMAP is properly >> handled via clac()+stac(). >> >> To fix, properly use clear_user() when we're dealing with a user buffer. >> > > I added cc:stable, OK? > I was a bit hesitant because this would (beofe the virtio-mem changes) only trigger under XEN and I was wondering why nobody notices under XEN so far. But yes, even though it only applies to the kdump kernel, cc:stable sounds like the right think to do! Thanks Andrew!
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index 30a3b66f475a..509f85148fee 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c @@ -154,9 +154,13 @@ ssize_t read_from_oldmem(char *buf, size_t count, nr_bytes = count; /* If pfn is not ram, return zeros for sparse dump files */ - if (!pfn_is_ram(pfn)) - memset(buf, 0, nr_bytes); - else { + if (!pfn_is_ram(pfn)) { + tmp = 0; + if (!userbuf) + memset(buf, 0, nr_bytes); + else if (clear_user(buf, nr_bytes)) + tmp = -EFAULT; + } else { if (encrypted) tmp = copy_oldmem_page_encrypted(pfn, buf, nr_bytes, @@ -165,12 +169,12 @@ ssize_t read_from_oldmem(char *buf, size_t count, else tmp = copy_oldmem_page(pfn, buf, nr_bytes, offset, userbuf); - - if (tmp < 0) { - up_read(&vmcore_cb_rwsem); - return tmp; - } } + if (tmp < 0) { + up_read(&vmcore_cb_rwsem); + return tmp; + } + *ppos += nr_bytes; count -= nr_bytes; buf += nr_bytes;