Skip to content

Commit 18fc694

Browse files
mrutland-armAlex Shi
authored andcommitted
arm64: hibernate: handle allocation failures
In create_safe_exec_page(), we create a copy of the hibernate exit text, along with some page tables to map this via TTBR0. We then install the new tables in TTBR0. In swsusp_arch_resume() we call create_safe_exec_page() before trying a number of operations which may fail (e.g. copying the linear map page tables). If these fail, we bail out of swsusp_arch_resume() and return an error code, but leave TTBR0 as-is. Subsequently, the core hibernate code will call free_basic_memory_bitmaps(), which will free all of the memory allocations we made, including the page tables installed in TTBR0. Thus, we may have TTBR0 pointing at dangling freed memory for some period of time. If the hibernate attempt was triggered by a user requesting a hibernate test via the reboot syscall, we may return to userspace with the clobbered TTBR0 value. Avoid these issues by reorganising swsusp_arch_resume() such that we have no failure paths after create_safe_exec_page(). We also add a check that the zero page allocation succeeded, matching what we have for other allocations. Fixes: 82869ac57b5d ("arm64: kernel: Add support for hibernate/suspend-to-disk") Signed-off-by: Mark Rutland <mark.rutland@arm.com> Acked-by: James Morse <james.morse@arm.com> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Cc: Will Deacon <will.deacon@arm.com> Cc: <stable@vger.kernel.org> # 4.7+ Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> (cherry picked from commit dfbca61af0b654990b9af8297ac574a9986d8275) Signed-off-by: Alex Shi <alex.shi@linaro.org>
1 parent 1ff46aa commit 18fc694

1 file changed

Lines changed: 32 additions & 27 deletions

File tree

arch/arm64/kernel/hibernate.c

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,38 @@ int swsusp_arch_resume(void)
398398
void __noreturn (*hibernate_exit)(phys_addr_t, phys_addr_t, void *,
399399
void *, phys_addr_t, phys_addr_t);
400400

401+
/*
402+
* Restoring the memory image will overwrite the ttbr1 page tables.
403+
* Create a second copy of just the linear map, and use this when
404+
* restoring.
405+
*/
406+
tmp_pg_dir = (pgd_t *)get_safe_page(GFP_ATOMIC);
407+
if (!tmp_pg_dir) {
408+
pr_err("Failed to allocate memory for temporary page tables.");
409+
rc = -ENOMEM;
410+
goto out;
411+
}
412+
rc = copy_page_tables(tmp_pg_dir, PAGE_OFFSET, 0);
413+
if (rc)
414+
goto out;
415+
416+
/*
417+
* Since we only copied the linear map, we need to find restore_pblist's
418+
* linear map address.
419+
*/
420+
lm_restore_pblist = LMADDR(restore_pblist);
421+
422+
/*
423+
* We need a zero page that is zero before & after resume in order to
424+
* to break before make on the ttbr1 page tables.
425+
*/
426+
zero_page = (void *)get_safe_page(GFP_ATOMIC);
427+
if (!zero_page) {
428+
pr_err("Failed to allocate zero page.");
429+
rc = -ENOMEM;
430+
goto out;
431+
}
432+
401433
/*
402434
* Locate the exit code in the bottom-but-one page, so that *NULL
403435
* still has disastrous affects.
@@ -423,27 +455,6 @@ int swsusp_arch_resume(void)
423455
*/
424456
__flush_dcache_area(hibernate_exit, exit_size);
425457

426-
/*
427-
* Restoring the memory image will overwrite the ttbr1 page tables.
428-
* Create a second copy of just the linear map, and use this when
429-
* restoring.
430-
*/
431-
tmp_pg_dir = (pgd_t *)get_safe_page(GFP_ATOMIC);
432-
if (!tmp_pg_dir) {
433-
pr_err("Failed to allocate memory for temporary page tables.");
434-
rc = -ENOMEM;
435-
goto out;
436-
}
437-
rc = copy_page_tables(tmp_pg_dir, PAGE_OFFSET, 0);
438-
if (rc)
439-
goto out;
440-
441-
/*
442-
* Since we only copied the linear map, we need to find restore_pblist's
443-
* linear map address.
444-
*/
445-
lm_restore_pblist = LMADDR(restore_pblist);
446-
447458
/*
448459
* KASLR will cause the el2 vectors to be in a different location in
449460
* the resumed kernel. Load hibernate's temporary copy into el2.
@@ -458,12 +469,6 @@ int swsusp_arch_resume(void)
458469
__hyp_set_vectors(el2_vectors);
459470
}
460471

461-
/*
462-
* We need a zero page that is zero before & after resume in order to
463-
* to break before make on the ttbr1 page tables.
464-
*/
465-
zero_page = (void *)get_safe_page(GFP_ATOMIC);
466-
467472
hibernate_exit(virt_to_phys(tmp_pg_dir), resume_hdr.ttbr1_el1,
468473
resume_hdr.reenter_kernel, lm_restore_pblist,
469474
resume_hdr.__hyp_stub_vectors, virt_to_phys(zero_page));

0 commit comments

Comments
 (0)