Skip to content

Commit 5bb513e

Browse files
committed
Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
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
2 parents 820828b + ea57368 commit 5bb513e

File tree

2 files changed

+32
-31
lines changed

2 files changed

+32
-31
lines changed

arch/arm64/kernel/machine_kexec_file.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,12 @@ static int create_dtb(struct kimage *image,
120120
{
121121
void *buf;
122122
size_t buf_size;
123+
size_t cmdline_len;
123124
int ret;
124125

126+
cmdline_len = cmdline ? strlen(cmdline) : 0;
125127
buf_size = fdt_totalsize(initial_boot_params)
126-
+ strlen(cmdline) + DTB_EXTRA_SPACE;
128+
+ cmdline_len + DTB_EXTRA_SPACE;
127129

128130
for (;;) {
129131
buf = vmalloc(buf_size);

arch/arm64/mm/dump.c

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -286,74 +286,73 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level,
286286

287287
}
288288

289-
static void walk_pte(struct pg_state *st, pmd_t *pmdp, unsigned long start)
289+
static void walk_pte(struct pg_state *st, pmd_t *pmdp, unsigned long start,
290+
unsigned long end)
290291
{
291-
pte_t *ptep = pte_offset_kernel(pmdp, 0UL);
292-
unsigned long addr;
293-
unsigned i;
292+
unsigned long addr = start;
293+
pte_t *ptep = pte_offset_kernel(pmdp, start);
294294

295-
for (i = 0; i < PTRS_PER_PTE; i++, ptep++) {
296-
addr = start + i * PAGE_SIZE;
295+
do {
297296
note_page(st, addr, 4, READ_ONCE(pte_val(*ptep)));
298-
}
297+
} while (ptep++, addr += PAGE_SIZE, addr != end);
299298
}
300299

301-
static void walk_pmd(struct pg_state *st, pud_t *pudp, unsigned long start)
300+
static void walk_pmd(struct pg_state *st, pud_t *pudp, unsigned long start,
301+
unsigned long end)
302302
{
303-
pmd_t *pmdp = pmd_offset(pudp, 0UL);
304-
unsigned long addr;
305-
unsigned i;
303+
unsigned long next, addr = start;
304+
pmd_t *pmdp = pmd_offset(pudp, start);
306305

307-
for (i = 0; i < PTRS_PER_PMD; i++, pmdp++) {
306+
do {
308307
pmd_t pmd = READ_ONCE(*pmdp);
308+
next = pmd_addr_end(addr, end);
309309

310-
addr = start + i * PMD_SIZE;
311310
if (pmd_none(pmd) || pmd_sect(pmd)) {
312311
note_page(st, addr, 3, pmd_val(pmd));
313312
} else {
314313
BUG_ON(pmd_bad(pmd));
315-
walk_pte(st, pmdp, addr);
314+
walk_pte(st, pmdp, addr, next);
316315
}
317-
}
316+
} while (pmdp++, addr = next, addr != end);
318317
}
319318

320-
static void walk_pud(struct pg_state *st, pgd_t *pgdp, unsigned long start)
319+
static void walk_pud(struct pg_state *st, pgd_t *pgdp, unsigned long start,
320+
unsigned long end)
321321
{
322-
pud_t *pudp = pud_offset(pgdp, 0UL);
323-
unsigned long addr;
324-
unsigned i;
322+
unsigned long next, addr = start;
323+
pud_t *pudp = pud_offset(pgdp, start);
325324

326-
for (i = 0; i < PTRS_PER_PUD; i++, pudp++) {
325+
do {
327326
pud_t pud = READ_ONCE(*pudp);
327+
next = pud_addr_end(addr, end);
328328

329-
addr = start + i * PUD_SIZE;
330329
if (pud_none(pud) || pud_sect(pud)) {
331330
note_page(st, addr, 2, pud_val(pud));
332331
} else {
333332
BUG_ON(pud_bad(pud));
334-
walk_pmd(st, pudp, addr);
333+
walk_pmd(st, pudp, addr, next);
335334
}
336-
}
335+
} while (pudp++, addr = next, addr != end);
337336
}
338337

339338
static void walk_pgd(struct pg_state *st, struct mm_struct *mm,
340339
unsigned long start)
341340
{
342-
pgd_t *pgdp = pgd_offset(mm, 0UL);
343-
unsigned i;
344-
unsigned long addr;
341+
unsigned long end = (start < TASK_SIZE_64) ? TASK_SIZE_64 : 0;
342+
unsigned long next, addr = start;
343+
pgd_t *pgdp = pgd_offset(mm, start);
345344

346-
for (i = 0; i < PTRS_PER_PGD; i++, pgdp++) {
345+
do {
347346
pgd_t pgd = READ_ONCE(*pgdp);
347+
next = pgd_addr_end(addr, end);
348348

349-
addr = start + i * PGDIR_SIZE;
350349
if (pgd_none(pgd)) {
351350
note_page(st, addr, 1, pgd_val(pgd));
352351
} else {
353352
BUG_ON(pgd_bad(pgd));
354-
walk_pud(st, pgdp, addr);
353+
walk_pud(st, pgdp, addr, next);
355354
}
356-
}
355+
} while (pgdp++, addr = next, addr != end);
357356
}
358357

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

0 commit comments

Comments
 (0)