[System]
You are a security patch backporting assistant for SUSE/openSUSE.

Given a CVE description and an upstream fix, adapt the patch to work with
the target SUSE package version. Output the backported patch in unified
diff format. If the upstream fix applies directly, output it unchanged.

[User]
## CVE: CVE-2017-5715

crash patch c3413456599161cabc4e910a0ae91dfe5eec3c21 (xen: Add support for

## Package
crash

## Files to modify
- kernel.c
- xendump.c
- xendump.h

## Target Source Code

### kernel.c

#### region() [lines 1-79]
```c
/* kernel.c - core analysis suite
 *
 * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
 * Copyright (C) 2002-2019 David Anderson
 * Copyright (C) 2002-2019 Red Hat, Inc. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include "defs.h"
#include "xen_hyper_defs.h"
#include "xen_dom0.h"
#include <elf.h>
#include <libgen.h>
#include <ctype.h>
#include <stdbool.h>
#include "xendump.h"

static void do_module_cmd(ulong, char *, ulong, char *, char *);
static void show_module_taint(void);
static char *find_module_objfile(char *, char *, char *);
static char *module_objfile_search(char *, char *, char *);
static char *get_loadavg(char *);
static void get_lkcd_regs(struct bt_info *, ulong *, ulong *);
static void dump_sys_call_table(char *, int);
static int get_NR_syscalls(int *);
static ulong get_irq_desc_addr(int);
static void display_cpu_affinity(ulong *);
static void display_bh_1(void);
static void display_bh_2(void);
static void display_bh_3(void);
static void display_bh_4(void);
static void dump_hrtimer_data(const ulong *cpus);
static void dump_hrtimer_clock_base(const void *, const int);
static void dump_hrtimer_base(const void *, const int);
static void dump_active_timers(const void *, ulonglong);
static int get_expires_len(const int, const ulong *, ulonglong, const int);
static void print_timer(const void *, ulonglong);
static ulonglong ktime_to_ns(const void *);
static void dump_timer_data(const ulong *cpus);
static void dump_timer_data_tvec_bases_v1(const ulong *cpus);
static void dump_timer_data_tvec_bases_v2(const ulong *cpus);
static void dump_timer_data_tvec_bases_v3(const ulong *cpus);
static void dump_timer_data_timer_bases(const ulong *cpus);
struct tv_range;
static void init_tv_ranges(struct tv_range *, int, int, int);
static int do_timer_list(ulong,int, ulong *, void *,ulong *, ulong *, struct tv_range *, ulong);
static int do_timer_list_v3(ulong, int, ulong *, void *,ulong *, ulong *, ulong, long);
struct timer_bases_data;
static int do_timer_list_v4(struct timer_bases_data *, ulong);
static int compare_timer_data(const void *, const void *);
static void panic_this_kernel(void);
static void dump_waitq(ulong, char *);
static void reinit_modules(void);
static int verify_modules(void);
static void verify_namelist(void);
static char *debug_kernel_version(char *);
static int restore_stack(struct bt_info *);
static ulong __xen_m2p(ulonglong, ulong);
static ulong __xen_pvops_m2p_l2(ulonglong, ulong);
static ulong __xen_pvops_m2p_l3(ulonglong, ulong);
static ulong __xen_pvops_m2p_hyper(ulonglong, ulong);
static ulong __xen_pvops_m2p_domU(ulonglong, ulong);
static int read_xc_p2m(ulonglong, void *, long);
static void read_p2m(ulong, int, void *);
static int search_mapping_page(ulong, ulong *, ulong *, ulong *);
static void read_in_kernel_config_err(int, char *);
static void BUG_bytes_init(void);
static int BUG_x86(void);
static int BUG_x86_64(void);
static void cpu_maps_init(void);
```

#### __xen_m2p() [lines 9733-9858]
```c
}

static ulong
__xen_m2p(ulonglong machine, ulong mfn)
{
	ulong c, i, kmfn, mapping, p, pfn;
	ulong start, end;
	ulong *mp = (ulong *)kt->m2p_page;
	int memtype;

	if (XEN_CORE_DUMPFILE() && symbol_exists("xen_p2m_addr"))
		memtype = PHYSADDR;
	else
		memtype = KVADDR;

	/*
	 *  Check the FIFO cache first.
	 */
	for (c = 0; c < P2M_MAPPING_CACHE; c++) {
		if (kt->p2m_mapping_cache[c].mapping &&
		    ((mfn >= kt->p2m_mapping_cache[c].start) &&
		     (mfn <= kt->p2m_mapping_cache[c].end))) {

			if (kt->p2m_mapping_cache[c].mapping != kt->last_mapping_read) {
				if (memtype == PHYSADDR)
					pc->curcmd_flags |= XEN_MACHINE_ADDR;

				read_p2m(c, memtype, mp);

				if (memtype == PHYSADDR)
					pc->curcmd_flags &= ~XEN_MACHINE_ADDR;
			} else
				kt->p2m_page_cache_hits++;

                	for (i = 0; i < XEN_PFNS_PER_PAGE; i++) {
				kmfn = (*(mp+i)) & ~XEN_FOREIGN_FRAME;
                        	if (kmfn == mfn) {
					p = P2M_MAPPING_PAGE_PFN(c);
					pfn = p + i;

/* ... 80 lines omitted ... */
				c = kt->p2m_cache_index;
				kt->p2m_mapping_cache[c].start = start;
				kt->p2m_mapping_cache[c].end = end;
				kt->p2m_mapping_cache[c].mapping = mapping;
				kt->p2m_cache_index = (c+1) % P2M_MAPPING_CACHE;

				return pfn;
			}

			mapping += PAGESIZE();
		}
	}

	if (CRASHDEBUG(1))
		console("machine address %llx not found\n", machine);

	return (XEN_MFN_NOT_FOUND);
}

static ulong
```

#### kernel_init() [lines 101-823]
```c
 *  Gather a few kernel basics.
 */
void
kernel_init()
{
	int i, c;
	char *p1, *p2, buf[BUFSIZE];
	struct syment *sp1, *sp2;
	char *rqstruct;
	char *rq_timestamp_name = NULL;
	char *irq_desc_type_name;
	ulong pv_init_ops;
	struct gnu_request req;

	if (pc->flags & KERNEL_DEBUG_QUERY)
		return;

        if (!(kt->cpu_flags = (ulong *)calloc(NR_CPUS, sizeof(ulong))))
                error(FATAL, "cannot malloc cpu_flags array");

	cpu_maps_init();

	kt->stext = symbol_value("_stext");
	kt->etext = symbol_value("_etext");
	get_text_init_space();
	if (symbol_exists("__init_begin")) {
		kt->init_begin = symbol_value("__init_begin");
		kt->init_end = symbol_value("__init_end");
	}
	kt->end = highest_bss_symbol();
	if ((sp1 = kernel_symbol_search("_end")) && (sp1->value > kt->end))
		kt->end = sp1->value;

	check_vmcoreinfo();

	/*
	 *  For the traditional (non-pv_ops) Xen architecture, default to writable
         *  page tables unless:
	 *
	 *  (1) it's an "xm save" CANONICAL_PAGE_TABLES dumpfile,  or
/* ... 31 lines omitted ... */
	if (PVOPS() && symbol_exists("pv_init_ops") &&
	    readmem(symbol_value("pv_init_ops"), KVADDR, &pv_init_ops,
	    sizeof(void *), "pv_init_ops", RETURN_ON_ERROR) &&
	    ((p1 = value_symbol(pv_init_ops)) &&
	    (STREQ(p1, "xen_patch") || STREQ(p1, "paravirt_patch_default")))) {
		kt->flags |= ARCH_XEN | ARCH_PVOPS_XEN;
		kt->xen_flags |= WRITABLE_PAGE_TABLES;
		if (machine_type("X86"))
                	get_symbol_data("max_pfn", sizeof(ulong), &kt->p2m_table_size);
		if (machine_type("X86_64")) {
			if (!try_get_symbol_data("end_pfn", sizeof(ulong), &kt->p2m_table_size))
				get_symbol_data("max_pfn", sizeof(ulong), &kt->p2m_table_size);
		}
                if ((kt->m2p_page = (char *)malloc(PAGESIZE())) == NULL)
                       	error(FATAL, "cannot malloc m2p page.");

		if (symbol_exists("p2m_mid_missing")) {
			kt->pvops_xen.p2m_top_entries = XEN_P2M_TOP_PER_PAGE;
			get_symbol_data("p2m_top", sizeof(ulong),
						&kt->pvops_xen.p2m_top);
			get_symbol_data("p2m_mid_missing", sizeof(ulong),
						&kt->pvops_xen.p2m_mid_missing);
			get_symbol_data("p2m_missing", sizeof(ulong),
						&kt->pvops_xen.p2m_missing);
		} else if (!symbol_exists("xen_p2m_addr")) {
			kt->pvops_xen.p2m_top_entries = get_array_length("p2m_top", NULL, 0);
			kt->pvops_xen.p2m_top = symbol_value("p2m_top");
			kt->pvops_xen.p2m_missing = symbol_value("p2m_missing");
		}
	}
/* ... 602 lines omitted ... */
	MEMBER_OFFSET_INIT(hrtimer_softexpires, "hrtimer", "_softexpires");
	MEMBER_OFFSET_INIT(hrtimer_function, "hrtimer", "function");

	MEMBER_OFFSET_INIT(ktime_t_tv64, "ktime", "tv64");
	if (INVALID_MEMBER(ktime_t_tv64))
		MEMBER_OFFSET_INIT(ktime_t_tv64, "ktime_t", "tv64");
	MEMBER_OFFSET_INIT(ktime_t_sec, "ktime", "sec");
	if (INVALID_MEMBER(ktime_t_sec))
		MEMBER_OFFSET_INIT(ktime_t_sec, "ktime_t", "sec");
	MEMBER_OFFSET_INIT(ktime_t_nsec, "ktime", "nsec");
	if (INVALID_MEMBER(ktime_t_nsec))
		MEMBER_OFFSET_INIT(ktime_t_nsec, "ktime_t", "nsec");

	if (kt->source_tree)
		source_tree_init();

	kt->flags &= ~PRE_KERNEL_INIT;
}

/*
```

#### __xen_pvops_m2p_hyper() [lines 9965-10011]
```c
}

static ulong
__xen_pvops_m2p_hyper(ulonglong machine, ulong mfn)
{
	ulong c, end, i, mapping, p, pfn, start;

	for (p = 0;
	     p < xkd->p2m_frames;
	     ++p) {

		mapping = PTOB(xkd->p2m_mfn_frame_list[p]);

		if (mapping != kt->last_mapping_read) {
			pc->curcmd_flags |= XEN_MACHINE_ADDR;
			if (!readmem(mapping, PHYSADDR, (void *)kt->m2p_page,
					PAGESIZE(), "p2m_mfn_frame_list page", RETURN_ON_ERROR))
				error(FATAL, "cannot access p2m_mfn_frame_list[] page\n");

			pc->curcmd_flags &= ~XEN_MACHINE_ADDR;
			kt->last_mapping_read = mapping;
		}

		kt->p2m_pages_searched++;

		if (search_mapping_page(mfn, &i, &start, &end)) {
			pfn = p * XEN_PFNS_PER_PAGE + i;
			if (CRASHDEBUG(1))
			    console("pages: %d mfn: %lx (%llx) p: %ld"
				" i: %ld pfn: %lx (%llx)\n", p + 1, mfn, machine,
				p, i, pfn, XEN_PFN_TO_PSEUDO(pfn));

			c = kt->p2m_cache_index;
			kt->p2m_mapping_cache[c].start = start;
			kt->p2m_mapping_cache[c].end = end;
			kt->p2m_mapping_cache[c].mapping = mapping;
			kt->p2m_mapping_cache[c].pfn = p * XEN_PFNS_PER_PAGE;
			kt->p2m_cache_index = (c+1) % P2M_MAPPING_CACHE;

			return pfn;
		}
	}

	return XEN_MFN_NOT_FOUND;
}

static void read_p2m(ulong cache_index, int memtype, void *buffer)
```

#### region() [lines 189-198]
```c
			kt->pvops_xen.p2m_top_entries = XEN_P2M_TOP_PER_PAGE;
			get_symbol_data("p2m_top", sizeof(ulong),
						&kt->pvops_xen.p2m_top);
			get_symbol_data("p2m_mid_missing", sizeof(ulong),
						&kt->pvops_xen.p2m_mid_missing);
			get_symbol_data("p2m_missing", sizeof(ulong),
						&kt->pvops_xen.p2m_missing);
		} else if (!symbol_exists("xen_p2m_addr")) {
			kt->pvops_xen.p2m_top_entries = get_array_length("p2m_top", NULL, 0);
			kt->pvops_xen.p2m_top = symbol_value("p2m_top");
```

### Type definitions

```c
/* from xendump.h */
struct xendump_data {
        ulong flags;       /* XENDUMP_LOCAL, plus anything else... */
	int xfd;
	int pc_next;
	uint page_size;
	FILE *ofp;
	char *page;
	ulong accesses;
	ulong cache_hits;
	ulong redundant;
	ulong last_pfn;
	struct pfn_offset_cache *poc;

	struct xc_core_data {
		int p2m_frames;
		ulong *p2m_frame_index_list;
		struct xen_core_header header;
		int elf_class;
		uint64_t format_version;
		off_t elf_strtab_offset;
		off_t shared_info_offset;
		off_t ia64_mapped_regs_offset;
		struct elf_index_pfn elf_index_pfn[INDEX_PFN_COUNT];
		struct last_batch last_batch;
		Elf32_Ehdr *elf32;
		Elf64_Ehdr *elf64;
	} xc_core;

	struct xc_save_data {
		ulong nr_pfns;
		int vmconfig_size;
		char *vmconfig_buf;
		ulong *p2m_frame_list;
		uint pfns_not;
		off_t pfns_not_offset;
		off_t vcpu_ctxt_offset;
		off_t shared_info_page_offset;
		off_t *batch_offsets;
		ulong batch_count;
		ulong *region_pfn_type;
		ulong ia64_version;
		ulong *ia64_page_offsets;
	} xc_save;

	ulong panic_pc;
	ulong panic_sp;
};

/* from xendump.h */
struct xen_dumpcore_p2m {
	uint64_t pfn;
	uint64_t gmfn;
};
```

## Upstream Fix
```diff

crash patch c3413456599161cabc4e910a0ae91dfe5eec3c21 (xen: Add support for
dom0 with Linux kernel 3.19 and newer) from Daniel made crash utility
support xen dom0 vmcores after linux kernel commit
054954eb051f35e74b75a566a96fe756015352c8 (xen: switch to linear virtual
mapped sparse p2m list).

This patch can be deemed as a subsequent and make this utility support Xen
PV domU dumpfiles again.

Basically speaking, readmem() can't be used to read xen_p2m_addr associate
memory directly during m2p translation. It introduces infinite recursion.
Following call sequence shows the scenario, it comes from a section of
backtrace with only kvaddr, machine addr and mfn left as parameter:

module_init()

/* The first readmem() from module_init(). */
readmem(addr=0xffffffffa02fe4a0)

/* readmem() needs physical address, so calls kvtop(). */
kvtop(kvaddr=0xffffffffa02fe4a0)
x86_64_kvtop(kvaddr=ffffffffa02fe4a0)

/* Calculate physical address by traversing page tables. */
x86_64_kvtop_xen_wpt(kvaddr=0xffffffffa02fe4a0)

/*
 * x86_64_kvtop_xen_wpt() is going to traverse the page table to
 * get the physical address for 0xffffffffa02fe4a0. So, at first it
 * is needed to translate the pgd from machine address to physical
 * address. So invoke xen_m2p() here to do the translation. 0x58687f000
 * is the pgd machine address in x86_64_kvtop_xen_wpt() and is needed
 * to be translated to its physical address.
 */
xen_m2p(machine=0x58687f000)
__xen_m2p(machine=0x58687f000, mfn=0x58687f)

/*
 * __xen_m2p() is going to search mfn 0x58687f in p2m VMA which starts
 * at VMA 0xffffc900001cf000. It compares every mfn stored in it with
 * 0x58687f. Once it's proved 0x58687f is one mfn in the p2m, its offset
 * will be used to calculate the pfn.
 *
 * readmem() is invoked by __xen_m2p() to read the page from VMA
 * 0xffffc900001cf000 here.
 */
readmem(addr=0xffffc900001cf000)

/*
 * readmem() needs physical address of 0xffffc900001cf000 to make the
 * reading done. So it invokes kvtop() to get the physical address.
 */
kvtop(kvaddr=0xffffc900001cf000)
x86_64_kvtop(kvaddr=0xffffc900001cf000)

/* It needs to calculate physical address by traversing page tables. */
x86_64_kvtop_xen_wpt(kvaddr=0xffffc900001cf000)

/*
 * 0x581b7e000 is the machine address of pgd need to be translated here.
 * The mfn is calculated in this way at x86_64_kvtop_xen_wpt():
 *
 * pml4 = ((ulong *)machdep->machspec->pml4) + pml4_index(kvaddr);
 * pgd_paddr = (*pml4) & PHYSICAL_PAGE_MASK;
 *
 * The kvaddr 0xffffc900001cf000 here is quite different from the one
 * above, so the machine address of pgd is not the same one. And this
 * pgd is the one we use to access the VMA of p2m table.
 */
xen_m2p(machine=0x581b7e000)
__xen_m2p(machine=0x581b7e000, mfn=0x581b7e)

/*
 * Looking for mfn 0x581b7e in the range of p2m page which starts at
 * VMA 0xffffc900001f5000.
 */
readmem(addr=0xffffc900001f5000)

/* Need physical address of VMA 0xffffc900001f5000 as same reason above. */
kvtop(kvaddr=0xffffc900001f5000)
x86_64_kvtop(kvaddr=0xffffc900001f5000)

/* Need to traverse page tables to calculate physical address for it. */
x86_64_kvtop_xen_wpt(kvaddr=0xffffc900001f5000)

/*
 * Unfortunately, machine address 0x581b7e000 have to be translated again.
 * Endless loop starts from here.
 */
xen_m2p(machine=0x581b7e000)
__xen_m2p(machine=0x581b7e000, mfn=0x581b7e)
readmem(addr=0xffffc900001f5000)

Fortunately, PV domU p2m mapping is also stored at xd->xfd + xch_index_offset
and organized as struct xen_dumpcore_p2m. We have a chance to read the p2m
stuff directly from there, and then we avoid the loop above.

So, this patch implements a special reading function read_xc_p2m() to extract
the mfns from xd->xfd + xch_index_offset. This function does not need to read
mfns from p2m VMA like readmem() does, so, we avoid the endless loop introduced
by the address translation.

Signed-off-by: Honglei Wang <honglei.wang@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
 kernel.c  |  151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 xendump.c |    2
 xendump.h |    2
 3 files changed, 140 insertions(+), 15 deletions(-)

--- a/kernel.c
+++ b/kernel.c
@@ -22,6 +22,7 @@
 #include <libgen.h>
 #include <ctype.h>
 #include <stdbool.h>
+#include "xendump.h"

 static void do_module_cmd(ulong, char *, ulong, char *, char *);
 static void show_module_taint(void);
@@ -67,6 +68,9 @@ static ulong __xen_m2p(ulonglong, ulong)
 static ulong __xen_pvops_m2p_l2(ulonglong, ulong);
 static ulong __xen_pvops_m2p_l3(ulonglong, ulong);
 static ulong __xen_pvops_m2p_hyper(ulonglong, ulong);
+static ulong __xen_pvops_m2p_domU(ulonglong, ulong);
+static int read_xc_p2m(ulonglong addr, void *buffer, long size);
+static void read_p2m(ulong cache_index, int memtype, void *buffer);
 static int search_mapping_page(ulong, ulong *, ulong *, ulong *);
 static void read_in_kernel_config_err(int, char *);
 static void BUG_bytes_init(void);
@@ -181,10 +185,7 @@ kernel_init()
 						&kt->pvops_xen.p2m_mid_missing);
 			get_symbol_data("p2m_missing", sizeof(ulong),
 						&kt->pvops_xen.p2m_missing);
-		} else if (symbol_exists("xen_p2m_addr")) {
-			if (!XEN_CORE_DUMPFILE())
-				error(FATAL, "p2m array in new format is unreadable.");
-		} else {
+		} else if (!symbol_exists("xen_p2m_addr")) {
 			kt->pvops_xen.p2m_top_entries = get_array_length("p2m_top", NULL, 0);
 			kt->pvops_xen.p2m_top = symbol_value("p2m_top");
 			kt->pvops_xen.p2m_missing = symbol_value("p2m_missing");
@@ -9312,13 +9313,7 @@ __xen_m2p(ulonglong machine, ulong mfn)
 				if (memtype == PHYSADDR)
 					pc->curcmd_flags |= XEN_MACHINE_ADDR;

-				if (!readmem(kt->p2m_mapping_cache[c].mapping, memtype,
-			       	    mp, PAGESIZE(), "phys_to_machine_mapping page (cached)",
-			    	    RETURN_ON_ERROR))
-                                	error(FATAL, "cannot access "
-                                    	    "phys_to_machine_mapping page\n");
-				else
-					kt->last_mapping_read = kt->p2m_mapping_cache[c].mapping;
+				read_p2m(c, memtype, mp);

 				if (memtype == PHYSADDR)
 					pc->curcmd_flags &= ~XEN_MACHINE_ADDR;
@@ -9356,9 +9351,12 @@ __xen_m2p(ulonglong machine, ulong mfn)
 		 */
 		if (symbol_exists("p2m_mid_missing"))
 			pfn = __xen_pvops_m2p_l3(machine, mfn);
-		else if (symbol_exists("xen_p2m_addr"))
-			pfn = __xen_pvops_m2p_hyper(machine, mfn);
-		else
+		else if (symbol_exists("xen_p2m_addr")) {
+			if (XEN_CORE_DUMPFILE())
+				pfn = __xen_pvops_m2p_hyper(machine, mfn);
+			else
+				pfn = __xen_pvops_m2p_domU(machine, mfn);
+		} else
 			pfn = __xen_pvops_m2p_l2(machine, mfn);

 		if (pfn != XEN_MFN_NOT_FOUND)
@@ -9566,6 +9564,131 @@ __xen_pvops_m2p_hyper(ulonglong machine,
 	return XEN_MFN_NOT_FOUND;
 }

+static void read_p2m(ulong cache_index, int memtype, void *buffer)
+{
+	/*
+	 *  Use special read function for PV domain p2m reading.
+	 *  See the comments of read_xc_p2m().
+	 */
+	if (symbol_exists("xen_p2m_addr") && !XEN_CORE_DUMPFILE()) {
+		if (!read_xc_p2m(kt->p2m_mapping_cache[cache_index].mapping,
+			buffer, PAGESIZE()))
+			error(FATAL, "cannot access phys_to_machine_mapping page\n");
+	} else if (!readmem(kt->p2m_mapping_cache[cache_index].mapping, memtype,
+			buffer, PAGESIZE(), "phys_to_machine_mapping page (cached)",
+			RETURN_ON_ERROR))
+		error(FATAL, "cannot access phys_to_machine_mapping page\n");
+
+	kt->last_mapping_read = kt->p2m_mapping_cache[cache_index].mapping;
+}
+
+/*
+ *  PV domain p2m mapping info is stored in xd->xfd at xch_index_offset. It
+ *  is organized as struct xen_dumpcore_p2m and the pfns are progressively
+ *  increased by 1 from 0.
+ *
+ *  This is a special p2m reading function for xen PV domain vmcores after
+ *  kernel commit 054954eb051f35e74b75a566a96fe756015352c8 (xen: switch
+ *  to linear virtual mapped sparse p2m list). It is invoked for reading
+ *  p2m associate stuff by read_p2m().
+ */
+static int read_xc_p2m(ulonglong addr, void *buffer, long size)
+{
+	ulong i, new_p2m_buf_size;
+	off_t offset;
+	struct xen_dumpcore_p2m *new_p2m_buf;
+	static struct xen_dumpcore_p2m *p2m_buf;
+	static ulong p2m_buf_size = 0;
+
+	if (size <= 0) {
+		if ((CRASHDEBUG(1) && !STREQ(pc->curcmd, "search")) ||
+			CRASHDEBUG(2))
+			error(INFO, "invalid size request: %ld\n", size);
+		return FALSE;
+	}
+
+	/*
+	 * We extract xen_dumpcore_p2m.gmfn and copy them into the
+	 * buffer. So, we need temporary p2m_buf whose size is
+	 * (size * (sizeof(struct xen_dumpcore_p2m) / sizeof(ulong)))
+	 * to put xen_dumpcore_p2m structures read from xd->xfd.
+	 */
+	new_p2m_buf_size = size * (sizeof(struct xen_dumpcore_p2m) / sizeof(ulong));
+
+	if (p2m_buf_size != new_p2m_buf_size) {
+		p2m_buf_size = new_p2m_buf_size;
+
+		new_p2m_buf = realloc(p2m_buf, p2m_buf_size);
+		if (new_p2m_buf == NULL) {
+			free(p2m_buf);
+			error(FATAL, "cannot realloc p2m buffer\n");
+		}
+		p2m_buf = new_p2m_buf;
+	}
+
+	offset = addr * (sizeof(struct xen_dumpcore_p2m) / sizeof(ulong));
+	offset += xd->xc_core.header.xch_index_offset;
+
+	if (lseek(xd->xfd, offset, SEEK_SET) == -1)
+		error(FATAL,
+		    "cannot lseek to xch_index_offset offset 0x%lx\n", offset);
+	if (read(xd->xfd, (void*)p2m_buf, p2m_buf_size) != p2m_buf_size)
+		error(FATAL,
+		    "cannot read from xch_index_offset offset 0x%lx\n", offset);
+
+	for (i = 0; i < size / sizeof(ulong); i++)
+		*((ulong *)buffer + i) = p2m_buf[i].gmfn;
+
+	return TRUE;
+}
+
+static ulong
+__xen_pvops_m2p_domU(ulonglong machine, ulong mfn)
+{
+	ulong c, end, i, mapping, p, pfn, start;
+
+	/*
+	 * xch_nr_pages is the number of pages of p2m mapping. It is composed
+	 * of struct xen_dumpcore_p2m. The stuff we want to copy into the mapping
+	 * page is mfn whose type is unsigned long.
+	 * So actual number of p2m pages should be:
+	 *
+	 * xch_nr_pages / (sizeof(struct xen_dumpcore_p2m) / sizeof(ulong))
+	 */
+	for (p = 0;
+	     p < xd->xc_core.header.xch_nr_pages /
+		(sizeof(struct xen_dumpcore_p2m) / sizeof(ulong));
+	     ++p) {
+
+		mapping = p * PAGESIZE();
+
+		if (mapping != kt->last_mapping_read) {
+			if (!read_xc_p2m(mapping, (void *)kt->m2p_page, PAGESIZE()))
+				error(FATAL, "cannot read the last mapping page\n");
+			kt->last_mapping_read = mapping;
+		}
+		kt->p2m_pages_searched++;
+
+		if (search_mapping_page(mfn, &i, &start, &end)) {
+			pfn = p * XEN_PFNS_PER_PAGE + i;
+			c = kt->p2m_cache_index;
+			if (CRASHDEBUG (1))
+				console("mfn: %lx (%llx) i: %ld pfn: %lx (%llx)\n",
+					mfn, machine, i, pfn, XEN_PFN_TO_PSEUDO(pfn));
+
+			kt->p2m_mapping_cache[c].start = start;
+			kt->p2m_mapping_cache[c].end = end;
+			kt->p2m_mapping_cache[c].mapping = mapping;
+			kt->p2m_mapping_cache[c].pfn = p * XEN_PFNS_PER_PAGE;
+			kt->p2m_cache_index = (c+1) % P2M_MAPPING_CACHE;
+
+			return pfn;
+		}
+	}
+
+	return XEN_MFN_NOT_FOUND;
+}
+
 /*
  *  Search for an mfn in the current mapping page, and if found,
  *  determine the range of contiguous mfns that it's contained
--- a/xendump.c
+++ b/xendump.c
@@ -19,7 +19,7 @@
 #include "xendump.h"

 static struct xendump_data xendump_data = { 0 };
-static struct xendump_data *xd = &xendump_data;
+struct xendump_data *xd = &xendump_data;

 static int xc_save_verify(char *);
 static int xc_core_verify(char *, char *);
--- a/xendump.h
+++ b/xendump.h
@@ -192,3 +192,5 @@ struct xen_dumpcore_p2m {
 	uint64_t pfn;
 	uint64_t gmfn;
 };
+
+extern struct xendump_data *xd;

```

Generate a backported patch for the SUSE target version.

[Assistant]
crash patch c3413456599161cabc4e910a0ae91dfe5eec3c21 (xen: Add support for
dom0 with Linux kernel 3.19 and newer) from Daniel made crash utility
support xen dom0 vmcores after linux kernel commit
054954eb051f35e74b75a566a96fe756015352c8 (xen: switch to linear virtual
mapped sparse p2m list).

This patch can be deemed as a subsequent and make this utility support Xen
PV domU dumpfiles again.

Basically speaking, readmem() can't be used to read xen_p2m_addr associate
memory directly during m2p translation. It introduces infinite recursion.
Following call sequence shows the scenario, it comes from a section of
backtrace with only kvaddr, machine addr and mfn left as parameter:

module_init()

/* The first readmem() from module_init(). */
readmem(addr=0xffffffffa02fe4a0)

/* readmem() needs physical address, so calls kvtop(). */
kvtop(kvaddr=0xffffffffa02fe4a0)
x86_64_kvtop(kvaddr=ffffffffa02fe4a0)

/* Calculate physical address by traversing page tables. */
x86_64_kvtop_xen_wpt(kvaddr=0xffffffffa02fe4a0)

/*
 * x86_64_kvtop_xen_wpt() is going to traverse the page table to
 * get the physical address for 0xffffffffa02fe4a0. So, at first it
 * is needed to translate the pgd from machine address to physical
 * address. So invoke xen_m2p() here to do the translation. 0x58687f000
 * is the pgd machine address in x86_64_kvtop_xen_wpt() and is needed
 * to be translated to its physical address.
 */
xen_m2p(machine=0x58687f000)
__xen_m2p(machine=0x58687f000, mfn=0x58687f)

/*
 * __xen_m2p() is going to search mfn 0x58687f in p2m VMA which starts
 * at VMA 0xffffc900001cf000. It compares every mfn stored in it with
 * 0x58687f. Once it's proved 0x58687f is one mfn in the p2m, its offset
 * will be used to calculate the pfn.
 *
 * readmem() is invoked by __xen_m2p() to read the page from VMA
 * 0xffffc900001cf000 here.
 */
readmem(addr=0xffffc900001cf000)

/*
 * readmem() needs physical address of 0xffffc900001cf000 to make the
 * reading done. So it invokes kvtop() to get the physical address.
 */
kvtop(kvaddr=0xffffc900001cf000)
x86_64_kvtop(kvaddr=0xffffc900001cf000)

/* It needs to calculate physical address by traversing page tables. */
x86_64_kvtop_xen_wpt(kvaddr=0xffffc900001cf000)

/*
 * 0x581b7e000 is the machine address of pgd need to be translated here.
 * The mfn is calculated in this way at x86_64_kvtop_xen_wpt():
 *
 * pml4 = ((ulong *)machdep->machspec->pml4) + pml4_index(kvaddr);
 * pgd_paddr = (*pml4) & PHYSICAL_PAGE_MASK;
 *
 * The kvaddr 0xffffc900001cf000 here is quite different from the one
 * above, so the machine address of pgd is not the same one. And this
 * pgd is the one we use to access the VMA of p2m table.
 */
xen_m2p(machine=0x581b7e000)
__xen_m2p(machine=0x581b7e000, mfn=0x581b7e)

/*
 * Looking for mfn 0x581b7e in the range of p2m page which starts at
 * VMA 0xffffc900001f5000.
 */
readmem(addr=0xffffc900001f5000)

/* Need physical address of VMA 0xffffc900001f5000 as same reason above. */
kvtop(kvaddr=0xffffc900001f5000)
x86_64_kvtop(kvaddr=0xffffc900001f5000)

/* Need to traverse page tables to calculate physical address for it. */
x86_64_kvtop_xen_wpt(kvaddr=0xffffc900001f5000)

/*
 * Unfortunately, machine address 0x581b7e000 have to be translated again.
 * Endless loop starts from here.
 */
xen_m2p(machine=0x581b7e000)
__xen_m2p(machine=0x581b7e000, mfn=0x581b7e)
readmem(addr=0xffffc900001f5000)

Fortunately, PV domU p2m mapping is also stored at xd->xfd + xch_index_offset
and organized as struct xen_dumpcore_p2m. We have a chance to read the p2m
stuff directly from there, and then we avoid the loop above.

So, this patch implements a special reading function read_xc_p2m() to extract
the mfns from xd->xfd + xch_index_offset. This function does not need to read
mfns from p2m VMA like readmem() does, so, we avoid the endless loop introduced
by the address translation.

Signed-off-by: Honglei Wang <honglei.wang@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
 kernel.c  |  151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 xendump.c |    2
 xendump.h |    2
 3 files changed, 140 insertions(+), 15 deletions(-)

--- a/kernel.c
+++ b/kernel.c
@@ -22,6 +22,7 @@
 #include <libgen.h>
 #include <ctype.h>
 #include <stdbool.h>
+#include "xendump.h"

 static void do_module_cmd(ulong, char *, ulong, char *, char *);
 static void show_module_taint(void);
@@ -67,6 +68,9 @@ static ulong __xen_m2p(ulonglong, ulong)
 static ulong __xen_pvops_m2p_l2(ulonglong, ulong);
 static ulong __xen_pvops_m2p_l3(ulonglong, ulong);
 static ulong __xen_pvops_m2p_hyper(ulonglong, ulong);
+static ulong __xen_pvops_m2p_domU(ulonglong, ulong);
+static int read_xc_p2m(ulonglong addr, void *buffer, long size);
+static void read_p2m(ulong cache_index, int memtype, void *buffer);
 static int search_mapping_page(ulong, ulong *, ulong *, ulong *);
 static void read_in_kernel_config_err(int, char *);
 static void BUG_bytes_init(void);
@@ -181,10 +185,7 @@ kernel_init()
 						&kt->pvops_xen.p2m_mid_missing);
 			get_symbol_data("p2m_missing", sizeof(ulong),
 						&kt->pvops_xen.p2m_missing);
