• Borislav Petkov's avatar
    x86: Fix early boot crash on gcc-10, third try · a9a3ed1e
    Borislav Petkov authored
    ... or the odyssey of trying to disable the stack protector for the
    function which generates the stack canary value.
    
    The whole story started with Sergei reporting a boot crash with a kernel
    built with gcc-10:
    
      Kernel panic — not syncing: stack-protector: Kernel stack is corrupted in: start_secondary
      CPU: 1 PID: 0 Comm: swapper/1 Not tainted 5.6.0-rc5—00235—gfffb08b3 #139
      Hardware name: Gigabyte Technology Co., Ltd. To be filled by O.E.M./H77M—D3H, BIOS F12 11/14/2013
      Call Trace:
        dump_stack
        panic
        ? start_secondary
        __stack_chk_fail
        start_secondary
        secondary_startup_64
      -—-[ end Kernel panic — not syncing: stack—protector: Kernel stack is corrupted in: start_secondary
    
    This happens because gcc-10 tail-call optimizes the last function call
    in start_secondary() - cpu_startup_entry() - and thus emits a stack
    canary check which fails because the canary value changes after the
    boot_init_stack_canary() call.
    
    To fix that, the initial attempt was to mark the one function which
    generates the stack canary with:
    
      __attribute__((optimize("-fno-stack-protector"))) ... start_secondary(void *unused)
    
    however, using the optimize attribute doesn't work cumulatively
    as the attribute does not add to but rather replaces previously
    supplied optimization options - roughly all -fxxx options.
    
    The key one among them being -fno-omit-frame-pointer and thus leading to
    not present frame pointer - frame pointer which the kernel needs.
    
    The next attempt to prevent compilers from tail-call optimizing
    the last function call cpu_startup_entry(), shy of carving out
    start_secondary() into a separate compilation unit and building it with
    -fno-stack-protector, was to add an empty asm("").
    
    This current solution was short and sweet, and reportedly, is supported
    by both compilers but we didn't get very far this time: future (LTO?)
    optimization passes could potentially eliminate this, which leads us
    to the third attempt: having an actual memory barrier there which the
    compiler cannot ignore or move around etc.
    
    That should hold for a long time, but hey we said that about the other
    two solutions too so...
    Reported-by: default avatarSergei Trofimovich <slyfox@gentoo.org>
    Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
    Tested-by: default avatarKalle Valo <kvalo@codeaurora.org>
    Cc: <stable@vger.kernel.org>
    Link: https://lkml.kernel.org/r/20200314164451.346497-1-slyfox@gentoo.org
    a9a3ed1e
main.c 36.5 KB