]>
Commit | Line | Data |
---|---|---|
10d555a3 GKH |
1 | From a466ef76b815b86748d9870ef2a430af7b39c710 Mon Sep 17 00:00:00 2001 |
2 | From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | |
3 | Date: Wed, 9 May 2018 19:42:20 +0900 | |
4 | Subject: x86/kexec: Avoid double free_page() upon do_kexec_load() failure | |
5 | ||
6 | From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | |
7 | ||
8 | commit a466ef76b815b86748d9870ef2a430af7b39c710 upstream. | |
9 | ||
10 | >From ff82bedd3e12f0d3353282054ae48c3bd8c72012 Mon Sep 17 00:00:00 2001 | |
11 | From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | |
12 | Date: Wed, 9 May 2018 12:12:39 +0900 | |
13 | Subject: x86/kexec: Avoid double free_page() upon do_kexec_load() failure | |
14 | ||
15 | syzbot is reporting crashes after memory allocation failure inside | |
16 | do_kexec_load() [1]. This is because free_transition_pgtable() is called | |
17 | by both init_transition_pgtable() and machine_kexec_cleanup() when memory | |
18 | allocation failed inside init_transition_pgtable(). | |
19 | ||
20 | Regarding 32bit code, machine_kexec_free_page_tables() is called by both | |
21 | machine_kexec_alloc_page_tables() and machine_kexec_cleanup() when memory | |
22 | allocation failed inside machine_kexec_alloc_page_tables(). | |
23 | ||
24 | Fix this by leaving the error handling to machine_kexec_cleanup() | |
25 | (and optionally setting NULL after free_page()). | |
26 | ||
27 | [1] https://syzkaller.appspot.com/bug?id=91e52396168cf2bdd572fe1e1bc0bc645c1c6b40 | |
28 | ||
29 | Fixes: f5deb79679af6eb4 ("x86: kexec: Use one page table in x86_64 machine_kexec") | |
30 | Fixes: 92be3d6bdf2cb349 ("kexec/i386: allocate page table pages dynamically") | |
31 | Reported-by: syzbot <syzbot+d96f60296ef613fe1d69@syzkaller.appspotmail.com> | |
32 | Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | |
33 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | |
34 | Acked-by: Baoquan He <bhe@redhat.com> | |
35 | Cc: thomas.lendacky@amd.com | |
36 | Cc: prudo@linux.vnet.ibm.com | |
37 | Cc: Huang Ying <ying.huang@intel.com> | |
38 | Cc: syzkaller-bugs@googlegroups.com | |
39 | Cc: takahiro.akashi@linaro.org | |
40 | Cc: H. Peter Anvin <hpa@zytor.com> | |
41 | Cc: akpm@linux-foundation.org | |
42 | Cc: dyoung@redhat.com | |
43 | Cc: kirill.shutemov@linux.intel.com | |
44 | Link: https://lkml.kernel.org/r/201805091942.DGG12448.tMFVFSJFQOOLHO@I-love.SAKURA.ne.jp | |
45 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
46 | ||
47 | --- | |
48 | arch/x86/kernel/machine_kexec_32.c | 6 +++++- | |
49 | arch/x86/kernel/machine_kexec_64.c | 4 +++- | |
50 | 2 files changed, 8 insertions(+), 2 deletions(-) | |
51 | ||
52 | --- a/arch/x86/kernel/machine_kexec_32.c | |
53 | +++ b/arch/x86/kernel/machine_kexec_32.c | |
54 | @@ -71,12 +71,17 @@ static void load_segments(void) | |
55 | static void machine_kexec_free_page_tables(struct kimage *image) | |
56 | { | |
57 | free_page((unsigned long)image->arch.pgd); | |
58 | + image->arch.pgd = NULL; | |
59 | #ifdef CONFIG_X86_PAE | |
60 | free_page((unsigned long)image->arch.pmd0); | |
61 | + image->arch.pmd0 = NULL; | |
62 | free_page((unsigned long)image->arch.pmd1); | |
63 | + image->arch.pmd1 = NULL; | |
64 | #endif | |
65 | free_page((unsigned long)image->arch.pte0); | |
66 | + image->arch.pte0 = NULL; | |
67 | free_page((unsigned long)image->arch.pte1); | |
68 | + image->arch.pte1 = NULL; | |
69 | } | |
70 | ||
71 | static int machine_kexec_alloc_page_tables(struct kimage *image) | |
72 | @@ -93,7 +98,6 @@ static int machine_kexec_alloc_page_tabl | |
73 | !image->arch.pmd0 || !image->arch.pmd1 || | |
74 | #endif | |
75 | !image->arch.pte0 || !image->arch.pte1) { | |
76 | - machine_kexec_free_page_tables(image); | |
77 | return -ENOMEM; | |
78 | } | |
79 | return 0; | |
80 | --- a/arch/x86/kernel/machine_kexec_64.c | |
81 | +++ b/arch/x86/kernel/machine_kexec_64.c | |
82 | @@ -37,8 +37,11 @@ static struct kexec_file_ops *kexec_file | |
83 | static void free_transition_pgtable(struct kimage *image) | |
84 | { | |
85 | free_page((unsigned long)image->arch.pud); | |
86 | + image->arch.pud = NULL; | |
87 | free_page((unsigned long)image->arch.pmd); | |
88 | + image->arch.pmd = NULL; | |
89 | free_page((unsigned long)image->arch.pte); | |
90 | + image->arch.pte = NULL; | |
91 | } | |
92 | ||
93 | static int init_transition_pgtable(struct kimage *image, pgd_t *pgd) | |
94 | @@ -79,7 +82,6 @@ static int init_transition_pgtable(struc | |
95 | set_pte(pte, pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL_EXEC)); | |
96 | return 0; | |
97 | err: | |
98 | - free_transition_pgtable(image); | |
99 | return result; | |
100 | } | |
101 |