lkml.org 
[lkml]   [2017]   [Apr]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.10 051/110] s390/decompressor: fix initrd corruption caused by bss clear
    Date
    4.10-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Marcelo Henrique Cerri <marcelo.cerri@canonical.com>

    commit d82c0d12c92705ef468683c9b7a8298dd61ed191 upstream.

    Reorder the operations in decompress_kernel() to ensure initrd is moved
    to a safe location before the bss section is zeroed.

    During decompression bss can overlap with the initrd and this can
    corrupt the initrd contents depending on the size of the compressed
    kernel (which affects where the initrd is placed by the bootloader) and
    the size of the bss section of the decompressor.

    Also use the correct initrd size when checking for overlaps with
    parmblock.

    Fixes: 06c0dd72aea3 ([S390] fix boot failures with compressed kernels)
    Reviewed-by: Joy Latten <joy.latten@canonical.com>
    Reviewed-by: Vineetha HariPai <vineetha.hari.pai@canonical.com>
    Signed-off-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    arch/s390/boot/compressed/misc.c | 35 +++++++++++++++++++----------------
    1 file changed, 19 insertions(+), 16 deletions(-)

    --- a/arch/s390/boot/compressed/misc.c
    +++ b/arch/s390/boot/compressed/misc.c
    @@ -141,31 +141,34 @@ static void check_ipl_parmblock(void *st

    unsigned long decompress_kernel(void)
    {
    - unsigned long output_addr;
    - unsigned char *output;
    + void *output, *kernel_end;

    - output_addr = ((unsigned long) &_end + HEAP_SIZE + 4095UL) & -4096UL;
    - check_ipl_parmblock((void *) 0, output_addr + SZ__bss_start);
    - memset(&_bss, 0, &_ebss - &_bss);
    - free_mem_ptr = (unsigned long)&_end;
    - free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
    - output = (unsigned char *) output_addr;
    + output = (void *) ALIGN((unsigned long) &_end + HEAP_SIZE, PAGE_SIZE);
    + kernel_end = output + SZ__bss_start;
    + check_ipl_parmblock((void *) 0, (unsigned long) kernel_end);

    #ifdef CONFIG_BLK_DEV_INITRD
    /*
    * Move the initrd right behind the end of the decompressed
    - * kernel image.
    + * kernel image. This also prevents initrd corruption caused by
    + * bss clearing since kernel_end will always be located behind the
    + * current bss section..
    */
    - if (INITRD_START && INITRD_SIZE &&
    - INITRD_START < (unsigned long) output + SZ__bss_start) {
    - check_ipl_parmblock(output + SZ__bss_start,
    - INITRD_START + INITRD_SIZE);
    - memmove(output + SZ__bss_start,
    - (void *) INITRD_START, INITRD_SIZE);
    - INITRD_START = (unsigned long) output + SZ__bss_start;
    + if (INITRD_START && INITRD_SIZE && kernel_end > (void *) INITRD_START) {
    + check_ipl_parmblock(kernel_end, INITRD_SIZE);
    + memmove(kernel_end, (void *) INITRD_START, INITRD_SIZE);
    + INITRD_START = (unsigned long) kernel_end;
    }
    #endif

    + /*
    + * Clear bss section. free_mem_ptr and free_mem_end_ptr need to be
    + * initialized afterwards since they reside in bss.
    + */
    + memset(&_bss, 0, &_ebss - &_bss);
    + free_mem_ptr = (unsigned long) &_end;
    + free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
    +
    puts("Uncompressing Linux... ");
    __decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error);
    puts("Ok, booting the kernel.\n");

    \
     
     \ /
      Last update: 2017-04-10 19:10    [W:4.275 / U:0.028 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site