Thread (35 messages) flat view 35 messages, 8 authors, 2021-02-05

Re: [PATCH] x86: efi: avoid BUILD_BUG_ON() for non-constant p4d_index

From: Ard Biesheuvel <ardb@kernel.org>
Date: 2021-01-16 17:10:36
Also in: lkml, platform-driver-x86

On Fri, 15 Jan 2021 at 21:27, Arvind Sankar [off-list ref] wrote:
On Fri, Jan 15, 2021 at 02:07:51PM -0500, Arvind Sankar wrote:
quoted
On Thu, Jan 07, 2021 at 11:34:15PM +0100, Arnd Bergmann wrote:
quoted
From: Arnd Bergmann <arnd@arndb.de>

When 5-level page tables are enabled, clang triggers a BUILD_BUG_ON():

x86_64-linux-ld: arch/x86/platform/efi/efi_64.o: in function `efi_sync_low_kernel_mappings':
efi_64.c:(.text+0x22c): undefined reference to `__compiletime_assert_354'

Use the same method as in commit c65e774fb3f6 ("x86/mm: Make PGDIR_SHIFT
and PTRS_PER_P4D variable") and change it to MAYBE_BUILD_BUG_ON(),
so it only triggers for constant input.

Link: https://github.com/ClangBuiltLinux/linux/issues/256
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 arch/x86/platform/efi/efi_64.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
index e1e8d4e3a213..62bb1616b4a5 100644
--- a/arch/x86/platform/efi/efi_64.c
+++ b/arch/x86/platform/efi/efi_64.c
@@ -137,8 +137,8 @@ void efi_sync_low_kernel_mappings(void)
     * As with PGDs, we share all P4D entries apart from the one entry
     * that covers the EFI runtime mapping space.
     */
-   BUILD_BUG_ON(p4d_index(EFI_VA_END) != p4d_index(MODULES_END));
-   BUILD_BUG_ON((EFI_VA_START & P4D_MASK) != (EFI_VA_END & P4D_MASK));
+   MAYBE_BUILD_BUG_ON(p4d_index(EFI_VA_END) != p4d_index(MODULES_END));
+   MAYBE_BUILD_BUG_ON((EFI_VA_START & P4D_MASK) != (EFI_VA_END & P4D_MASK));

    pgd_efi = efi_pgd + pgd_index(EFI_VA_END);
    pgd_k = pgd_offset_k(EFI_VA_END);
--
2.29.2
I think this needs more explanation as to why clang is triggering this.
The issue mentions clang not inline p4d_index(), and I guess not
performing inter-procedural analysis either?

For the second assertion there, everything is always constant AFAICT:
EFI_VA_START, EFI_VA_END and P4D_MASK are all constants regardless of
CONFIG_5LEVEL.

For the first assertion, it isn't technically constant, but if
p4d_index() gets inlined, the compiler should be able to see that the
two are always equal, even though ptrs_per_p4d is not constant:
      EFI_VA_END >> 39 == MODULES_END >> 39
so the masking with ptrs_per_p4d-1 doesn't matter for the comparison.

As a matter of fact, it seems like the four assertions could be combined
into:
      BUILD_BUG_ON((EFI_VA_END & P4D_MASK) != (MODULES_END & P4D_MASK));
      BUILD_BUG_ON((EFI_VA_START & P4D_MASK) != (EFI_VA_END & P4D_MASK));
instead of separately asserting they're the same PGD entry and the same
P4D entry.

Thanks.
I actually don't quite get the MODULES_END check -- Ard, do you know
what that's for?
Maybe Boris remembers? He wrote the original code for the 'new' EFI
page table layout.

What we really should be checking is that EFI_VA_START is in the top-most
PGD entry and the top-most P4D entry, since we only copy PGD/P4D entries
before EFI_VA_END, but not after EFI_VA_START. So the checks should
really be
        BUILD_BUG_ON(((EFI_VA_START - 1) & P4D_MASK) != (-1ul & P4D_MASK));
        BUILD_BUG_ON(((EFI_VA_START - 1) & P4D_MASK) != (EFI_VA_END & P4D_MASK));
imo. I guess that's what using MODULES_END is effectively checking, but
it would be clearer to check it directly.
This obviously needs a comment, but checking that everything lives in
the top 512 GB of the kernel VA space seems sufficient to me,
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help