Commit 303fd988 authored by Alexander Gordeev's avatar Alexander Gordeev Committed by Vasily Gorbik
Browse files

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: default avatarHeiko Carstens <hca@linux.ibm.com>
Signed-off-by: default avatarAlexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent dc306186
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ u32 os_info_csum(struct os_info *os_info);

#ifdef CONFIG_CRASH_DUMP
void *os_info_old_entry(int nr, unsigned long *size);
int copy_oldmem_kernel(void *dst, void *src, size_t count);
int copy_oldmem_kernel(void *dst, unsigned long src, size_t count);
#else
static inline void *os_info_old_entry(int nr, unsigned long *size)
{
+1 −1
Original line number Diff line number Diff line
@@ -317,7 +317,7 @@ extern void (*s390_base_pgm_handler_fn)(void);

#define ARCH_LOW_ADDRESS_LIMIT	0x7fffffffUL

extern int memcpy_real(void *, void *, size_t);
extern int memcpy_real(void *, unsigned long, size_t);
extern void memcpy_absolute(void *, void *, size_t);

#define mem_assign_absolute(dest, val) do {			\
+1 −1
Original line number Diff line number Diff line
@@ -279,7 +279,7 @@ static inline unsigned long __must_check clear_user(void __user *to, unsigned lo
	return __clear_user(to, n);
}

int copy_to_user_real(void __user *dest, void *src, unsigned long count);
int copy_to_user_real(void __user *dest, unsigned long src, unsigned long count);
void *s390_kernel_write(void *dst, const void *src, size_t size);

#define HAVE_GET_KERNEL_NOFAULT
+28 −30
Original line number Diff line number Diff line
@@ -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)))
+3 −4
Original line number Diff line number Diff line
@@ -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;
Loading