From patchwork Tue Jan 23 14:53:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 13527539 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 9F0BCC47258 for ; Tue, 23 Jan 2024 14:55:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:Message-ID: References:Mime-Version:In-Reply-To:Date:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=xaXeomi/WX6hRyTOAwTUjJJWjFGOpsvJnVXVBqxHqhU=; b=ep1b8tQjRKgp30cCF/ZHWqo6/x 1SJM5X4t8WOQsviZbmXFoBhikp/74+ieVIq4JD1MdgP3ge19TzAvr3BWH6FGh6qcoOImyGblCms2w COVDJ/ahFvZxklA22imAK++/dYQGndpnTFe5wvZBO/TO1sNfachyOpN1oI/Ct2tFoMcsak4x2YoT+ 4ofu6Uz41+pYuTpxQo5XOsFZ/zpFSWJuenyEUM8T6l3irlWKmNoKFyVKif1XYCur5RU0KvuZ2SiDz xWFJScl9LB0nYeYyci1D87gcbyCjsOkENv/RopvUCFziA5qYMBNSvCbB/LARPLLLZ4OEDG8ARXejF 8yCC/pfA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1rSIAv-00GtnO-2o; Tue, 23 Jan 2024 14:54:53 +0000 Received: from mail-yw1-x1149.google.com ([2607:f8b0:4864:20::1149]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1rSIAj-00GtgT-1A for linux-arm-kernel@lists.infradead.org; Tue, 23 Jan 2024 14:54:43 +0000 Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-5fc6463b0edso72293587b3.0 for ; Tue, 23 Jan 2024 06:54:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1706021680; x=1706626480; darn=lists.infradead.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=uHapg+q84iY+9DVDrmY/Rzm5S7AajVfJPXOm3N8uiK0=; b=lP8ZahdiA7AZz7DOf9kIJnuGCkpG+dSzmQVlMA3G4h4tU7YkPDavv02NGcEhyYa6GL GdbGXOsi1MEfNOpEzotpX7Jpq9FemYUVFygi/LEjawk/WW9pKtWuMg4d2yM6uXQxkd1Q Ox4bb+01Ow4SWv+cUKMkfHAwEjQaZXVRinJu4Fm+bh+VpMywvyUtA3hqeL5x8SK4dDB3 DDYhwlQeiA185ayeakS51dwpU0ZBQwaJiHzleeYTAd3yh7OEnSqsvYKzncUmOVDfYF++ qV13NXhtS8rKhQ6BoOso4fuPGxPGOD5Oum9a63lQHqc7+AoNg3COe9t0Ze3MCsfv8O4U 70Yw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1706021680; x=1706626480; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=uHapg+q84iY+9DVDrmY/Rzm5S7AajVfJPXOm3N8uiK0=; b=rn5cVMhgQA4ArCmXR+K2JzUCrTKrfuK3mx/Cvr/rN65LBV1837geRMc67lNYpSCal3 xiS3U5I68dlr6rBZZ1GwW9ka9D8Zp/1++fI5M8ZLbXYHlpa7/ypsIQidFcEm32ikOtz7 H9Tth8BXFA1mIoEMdvcAWcOctwyTXvfZIdT0AfUtPzYIKdfTmua7fJ/0zL2YHOzXs9fS Udw3dmH3R7iUXYg6TTGPp31zhGhokXyKCm2QtA2wk+1sKPTv0gvS5QtW/c+gf/S3vjcN dageHJXY6HYMXW3t6ETrtZ+NYGRD1zI4I0Fx82GFXeJY5QPHguLOfFeXdBXd6703CS+W z1qg== X-Gm-Message-State: AOJu0Yy1eCeiIuV56uQTD+dzWSAyzjQxt9D6Uu8nUk2fiZe7zCyDewPn cEQe3+i3K5M9D5n9kuZ6qod8QZT5EO/1JdOqkt336CYGvVA3OwZS6g+rjd46zDfQ3For1KlNOoY znRFztxNgFBnTKJlyFa4a7ebwNAWsIhH7w0g0DMp6aq68AZVJ/ux9l5iuFxt8l+wL1dKM5EktjP qUMFTRM3SsMjr/C/k9FIx7OK/mHqqFqgg1D6iF7Ccu X-Google-Smtp-Source: AGHT+IFlm2oI/U4DYho9OPIhPb71qMfc98Ar1kdveeP7X/hjNivrXRQsFZveDGjggZAcU9+w8/93fxkP X-Received: from palermo.c.googlers.com ([fda3:e722:ac3:cc00:28:9cb1:c0a8:118a]) (user=ardb job=sendgmr) by 2002:a25:ce92:0:b0:dc2:65e2:58f3 with SMTP id x140-20020a25ce92000000b00dc265e258f3mr350474ybe.7.1706021680150; Tue, 23 Jan 2024 06:54:40 -0800 (PST) Date: Tue, 23 Jan 2024 15:53:07 +0100 In-Reply-To: <20240123145258.1462979-52-ardb+git@google.com> Mime-Version: 1.0 References: <20240123145258.1462979-52-ardb+git@google.com> X-Developer-Key: i=ardb@kernel.org; a=openpgp; fpr=F43D03328115A198C90016883D200E9CA6329909 X-Developer-Signature: v=1; a=openpgp-sha256; l=6618; i=ardb@kernel.org; h=from:subject; bh=IdH78ZaX1BFe8iHl3LhquM/a8D/A7UQlQ1jqPN1t198=; b=owGbwMvMwCFmkMcZplerG8N4Wi2JIXX9pcuyH++tO/b38gbRPWf5Hz3z/6b16fS8pZUH+D/7O 105vXbnt45SFgYxDgZZMUUWgdl/3+08PVGq1nmWLMwcViaQIQxcnAIwkYXvGf6HmLXZ86v0ztYM bF5wZ/7x5pI+V8ZLji1zfupKpHBO6JzO8L+ac5vC1qX3T1YzBJ5x+m/Il8cpz/ax78Xf8nsz0xQ 2qfECAA== X-Mailer: git-send-email 2.43.0.429.g432eaa2c6b-goog Message-ID: <20240123145258.1462979-60-ardb+git@google.com> Subject: [PATCH v7 08/50] arm64: kernel: Manage absolute relocations in code built under pi/ From: Ard Biesheuvel To: linux-arm-kernel@lists.infradead.org Cc: Ard Biesheuvel , Catalin Marinas , Will Deacon , Marc Zyngier , Mark Rutland , Ryan Roberts , Anshuman Khandual , Kees Cook X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20240123_065441_399490_4A407EA5 X-CRM114-Status: GOOD ( 24.16 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Ard Biesheuvel The mini C runtime runs before relocations are processed, and so it cannot rely on statically initialized pointer variables. Add a check to ensure that such code does not get introduced by accident, by going over the relocations in each object, identifying the ones that operate on data sections that are part of the executable image, and raising an error if any relocations of type R_AARCH64_ABS64 exist. Note that such relocations are permitted in other places (e.g., debug sections) and will never occur in compiler generated code sections when using the small code model, so only check sections that have SHF_ALLOC set and SHF_EXECINSTR cleared. To accommodate cases where statically initialized symbol references are unavoidable, introduce a special case for ELF input data sections that have ".rodata.prel64" in their names, and in these cases, instead of rejecting any encountered ABS64 relocations, convert them into PREL64 relocations, which don't require any runtime fixups. Note that the code in question must still be modified to deal with this, as it needs to convert the 64-bit signed offsets into absolute addresses before use. Signed-off-by: Ard Biesheuvel --- arch/arm64/kernel/pi/Makefile | 9 +- arch/arm64/kernel/pi/pi.h | 18 +++ arch/arm64/kernel/pi/relacheck.c | 130 ++++++++++++++++++++ 3 files changed, 155 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/pi/Makefile b/arch/arm64/kernel/pi/Makefile index c844a0546d7f..bc32a431fe35 100644 --- a/arch/arm64/kernel/pi/Makefile +++ b/arch/arm64/kernel/pi/Makefile @@ -22,11 +22,16 @@ KCSAN_SANITIZE := n UBSAN_SANITIZE := n KCOV_INSTRUMENT := n +hostprogs := relacheck + +quiet_cmd_piobjcopy = $(quiet_cmd_objcopy) + cmd_piobjcopy = $(cmd_objcopy) && $(obj)/relacheck $(@) $(<) + $(obj)/%.pi.o: OBJCOPYFLAGS := --prefix-symbols=__pi_ \ --remove-section=.note.gnu.property \ --prefix-alloc-sections=.init -$(obj)/%.pi.o: $(obj)/%.o FORCE - $(call if_changed,objcopy) +$(obj)/%.pi.o: $(obj)/%.o $(obj)/relacheck FORCE + $(call if_changed,piobjcopy) $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE $(call if_changed_rule,cc_o_c) diff --git a/arch/arm64/kernel/pi/pi.h b/arch/arm64/kernel/pi/pi.h new file mode 100644 index 000000000000..7c2d9bbf0ff9 --- /dev/null +++ b/arch/arm64/kernel/pi/pi.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2023 Google LLC +// Author: Ard Biesheuvel + +#define __prel64_initconst __section(".init.rodata.prel64") + +#define PREL64(type, name) union { type *name; prel64_t name ## _prel; } + +#define prel64_pointer(__d) (typeof(__d))prel64_to_pointer(&__d##_prel) + +typedef volatile signed long prel64_t; + +static inline void *prel64_to_pointer(const prel64_t *offset) +{ + if (!*offset) + return NULL; + return (void *)offset + *offset; +} diff --git a/arch/arm64/kernel/pi/relacheck.c b/arch/arm64/kernel/pi/relacheck.c new file mode 100644 index 000000000000..b0cd4d0d275b --- /dev/null +++ b/arch/arm64/kernel/pi/relacheck.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2023 - Google LLC + * Author: Ard Biesheuvel + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define HOST_ORDER ELFDATA2LSB +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define HOST_ORDER ELFDATA2MSB +#endif + +static Elf64_Ehdr *ehdr; +static Elf64_Shdr *shdr; +static const char *strtab; +static bool swap; + +static uint64_t swab_elfxword(uint64_t val) +{ + return swap ? __builtin_bswap64(val) : val; +} + +static uint32_t swab_elfword(uint32_t val) +{ + return swap ? __builtin_bswap32(val) : val; +} + +static uint16_t swab_elfhword(uint16_t val) +{ + return swap ? __builtin_bswap16(val) : val; +} + +int main(int argc, char *argv[]) +{ + struct stat stat; + int fd, ret; + + if (argc < 3) { + fprintf(stderr, "file arguments missing\n"); + exit(EXIT_FAILURE); + } + + fd = open(argv[1], O_RDWR); + if (fd < 0) { + fprintf(stderr, "failed to open %s\n", argv[1]); + exit(EXIT_FAILURE); + } + + ret = fstat(fd, &stat); + if (ret < 0) { + fprintf(stderr, "failed to stat() %s\n", argv[1]); + exit(EXIT_FAILURE); + } + + ehdr = mmap(0, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ehdr == MAP_FAILED) { + fprintf(stderr, "failed to mmap() %s\n", argv[1]); + exit(EXIT_FAILURE); + } + + swap = ehdr->e_ident[EI_DATA] != HOST_ORDER; + shdr = (void *)ehdr + swab_elfxword(ehdr->e_shoff); + strtab = (void *)ehdr + + swab_elfxword(shdr[swab_elfhword(ehdr->e_shstrndx)].sh_offset); + + for (int i = 0; i < swab_elfhword(ehdr->e_shnum); i++) { + unsigned long info, flags; + bool prel64 = false; + Elf64_Rela *rela; + int numrela; + + if (swab_elfword(shdr[i].sh_type) != SHT_RELA) + continue; + + /* only consider RELA sections operating on data */ + info = swab_elfword(shdr[i].sh_info); + flags = swab_elfxword(shdr[info].sh_flags); + if ((flags & (SHF_ALLOC | SHF_EXECINSTR)) != SHF_ALLOC) + continue; + + /* + * We generally don't permit ABS64 relocations in the code that + * runs before relocation processing occurs. If statically + * initialized absolute symbol references are unavoidable, they + * may be emitted into a *.rodata.prel64 section and they will + * be converted to place-relative 64-bit references. This + * requires special handling in the referring code. + */ + if (strstr(strtab + swab_elfword(shdr[info].sh_name), + ".rodata.prel64")) { + prel64 = true; + } + + rela = (void *)ehdr + swab_elfxword(shdr[i].sh_offset); + numrela = swab_elfxword(shdr[i].sh_size) / sizeof(*rela); + + for (int j = 0; j < numrela; j++) { + uint64_t info = swab_elfxword(rela[j].r_info); + + if (ELF64_R_TYPE(info) != R_AARCH64_ABS64) + continue; + + if (prel64) { + /* convert ABS64 into PREL64 */ + info ^= R_AARCH64_ABS64 ^ R_AARCH64_PREL64; + rela[j].r_info = swab_elfxword(info); + } else { + fprintf(stderr, + "Unexpected absolute relocations detected in %s\n", + argv[2]); + close(fd); + unlink(argv[1]); + exit(EXIT_FAILURE); + } + } + } + close(fd); + return 0; +}