| From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> |
| Date: Wed, 9 May 2018 19:42:20 +0900 |
| Subject: x86/kexec: Avoid double free_page() upon do_kexec_load() failure |
| |
| commit a466ef76b815b86748d9870ef2a430af7b39c710 upstream. |
| |
| >From ff82bedd3e12f0d3353282054ae48c3bd8c72012 Mon Sep 17 00:00:00 2001 |
| From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> |
| Date: Wed, 9 May 2018 12:12:39 +0900 |
| Subject: [PATCH v3] x86/kexec: avoid double free_page() upon do_kexec_load() failure. |
| |
| syzbot is reporting crashes after memory allocation failure inside |
| do_kexec_load() [1]. This is because free_transition_pgtable() is called |
| by both init_transition_pgtable() and machine_kexec_cleanup() when memory |
| allocation failed inside init_transition_pgtable(). |
| |
| Regarding 32bit code, machine_kexec_free_page_tables() is called by both |
| machine_kexec_alloc_page_tables() and machine_kexec_cleanup() when memory |
| allocation failed inside machine_kexec_alloc_page_tables(). |
| |
| Fix this by leaving the error handling to machine_kexec_cleanup() |
| (and optionally setting NULL after free_page()). |
| |
| [1] https://syzkaller.appspot.com/bug?id=91e52396168cf2bdd572fe1e1bc0bc645c1c6b40 |
| |
| Fixes: f5deb79679af6eb4 ("x86: kexec: Use one page table in x86_64 machine_kexec") |
| Fixes: 92be3d6bdf2cb349 ("kexec/i386: allocate page table pages dynamically") |
| Reported-by: syzbot <syzbot+d96f60296ef613fe1d69@syzkaller.appspotmail.com> |
| Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Acked-by: Baoquan He <bhe@redhat.com> |
| Cc: thomas.lendacky@amd.com |
| Cc: prudo@linux.vnet.ibm.com |
| Cc: Huang Ying <ying.huang@intel.com> |
| Cc: syzkaller-bugs@googlegroups.com |
| Cc: takahiro.akashi@linaro.org |
| Cc: H. Peter Anvin <hpa@zytor.com> |
| Cc: akpm@linux-foundation.org |
| Cc: dyoung@redhat.com |
| Cc: kirill.shutemov@linux.intel.com |
| Link: https://lkml.kernel.org/r/201805091942.DGG12448.tMFVFSJFQOOLHO@I-love.SAKURA.ne.jp |
| [bwh: Backported to 3.16: No need to handle a P4D] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| --- a/arch/x86/kernel/machine_kexec_32.c |
| +++ b/arch/x86/kernel/machine_kexec_32.c |
| @@ -70,12 +70,17 @@ static void load_segments(void) |
| static void machine_kexec_free_page_tables(struct kimage *image) |
| { |
| free_page((unsigned long)image->arch.pgd); |
| + image->arch.pgd = NULL; |
| #ifdef CONFIG_X86_PAE |
| free_page((unsigned long)image->arch.pmd0); |
| + image->arch.pmd0 = NULL; |
| free_page((unsigned long)image->arch.pmd1); |
| + image->arch.pmd1 = NULL; |
| #endif |
| free_page((unsigned long)image->arch.pte0); |
| + image->arch.pte0 = NULL; |
| free_page((unsigned long)image->arch.pte1); |
| + image->arch.pte1 = NULL; |
| } |
| |
| static int machine_kexec_alloc_page_tables(struct kimage *image) |
| @@ -92,7 +97,6 @@ static int machine_kexec_alloc_page_tabl |
| !image->arch.pmd0 || !image->arch.pmd1 || |
| #endif |
| !image->arch.pte0 || !image->arch.pte1) { |
| - machine_kexec_free_page_tables(image); |
| return -ENOMEM; |
| } |
| return 0; |
| --- a/arch/x86/kernel/machine_kexec_64.c |
| +++ b/arch/x86/kernel/machine_kexec_64.c |
| @@ -25,8 +25,11 @@ |
| static void free_transition_pgtable(struct kimage *image) |
| { |
| free_page((unsigned long)image->arch.pud); |
| + image->arch.pud = NULL; |
| free_page((unsigned long)image->arch.pmd); |
| + image->arch.pmd = NULL; |
| free_page((unsigned long)image->arch.pte); |
| + image->arch.pte = NULL; |
| } |
| |
| static int init_transition_pgtable(struct kimage *image, pgd_t *pgd) |
| @@ -67,7 +70,6 @@ static int init_transition_pgtable(struc |
| set_pte(pte, pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL_EXEC)); |
| return 0; |
| err: |
| - free_transition_pgtable(image); |
| return result; |
| } |
| |