Message ID | 1504900337-21269-1-git-send-email-marcelo.cerri@canonical.com |
---|---|
State | New |
Headers | show |
Series | [azure] x86/KASLR: Fix kexec kernel boot crash when KASLR randomization fails | expand |
On Fri, Sep 08, 2017 at 04:52:17PM -0300, Marcelo Henrique Cerri wrote: > From: Baoquan He <bhe@redhat.com> > > BugLink: http://bugs.launchpad.net/bugs/1702515 BugLink: http://bugs.launchpad.net/bugs/1712867 > > Dave found that a kdump kernel with KASLR enabled will reset to the BIOS > immediately if physical randomization failed to find a new position for > the kernel. A kernel with the 'nokaslr' option works in this case. > > The reason is that KASLR will install a new page table for the identity > mapping, while it missed building it for the original kernel location > if KASLR physical randomization fails. > > This only happens in the kexec/kdump kernel, because the identity mapping > has been built for kexec/kdump in the 1st kernel for the whole memory by > calling init_pgtable(). Here if physical randomizaiton fails, it won't build > the identity mapping for the original area of the kernel but change to a > new page table '_pgtable'. Then the kernel will triple fault immediately > caused by no identity mappings. > > The normal kernel won't see this bug, because it comes here via startup_32() > and CR3 will be set to _pgtable already. In startup_32() the identity > mapping is built for the 0~4G area. In KASLR we just append to the existing > area instead of entirely overwriting it for on-demand identity mapping > building. So the identity mapping for the original area of kernel is still > there. > > To fix it we just switch to the new identity mapping page table when physical > KASLR succeeds. Otherwise we keep the old page table unchanged just like > "nokaslr" does. > > Signed-off-by: Baoquan He <bhe@redhat.com> > Signed-off-by: Dave Young <dyoung@redhat.com> > Acked-by: Kees Cook <keescook@chromium.org> > Cc: Borislav Petkov <bp@suse.de> > Cc: Dave Jiang <dave.jiang@intel.com> > Cc: Linus Torvalds <torvalds@linux-foundation.org> > Cc: Peter Zijlstra <peterz@infradead.org> > Cc: Thomas Garnier <thgarnie@google.com> > Cc: Thomas Gleixner <tglx@linutronix.de> > Cc: Yinghai Lu <yinghai@kernel.org> > Link: http://lkml.kernel.org/r/1493278940-5885-1-git-send-email-bhe@redhat.com > Signed-off-by: Ingo Molnar <mingo@kernel.org> > (cherry picked from commit da63b6b20077469bd6bd96e07991ce145fc4fbc4) > Signed-off-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com> > --- > arch/x86/boot/compressed/kaslr.c | 11 +++++++++-- > 1 file changed, 9 insertions(+), 2 deletions(-) > > diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c > index 8fad8a64d670..1199a74f867c 100644 > --- a/arch/x86/boot/compressed/kaslr.c > +++ b/arch/x86/boot/compressed/kaslr.c > @@ -594,10 +594,17 @@ void choose_random_location(unsigned long input, > add_identity_map(random_addr, output_size); > *output = random_addr; > } > + > + /* > + * This loads the identity mapping page table. > + * This should only be done if a new physical address > + * is found for the kernel, otherwise we should keep > + * the old page table to make it be like the "nokaslr" > + * case. > + */ > + finalize_identity_maps(); > } > > - /* This actually loads the identity pagetable on x86_64. */ > - finalize_identity_maps(); > > /* Pick random virtual address starting from LOAD_PHYSICAL_ADDR. */ > if (IS_ENABLED(CONFIG_X86_64)) > -- > 2.7.4 >
On 09/09/17 02:44, Marcelo Henrique Cerri wrote: > On Fri, Sep 08, 2017 at 04:52:17PM -0300, Marcelo Henrique Cerri wrote: >> From: Baoquan He <bhe@redhat.com> >> >> BugLink: http://bugs.launchpad.net/bugs/1702515 > > BugLink: http://bugs.launchpad.net/bugs/1712867 > >> >> Dave found that a kdump kernel with KASLR enabled will reset to the BIOS >> immediately if physical randomization failed to find a new position for >> the kernel. A kernel with the 'nokaslr' option works in this case. >> >> The reason is that KASLR will install a new page table for the identity >> mapping, while it missed building it for the original kernel location >> if KASLR physical randomization fails. >> >> This only happens in the kexec/kdump kernel, because the identity mapping >> has been built for kexec/kdump in the 1st kernel for the whole memory by >> calling init_pgtable(). Here if physical randomizaiton fails, it won't build >> the identity mapping for the original area of the kernel but change to a >> new page table '_pgtable'. Then the kernel will triple fault immediately >> caused by no identity mappings. >> >> The normal kernel won't see this bug, because it comes here via startup_32() >> and CR3 will be set to _pgtable already. In startup_32() the identity >> mapping is built for the 0~4G area. In KASLR we just append to the existing >> area instead of entirely overwriting it for on-demand identity mapping >> building. So the identity mapping for the original area of kernel is still >> there. >> >> To fix it we just switch to the new identity mapping page table when physical >> KASLR succeeds. Otherwise we keep the old page table unchanged just like >> "nokaslr" does. >> >> Signed-off-by: Baoquan He <bhe@redhat.com> >> Signed-off-by: Dave Young <dyoung@redhat.com> >> Acked-by: Kees Cook <keescook@chromium.org> >> Cc: Borislav Petkov <bp@suse.de> >> Cc: Dave Jiang <dave.jiang@intel.com> >> Cc: Linus Torvalds <torvalds@linux-foundation.org> >> Cc: Peter Zijlstra <peterz@infradead.org> >> Cc: Thomas Garnier <thgarnie@google.com> >> Cc: Thomas Gleixner <tglx@linutronix.de> >> Cc: Yinghai Lu <yinghai@kernel.org> >> Link: http://lkml.kernel.org/r/1493278940-5885-1-git-send-email-bhe@redhat.com >> Signed-off-by: Ingo Molnar <mingo@kernel.org> >> (cherry picked from commit da63b6b20077469bd6bd96e07991ce145fc4fbc4) >> Signed-off-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com> >> --- >> arch/x86/boot/compressed/kaslr.c | 11 +++++++++-- >> 1 file changed, 9 insertions(+), 2 deletions(-) >> >> diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c >> index 8fad8a64d670..1199a74f867c 100644 >> --- a/arch/x86/boot/compressed/kaslr.c >> +++ b/arch/x86/boot/compressed/kaslr.c >> @@ -594,10 +594,17 @@ void choose_random_location(unsigned long input, >> add_identity_map(random_addr, output_size); >> *output = random_addr; >> } >> + >> + /* >> + * This loads the identity mapping page table. >> + * This should only be done if a new physical address >> + * is found for the kernel, otherwise we should keep >> + * the old page table to make it be like the "nokaslr" >> + * case. >> + */ >> + finalize_identity_maps(); >> } >> >> - /* This actually loads the identity pagetable on x86_64. */ >> - finalize_identity_maps(); >> >> /* Pick random virtual address starting from LOAD_PHYSICAL_ADDR. */ >> if (IS_ENABLED(CONFIG_X86_64)) >> -- >> 2.7.4 >> >> >> Has positive test results. Just needs the buglink to be corrected before applying. Acked-by: Colin Ian King <colin.king@canonical.com>
Applied with the correct BugLink.
Acked-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com>
diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c index 8fad8a64d670..1199a74f867c 100644 --- a/arch/x86/boot/compressed/kaslr.c +++ b/arch/x86/boot/compressed/kaslr.c @@ -594,10 +594,17 @@ void choose_random_location(unsigned long input, add_identity_map(random_addr, output_size); *output = random_addr; } + + /* + * This loads the identity mapping page table. + * This should only be done if a new physical address + * is found for the kernel, otherwise we should keep + * the old page table to make it be like the "nokaslr" + * case. + */ + finalize_identity_maps(); } - /* This actually loads the identity pagetable on x86_64. */ - finalize_identity_maps(); /* Pick random virtual address starting from LOAD_PHYSICAL_ADDR. */ if (IS_ENABLED(CONFIG_X86_64))