-		} else if (symbol_exists("xen_p2m_addr")) {
-			if (!XEN_CORE_DUMPFILE())
-				error(FATAL, "p2m array in new format is unreadable.");
-		} else {
+		} else if (!symbol_exists("xen_p2m_addr")) {
 			kt->pvops_xen.p2m_top_entries = get_array_length("p2m_top", NULL, 0);
 			kt->pvops_xen.p2m_top = symbol_value("p2m_top");
 			kt->pvops_xen.p2m_missing = symbol_value("p2m_missing");
@@ -9312,13 +9313,7 @@ __xen_m2p(ulonglong machine, ulong mfn)
 				if (memtype == PHYSADDR)
 					pc->curcmd_flags |= XEN_MACHINE_ADDR;

-				if (!readmem(kt->p2m_mapping_cache[c].mapping, memtype,
-			       	    mp, PAGESIZE(), "phys_to_machine_mapping page (cached)",
-			    	    RETURN_ON_ERROR))
-                                	error(FATAL, "cannot access "
-                                    	    "phys_to_machine_mapping page\n");
-				else
-					kt->last_mapping_read = kt->p2m_mapping_cache[c].mapping;
+				read_p2m(c, memtype, mp);

 				if (memtype == PHYSADDR)
 					pc->curcmd_flags &= ~XEN_MACHINE_ADDR;
@@ -9356,9 +9351,12 @@ __xen_m2p(ulonglong machine, ulong mfn)
 		 */
 		if (symbol_exists("p2m_mid_missing"))
 			pfn = __xen_pvops_m2p_l3(machine, mfn);
-		else if (symbol_exists("xen_p2m_addr"))
-			pfn = __xen_pvops_m2p_hyper(machine, mfn);
-		else
+		else if (symbol_exists("xen_p2m_addr")) {
+			if (XEN_CORE_DUMPFILE())
+				pfn = __xen_pvops_m2p_hyper(machine, mfn);
+			else
+				pfn = __xen_pvops_m2p_domU(machine, mfn);
+		} else
 			pfn = __xen_pvops_m2p_l2(machine, mfn);

 		if (pfn != XEN_MFN_NOT_FOUND)
@@ -9566,6 +9564,131 @@ __xen_pvops_m2p_hyper(ulonglong machine,
 	return XEN_MFN_NOT_FOUND;
 }

+static void read_p2m(ulong cache_index, int memtype, void *buffer)
+{
+	/*
+	 *  Use special read function for PV domain p2m reading.
+	 *  See the comments of read_xc_p2m().
+	 */
+	if (symbol_exists("xen_p2m_addr") && !XEN_CORE_DUMPFILE()) {
+		if (!read_xc_p2m(kt->p2m_mapping_cache[cache_index].mapping,
+			buffer, PAGESIZE()))
+			error(FATAL, "cannot access phys_to_machine_mapping page\n");
+	} else if (!readmem(kt->p2m_mapping_cache[cache_index].mapping, memtype,
+			buffer, PAGESIZE(), "phys_to_machine_mapping page (cached)",
+			RETURN_ON_ERROR))
+		error(FATAL, "cannot access phys_to_machine_mapping page\n");
+
+	kt->last_mapping_read = kt->p2m_mapping_cache[cache_index].mapping;
+}
+
+/*
+ *  PV domain p2m mapping info is stored in xd->xfd at xch_index_offset. It
+ *  is organized as struct xen_dumpcore_p2m and the pfns are progressively
+ *  increased by 1 from 0.
+ *
+ *  This is a special p2m reading function for xen PV domain vmcores after
+ *  kernel commit 054954eb051f35e74b75a566a96fe756015352c8 (xen: switch
+ *  to linear virtual mapped sparse p2m list). It is invoked for reading
+ *  p2m associate stuff by read_p2m().
+ */
+static int read_xc_p2m(ulonglong addr, void *buffer, long size)
+{
+	ulong i, new_p2m_buf_size;
+	off_t offset;
+	struct xen_dumpcore_p2m *new_p2m_buf;
+	static struct xen_dumpcore_p2m *p2m_buf;
+	static ulong p2m_buf_size = 0;
+
+	if (size <= 0) {
+		if ((CRASHDEBUG(1) && !STREQ(pc->curcmd, "search")) ||
+			CRASHDEBUG(2))
+			error(INFO, "invalid size request: %ld\n", size);
+		return FALSE;
+	}
+
+	/*
+	 * We extract xen_dumpcore_p2m.gmfn and copy them into the
+	 * buffer. So, we need temporary p2m_buf whose size is
+	 * (size * (sizeof(struct xen_dumpcore_p2m) / sizeof(ulong)))
+	 * to put xen_dumpcore_p2m structures read from xd->xfd.
+	 */
+	new_p2m_buf_size = size * (sizeof(struct xen_dumpcore_p2m) / sizeof(ulong));
+
+	if (p2m_buf_size != new_p2m_buf_size) {
+		p2m_buf_size = new_p2m_buf_size;
+
+		new_p2m_buf = realloc(p2m_buf, p2m_buf_size);
+		if (new_p2m_buf == NULL) {
+			free(p2m_buf);
+			error(FATAL, "cannot realloc p2m buffer\n");
+		}
+		p2m_buf = new_p2m_buf;
+	}
+
+	offset = addr * (sizeof(struct xen_dumpcore_p2m) / sizeof(ulong));
+	offset += xd->xc_core.header.xch_index_offset;
+
+	if (lseek(xd->xfd, offset, SEEK_SET) == -1)
+		error(FATAL,
+		    "cannot lseek to xch_index_offset offset 0x%lx\n", offset);
+	if (read(xd->xfd, (void*)p2m_buf, p2m_buf_size) != p2m_buf_size)
+		error(FATAL,
+		    "cannot read from xch_index_offset offset 0x%lx\n", offset);
+
+	for (i = 0; i < size / sizeof(ulong); i++)
+		*((ulong *)buffer + i) = p2m_buf[i].gmfn;
+
+	return TRUE;
+}
+
+static ulong
+__xen_pvops_m2p_domU(ulonglong machine, ulong mfn)
+{
+	ulong c, end, i, mapping, p, pfn, start;
+
+	/*
+	 * xch_nr_pages is the number of pages of p2m mapping. It is composed
+	 * of struct xen_dumpcore_p2m. The stuff we want to copy into the mapping
+	 * page is mfn whose type is unsigned long.
+	 * So actual number of p2m pages should be:
+	 *
+	 * xch_nr_pages / (sizeof(struct xen_dumpcore_p2m) / sizeof(ulong))
+	 */
+	for (p = 0;
+	     p < xd->xc_core.header.xch_nr_pages /
+		(sizeof(struct xen_dumpcore_p2m) / sizeof(ulong));
+	     ++p) {
+
+		mapping = p * PAGESIZE();
+
+		if (mapping != kt->last_mapping_read) {
+			if (!read_xc_p2m(mapping, (void *)kt->m2p_page, PAGESIZE()))
+				error(FATAL, "cannot read the last mapping page\n");
+			kt->last_mapping_read = mapping;
+		}
+		kt->p2m_pages_searched++;
+
+		if (search_mapping_page(mfn, &i, &start, &end)) {
+			pfn = p * XEN_PFNS_PER_PAGE + i;
+			c = kt->p2m_cache_index;
+			if (CRASHDEBUG (1))
+				console("mfn: %lx (%llx) i: %ld pfn: %lx (%llx)\n",
+					mfn, machine, i, pfn, XEN_PFN_TO_PSEUDO(pfn));
+
+			kt->p2m_mapping_cache[c].start = start;
+			kt->p2m_mapping_cache[c].end = end;
+			kt->p2m_mapping_cache[c].mapping = mapping;
+			kt->p2m_mapping_cache[c].pfn = p * XEN_PFNS_PER_PAGE;
+			kt->p2m_cache_index = (c+1) % P2M_MAPPING_CACHE;
+
+			return pfn;
+		}
+	}
+
+	return XEN_MFN_NOT_FOUND;
+}
+
 /*
  *  Search for an mfn in the current mapping page, and if found,
  *  determine the range of contiguous mfns that it's contained
--- a/xendump.c
+++ b/xendump.c
@@ -19,7 +19,7 @@
 #include "xendump.h"

 static struct xendump_data xendump_data = { 0 };
-static struct xendump_data *xd = &xendump_data;
+struct xendump_data *xd = &xendump_data;

 static int xc_save_verify(char *);
 static int xc_core_verify(char *, char *);
--- a/xendump.h
+++ b/xendump.h
@@ -192,3 +192,5 @@ struct xen_dumpcore_p2m {
 	uint64_t pfn;
 	uint64_t gmfn;
 };
+
+extern struct xendump_data *xd;


[System]
You are a security patch backporting assistant for SUSE/openSUSE.

Given a CVE description and an upstream fix, adapt the patch to work with
the target SUSE package version. Output the backported patch in unified
diff format. If the upstream fix applies directly, output it unchanged.

[User]
## CVE: CVE-2017-5715

CFLAGS.extra  |    1 +

## Package
crash

## Upstream Fix
```diff
---
 CFLAGS.extra  |    1 +
 LDFLAGS.extra |    1 +
 2 files changed, 2 insertions(+)

--- /dev/null
+++ b/CFLAGS.extra
@@ -0,0 +1 @@
+-DLZO
--- /dev/null
+++ b/LDFLAGS.extra
@@ -0,0 +1 @@
+-llzo2

```

Generate a backported patch for the SUSE target version.

[Assistant]
---
 CFLAGS.extra  |    1 +
 LDFLAGS.extra |    1 +
 2 files changed, 2 insertions(+)

--- /dev/null
+++ b/CFLAGS.extra
@@ -0,0 +1 @@
+-DLZO
--- /dev/null
+++ b/LDFLAGS.extra
@@ -0,0 +1 @@
+-llzo2


[System]
You are a security patch backporting assistant for SUSE/openSUSE.

Given a CVE description and an upstream fix, adapt the patch to work with
the target SUSE package version. Output the backported patch in unified
diff format. If the upstream fix applies directly, output it unchanged.

[User]
## CVE: CVE-2017-5715

From: Petr Tesarik <ptesarik@suse.cz>

## Package
crash

## Files to modify
- CFLAGS.extra
- LDFLAGS.extra

## Upstream Fix
```diff
From: Petr Tesarik <ptesarik@suse.cz>
Subject: enably snappy support
Patch-mainline: never, configurable default

Signed-off-by: Petr Tesarik <ptesarik@suse.cz>

---
 CFLAGS.extra  |    2 +-
 LDFLAGS.extra |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

--- a/CFLAGS.extra
+++ b/CFLAGS.extra
@@ -1 +1 @@
--DLZO
+-DLZO -DSNAPPY
--- a/LDFLAGS.extra
+++ b/LDFLAGS.extra
@@ -1 +1 @@
--llzo2
+-llzo2 -lsnappy

```

Generate a backported patch for the SUSE target version.

[Assistant]
From: Petr Tesarik <ptesarik@suse.cz>
Subject: enably snappy support
Patch-mainline: never, configurable default

Signed-off-by: Petr Tesarik <ptesarik@suse.cz>

---
 CFLAGS.extra  |    2 +-
 LDFLAGS.extra |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

--- a/CFLAGS.extra
+++ b/CFLAGS.extra
@@ -1 +1 @@
--DLZO
+-DLZO -DSNAPPY
--- a/LDFLAGS.extra
+++ b/LDFLAGS.extra
@@ -1 +1 @@
--llzo2
+-llzo2 -lsnappy


[System]
You are a security patch backporting assistant for SUSE/openSUSE.

Given a CVE description and an upstream fix, adapt the patch to work with
the target SUSE package version. Output the backported patch in unified
diff format. If the upstream fix applies directly, output it unchanged.

[User]
## CVE: CVE-2017-5715

From: Luc Chouinard <lchouinard@lchouinard-desktop.englab.juniper.net>

## Package
crash

## Files to modify
- extensions/eppic/applications/crash/eppic.c

## Target Source Code

### eppic/applications/crash/eppic.c

#### _init() [lines 984-5]
```c

```

## Upstream Fix
```diff
From: Luc Chouinard <lchouinard@lchouinard-desktop.englab.juniper.net>
Date: Thu Jun 19 12:28:40 2014 -0700
Subject: Support for ARM64
References: FATE#320844
Patch-mainline: yes
Git-commit: 5391d3dd0e6710c22ec5801f99a6788a2e4b132a

Acked-by: Petr Tesarik <ptesarik@suse.com>

---
 extensions/eppic/applications/crash/eppic.c |    4 ++++
 1 file changed, 4 insertions(+)

--- a/extensions/eppic/applications/crash/eppic.c
+++ b/extensions/eppic/applications/crash/eppic.c
@@ -1033,10 +1033,14 @@ _init() /* Register the command set. */
 #ifdef PPC64
 #define EPPIC_ABI  ABI_PPC64
 #else
+#ifdef ARM64
+#define EPPIC_ABI  ABI_ARM64
+#else
 #error eppic: Unkown ABI
 #endif
 #endif
 #endif
+#endif
 #endif
 #endif
 #endif

```

Generate a backported patch for the SUSE target version.

[Assistant]
From: Luc Chouinard <lchouinard@lchouinard-desktop.englab.juniper.net>
Date: Thu Jun 19 12:28:40 2014 -0700
Subject: Support for ARM64
References: FATE#320844
Patch-mainline: yes
Git-commit: 5391d3dd0e6710c22ec5801f99a6788a2e4b132a

Acked-by: Petr Tesarik <ptesarik@suse.com>

---
 extensions/eppic/applications/crash/eppic.c |    4 ++++
 1 file changed, 4 insertions(+)

--- a/extensions/eppic/applications/crash/eppic.c
+++ b/extensions/eppic/applications/crash/eppic.c
@@ -1033,10 +1033,14 @@ _init() /* Register the command set. */
 #ifdef PPC64
 #define EPPIC_ABI  ABI_PPC64
 #else
+#ifdef ARM64
+#define EPPIC_ABI  ABI_ARM64
+#else
 #error eppic: Unkown ABI
 #endif
 #endif
 #endif
+#endif
 #endif
 #endif
 #endif