Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5bb513ed authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull arm64 fixes from Will Deacon:
 "Two arm64 fixes for -rc6. They resolve a kernel NULL dereference in
  kexec and bogus kernel page table dumping when userspace is configured
  for 52-bit virtual addressing.

  Summary:

   - Fix kernel oops when attemping kexec_file() with a NULL cmdline

   - Fix page table output in debugfs when ARM64_USER_VA_BITS_52=y"

* tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux:
  arm64: kexec_file: handle empty command-line
  arm64: ptdump: Don't iterate kernel page tables using PTRS_PER_PXX
parents 820828bf ea573680
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -120,10 +120,12 @@ static int create_dtb(struct kimage *image,
{
	void *buf;
	size_t buf_size;
	size_t cmdline_len;
	int ret;

	cmdline_len = cmdline ? strlen(cmdline) : 0;
	buf_size = fdt_totalsize(initial_boot_params)
			+ strlen(cmdline) + DTB_EXTRA_SPACE;
			+ cmdline_len + DTB_EXTRA_SPACE;

	for (;;) {
		buf = vmalloc(buf_size);
+29 −30
Original line number Diff line number Diff line
@@ -286,74 +286,73 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level,

}

static void walk_pte(struct pg_state *st, pmd_t *pmdp, unsigned long start)
static void walk_pte(struct pg_state *st, pmd_t *pmdp, unsigned long start,
		     unsigned long end)
{
	pte_t *ptep = pte_offset_kernel(pmdp, 0UL);
	unsigned long addr;
	unsigned i;
	unsigned long addr = start;
	pte_t *ptep = pte_offset_kernel(pmdp, start);

	for (i = 0; i < PTRS_PER_PTE; i++, ptep++) {
		addr = start + i * PAGE_SIZE;
	do {
		note_page(st, addr, 4, READ_ONCE(pte_val(*ptep)));
	}
	} while (ptep++, addr += PAGE_SIZE, addr != end);
}

static void walk_pmd(struct pg_state *st, pud_t *pudp, unsigned long start)
static void walk_pmd(struct pg_state *st, pud_t *pudp, unsigned long start,
		     unsigned long end)
{
	pmd_t *pmdp = pmd_offset(pudp, 0UL);
	unsigned long addr;
	unsigned i;
	unsigned long next, addr = start;
	pmd_t *pmdp = pmd_offset(pudp, start);

	for (i = 0; i < PTRS_PER_PMD; i++, pmdp++) {
	do {
		pmd_t pmd = READ_ONCE(*pmdp);
		next = pmd_addr_end(addr, end);

		addr = start + i * PMD_SIZE;
		if (pmd_none(pmd) || pmd_sect(pmd)) {
			note_page(st, addr, 3, pmd_val(pmd));
		} else {
			BUG_ON(pmd_bad(pmd));
			walk_pte(st, pmdp, addr);
		}
			walk_pte(st, pmdp, addr, next);
		}
	} while (pmdp++, addr = next, addr != end);
}

static void walk_pud(struct pg_state *st, pgd_t *pgdp, unsigned long start)
static void walk_pud(struct pg_state *st, pgd_t *pgdp, unsigned long start,
		     unsigned long end)
{
	pud_t *pudp = pud_offset(pgdp, 0UL);
	unsigned long addr;
	unsigned i;
	unsigned long next, addr = start;
	pud_t *pudp = pud_offset(pgdp, start);

	for (i = 0; i < PTRS_PER_PUD; i++, pudp++) {
	do {
		pud_t pud = READ_ONCE(*pudp);
		next = pud_addr_end(addr, end);

		addr = start + i * PUD_SIZE;
		if (pud_none(pud) || pud_sect(pud)) {
			note_page(st, addr, 2, pud_val(pud));
		} else {
			BUG_ON(pud_bad(pud));
			walk_pmd(st, pudp, addr);
		}
			walk_pmd(st, pudp, addr, next);
		}
	} while (pudp++, addr = next, addr != end);
}

static void walk_pgd(struct pg_state *st, struct mm_struct *mm,
		     unsigned long start)
{
	pgd_t *pgdp = pgd_offset(mm, 0UL);
	unsigned i;
	unsigned long addr;
	unsigned long end = (start < TASK_SIZE_64) ? TASK_SIZE_64 : 0;
	unsigned long next, addr = start;
	pgd_t *pgdp = pgd_offset(mm, start);

	for (i = 0; i < PTRS_PER_PGD; i++, pgdp++) {
	do {
		pgd_t pgd = READ_ONCE(*pgdp);
		next = pgd_addr_end(addr, end);

		addr = start + i * PGDIR_SIZE;
		if (pgd_none(pgd)) {
			note_page(st, addr, 1, pgd_val(pgd));
		} else {
			BUG_ON(pgd_bad(pgd));
			walk_pud(st, pgdp, addr);
		}
			walk_pud(st, pgdp, addr, next);
		}
	} while (pgdp++, addr = next, addr != end);
}

void ptdump_walk_pgd(struct seq_file *m, struct ptdump_info *info)