summaryrefslogtreecommitdiff
path: root/arch/s390/kernel
diff options
context:
space:
mode:
authorAlexander Gordeev <agordeev@linux.ibm.com>2022-01-29 09:24:50 +0100
committerVasily Gorbik <gor@linux.ibm.com>2022-02-09 22:56:04 +0100
commit303fd988ed644c7daa260410f3ac99266573557d (patch)
treee93519a8541e4300b55f52a3c320beac2f7214a6 /arch/s390/kernel
parentdc306186a130c6d9feb0aabc1c71b8ed1674a3bf (diff)
s390/maccess: fix semantics of memcpy_real() and its callers
There is a confusion with regard to the source address of memcpy_real() and calling functions. While the declared type for a source assumes a virtual address, in fact it always called with physical address of the source. This confusion led to bugs in copy_oldmem_kernel() and copy_oldmem_user() functions, where __pa() macro applied mistakenly to physical addresses. It does not lead to a real issue, since virtual and physical addresses are currently the same. Fix both the bugs and memcpy_real() prototype by making type of source address consistent to the function name and the way it actually used. Reviewed-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r--arch/s390/kernel/crash_dump.c58
-rw-r--r--arch/s390/kernel/os_info.c7
-rw-r--r--arch/s390/kernel/smp.c2
3 files changed, 32 insertions, 35 deletions
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c
index a62bee83a88b..69819b765250 100644
--- a/arch/s390/kernel/crash_dump.c
+++ b/arch/s390/kernel/crash_dump.c
@@ -132,28 +132,27 @@ static inline void *load_real_addr(void *addr)
/*
* Copy memory of the old, dumped system to a kernel space virtual address
*/
-int copy_oldmem_kernel(void *dst, void *src, size_t count)
+int copy_oldmem_kernel(void *dst, unsigned long src, size_t count)
{
- unsigned long from, len;
+ unsigned long len;
void *ra;
int rc;
while (count) {
- from = __pa(src);
- if (!oldmem_data.start && from < sclp.hsa_size) {
+ if (!oldmem_data.start && src < sclp.hsa_size) {
/* Copy from zfcp/nvme dump HSA area */
- len = min(count, sclp.hsa_size - from);
- rc = memcpy_hsa_kernel(dst, from, len);
+ len = min(count, sclp.hsa_size - src);
+ rc = memcpy_hsa_kernel(dst, src, len);
if (rc)
return rc;
} else {
/* Check for swapped kdump oldmem areas */
- if (oldmem_data.start && from - oldmem_data.start < oldmem_data.size) {
- from -= oldmem_data.start;
- len = min(count, oldmem_data.size - from);
- } else if (oldmem_data.start && from < oldmem_data.size) {
- len = min(count, oldmem_data.size - from);
- from += oldmem_data.start;
+ if (oldmem_data.start && src - oldmem_data.start < oldmem_data.size) {
+ src -= oldmem_data.start;
+ len = min(count, oldmem_data.size - src);
+ } else if (oldmem_data.start && src < oldmem_data.size) {
+ len = min(count, oldmem_data.size - src);
+ src += oldmem_data.start;
} else {
len = count;
}
@@ -163,7 +162,7 @@ int copy_oldmem_kernel(void *dst, void *src, size_t count)
} else {
ra = dst;
}
- if (memcpy_real(ra, (void *) from, len))
+ if (memcpy_real(ra, src, len))
return -EFAULT;
}
dst += len;
@@ -176,31 +175,30 @@ int copy_oldmem_kernel(void *dst, void *src, size_t count)
/*
* Copy memory of the old, dumped system to a user space virtual address
*/
-static int copy_oldmem_user(void __user *dst, void *src, size_t count)
+static int copy_oldmem_user(void __user *dst, unsigned long src, size_t count)
{
- unsigned long from, len;
+ unsigned long len;
int rc;
while (count) {
- from = __pa(src);
- if (!oldmem_data.start && from < sclp.hsa_size) {
+ if (!oldmem_data.start && src < sclp.hsa_size) {
/* Copy from zfcp/nvme dump HSA area */
- len = min(count, sclp.hsa_size - from);
- rc = memcpy_hsa_user(dst, from, len);
+ len = min(count, sclp.hsa_size - src);
+ rc = memcpy_hsa_user(dst, src, len);
if (rc)
return rc;
} else {
/* Check for swapped kdump oldmem areas */
- if (oldmem_data.start && from - oldmem_data.start < oldmem_data.size) {
- from -= oldmem_data.start;
- len = min(count, oldmem_data.size - from);
- } else if (oldmem_data.start && from < oldmem_data.size) {
- len = min(count, oldmem_data.size - from);
- from += oldmem_data.start;
+ if (oldmem_data.start && src - oldmem_data.start < oldmem_data.size) {
+ src -= oldmem_data.start;
+ len = min(count, oldmem_data.size - src);
+ } else if (oldmem_data.start && src < oldmem_data.size) {
+ len = min(count, oldmem_data.size - src);
+ src += oldmem_data.start;
} else {
len = count;
}
- rc = copy_to_user_real(dst, (void *) from, count);
+ rc = copy_to_user_real(dst, src, count);
if (rc)
return rc;
}
@@ -217,12 +215,12 @@ static int copy_oldmem_user(void __user *dst, void *src, size_t count)
ssize_t copy_oldmem_page(unsigned long pfn, char *buf, size_t csize,
unsigned long offset, int userbuf)
{
- void *src;
+ unsigned long src;
int rc;
if (!csize)
return 0;
- src = (void *) (pfn << PAGE_SHIFT) + offset;
+ src = pfn_to_phys(pfn) + offset;
if (userbuf)
rc = copy_oldmem_user((void __force __user *) buf, src, csize);
else
@@ -429,10 +427,10 @@ static void *nt_prpsinfo(void *ptr)
static void *get_vmcoreinfo_old(unsigned long *size)
{
char nt_name[11], *vmcoreinfo;
+ unsigned long addr;
Elf64_Nhdr note;
- void *addr;
- if (copy_oldmem_kernel(&addr, (void *)__LC_VMCORE_INFO, sizeof(addr)))
+ if (copy_oldmem_kernel(&addr, __LC_VMCORE_INFO, sizeof(addr)))
return NULL;
memset(nt_name, 0, sizeof(nt_name));
if (copy_oldmem_kernel(&note, addr, sizeof(note)))
diff --git a/arch/s390/kernel/os_info.c b/arch/s390/kernel/os_info.c
index a2b08d3f53ec..6b5b64e67eee 100644
--- a/arch/s390/kernel/os_info.c
+++ b/arch/s390/kernel/os_info.c
@@ -91,7 +91,7 @@ static void os_info_old_alloc(int nr, int align)
goto fail;
}
buf_align = PTR_ALIGN(buf, align);
- if (copy_oldmem_kernel(buf_align, (void *) addr, size)) {
+ if (copy_oldmem_kernel(buf_align, addr, size)) {
msg = "copy failed";
goto fail_free;
}
@@ -124,15 +124,14 @@ static void os_info_old_init(void)
return;
if (!oldmem_data.start)
goto fail;
- if (copy_oldmem_kernel(&addr, (void *)__LC_OS_INFO, sizeof(addr)))
+ if (copy_oldmem_kernel(&addr, __LC_OS_INFO, sizeof(addr)))
goto fail;
if (addr == 0 || addr % PAGE_SIZE)
goto fail;
os_info_old = kzalloc(sizeof(*os_info_old), GFP_KERNEL);
if (!os_info_old)
goto fail;
- if (copy_oldmem_kernel(os_info_old, (void *) addr,
- sizeof(*os_info_old)))
+ if (copy_oldmem_kernel(os_info_old, addr, sizeof(*os_info_old)))
goto fail_free;
if (os_info_old->magic != OS_INFO_MAGIC)
goto fail_free;
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index b214af5164bd..4f0e9f412f27 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -670,7 +670,7 @@ static __init void smp_save_cpu_regs(struct save_area *sa, u16 addr,
bool is_boot_cpu, void *regs)
{
if (is_boot_cpu)
- copy_oldmem_kernel(regs, (void *) __LC_FPREGS_SAVE_AREA, 512);
+ copy_oldmem_kernel(regs, __LC_FPREGS_SAVE_AREA, 512);
else
__pcpu_sigp_relax(addr, SIGP_STORE_STATUS_AT_ADDRESS, __pa(regs));
save_area_add_regs(sa, regs);