Received: by 2002:ab2:6309:0:b0:1fb:d597:ff75 with SMTP id s9csp773468lqt; Thu, 6 Jun 2024 19:41:35 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCUQtNIVif3/P11D4caZZEndVcvwDKbQiiLmt+po+fuyL4ZHMRgF6H2yARnbBtzUh7dI8OMrwwZ5Eoqn76eBGLC7bWqV5Gu7R+bI4zNyJg== X-Google-Smtp-Source: AGHT+IFhcU8Asx9gSHyoJLf9u3NoH5byFkfsEGw2iRoSHaYMf8youeLSUGPr9jeSCZt4U4N5HeeG X-Received: by 2002:ac2:5a4a:0:b0:51d:9921:20f7 with SMTP id 2adb3069b0e04-52bb9f91d77mr738118e87.40.1717728095101; Thu, 06 Jun 2024 19:41:35 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1717728095; cv=pass; d=google.com; s=arc-20160816; b=fCbhSpgvOfEUTpX7/RWRNaEc9nkZACTJKe7hCpSazUst1auanROI8SCi+jnLbOU2Tf 9ONQ+WJouxO/KbEYWGdmwwFh0obz0hJCjCa02ZOJJy+JIxEJkLRNwuYxFpbUlq2QRO6v z4vpiZAZC4Ubzcv6qHBXqyN/ILBXkDwU88aevXxuU6/59j0fgNoCNVU7LpUpYGCpBaq0 Hp9tlV4LMbZGjfTeKrPL0yXDD4mkvpzqi3oRRLttXfdutpKcTLytnw0qrQeo494/tirA EDiyYQXVOJDCCUAc9KWiepgzqf8B3GSUtBG8/OfCaaMAhW2mtWXQRcrGjHMA4Ck5N/aX 0RRg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=in-reply-to:content-disposition:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:message-id:subject:cc :to:from:date:dkim-signature; bh=MnG/KOCYJj1nDTQjkDARDGmTge5J2n8OK1U6FH0keB4=; fh=1H1z9aAjrk0wwJJunQ8+UGw/Y6Iv9rTVBDC0sKXmJF4=; b=ImYJzOLHQUH9cwm3UeV6Zc6yhGE1tdVbXlIf614I/9V1hlLWJfX6ey4bjr4Cq8iVvN O/SU0pPd3LuuMfU0eCXybhV3VBaklr4+u/PDuCFh2nk1G+hX5JpG+ne1CHEDMFnq8J7p QowO7SAv+FArpvxZmzaFF9lAyUMcoLbsHFWrcoy5p1+0FCpgmbIG0OVZpNyU+5xzcrsP DZk6FkWywBoaVMJ+3mrd+4AVQrSpw1ygqPthWn5vj5ZmTucGM6tCmqUhxnViLddUAC7P tBNiFWt7y9ESQ+eYK9OoEgrLYuV+S18tY8Eqoe5IZmxLZ9/1Adyqodbytzrt4Ruf//dE z/fA==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=O8EN6HI4; arc=pass (i=1 dkim=pass dkdomain=kernel.org); spf=pass (google.com: domain of linux-kernel+bounces-205257-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-205257-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [2604:1380:4601:e00::3]) by mx.google.com with ESMTPS id 4fb4d7f45d1cf-57aae26364asi1337692a12.546.2024.06.06.19.41.35 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Jun 2024 19:41:35 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-205257-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) client-ip=2604:1380:4601:e00::3; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=O8EN6HI4; arc=pass (i=1 dkim=pass dkdomain=kernel.org); spf=pass (google.com: domain of linux-kernel+bounces-205257-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-205257-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id 9FC0F1F24C4E for ; Fri, 7 Jun 2024 02:41:34 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8355115ACB; Fri, 7 Jun 2024 02:41:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="O8EN6HI4" Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6D4FE12E47 for ; Fri, 7 Jun 2024 02:41:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717728087; cv=none; b=sccI9OnMH+auQqiD/fM1MGQZLoTiYIVafeFjOoXwA/+CW2DD8fzn+akjkUhGnyejTit4hVOs5ND9hIM9wAx74Cl9tgDFk0qsw+FWyZLcLhRByzp948sXas7iHp3CM5eDh5evrb7DgbClRcp6fEozW5TWsPFVo76tihV13bfBT/w= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717728087; c=relaxed/simple; bh=us34JFVYbA5mG82uLJk2U+J0l+KMvoo6AlvtT/zfTlA=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=JZ89ya9+R6xdbMbzqmY3a1Q/+zJqYfGn+BVd0qNVZrT47Lt8MGs6b0TF94scQ61V1RNQHwilV0vW2DTiaoSQZeWYghikPklGYHfRCmlzXLvFH5TcI1otg4xP+NaKkVC53FIDj48k+NXQjkxuk22E0AqjUeDPHYhJjoKyCjSxCGg= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=O8EN6HI4; arc=none smtp.client-ip=10.30.226.201 Received: by smtp.kernel.org (Postfix) with ESMTPSA id C4CBCC2BD10; Fri, 7 Jun 2024 02:41:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1717728086; bh=us34JFVYbA5mG82uLJk2U+J0l+KMvoo6AlvtT/zfTlA=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=O8EN6HI4OjDEsL0zKsAdzsKpDF6u4LAwIEODtZXF4E3a1aVf4TMz7MatOoeXlp1XR tSCDMHzs5O/v+kzryZ59yaUWHsPpuZMzgUtTnd7BdUbAPj3EXRkZCTlzIPvaKu390x pieHlGvZbibapwUgTIv4COwp7uzn9N+5uEfa6+1wFZPCfGyf95D4fPtrrXrT4sB2yo 2YpjOQkSd6sIpVe0WQT6zH8Nmfg1BoJAinJWqn/Bfa9jMJ0pDvXSV4zjtKq02DQXUK 3gmZr9SuTFIqx/17Y3gcMZDmbXQCzrhmbBnQehnLgEal73Fn3tkYoMoWG0etRWqCrX W6gLP8Gj8249Q== Date: Thu, 6 Jun 2024 19:41:25 -0700 From: Josh Poimboeuf To: Linus Torvalds Cc: Peter Zijlstra , Linux Kernel Mailing List Subject: Re: objtool query: section start/end symbols? Message-ID: <20240607024125.jsumfrbgoz5vz3si@treble> References: <20240606194525.cdnnidxurejsjtx4@treble> <20240606221856.g3iboxfkkgzp6sd3@treble> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: On Thu, Jun 06, 2024 at 03:54:34PM -0700, Linus Torvalds wrote: > On Thu, 6 Jun 2024 at 15:19, Josh Poimboeuf wrote: > > So while I'm not yet necessarily conceding that objtool is really needed > > here, I could work up a quick objtool patch. It would just be x86-only, > > is that ok for the time being? > > Absolutely. This adds a new objtool "--bounds" action which creates a __sec__{start,end} symbol for every section. The only testing I've done has been staring cross-eyed at the readelf output on a defconfig kernel. If you have CONFIG_X86_KERNEL_IBT -- which causes objtool to run on vmlinux.o -- you can enable bounds symbol creation by adding OBJTOOL_ARGS="--bounds" to your make cmdline: make -j$(nproc) -s OBJTOOL_ARGS="--bounds" Otherwise it would need to be manually added with objtool --bounds --link vmlinux.o diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 5e21cfb7661d..e1a86981fd96 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -68,6 +68,7 @@ static int parse_hacks(const struct option *opt, const char *str, int unset) static const struct option check_options[] = { OPT_GROUP("Actions:"), OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label,noinstr,skylake", "patch toolchain bugs/limitations", parse_hacks), + OPT_BOOLEAN('b', "bounds", &opts.bounds, "generate section start/end bounds symbols"), OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"), OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"), OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"), @@ -131,7 +132,8 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[]) static bool opts_valid(void) { - if (opts.hack_jump_label || + if (opts.bounds || + opts.hack_jump_label || opts.hack_noinstr || opts.ibt || opts.mcount || @@ -199,6 +201,11 @@ static bool link_opts_valid(struct objtool_file *file) return false; } + if (opts.bounds) { + ERROR("--bounds requires --link"); + return false; + } + return true; } diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 0a33d9195b7a..59e6638db83f 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -4213,6 +4213,124 @@ static int add_prefix_symbols(struct objtool_file *file) return 0; } +static bool is_discarded_sec(struct section *sec) +{ + static const char * const discards[] = { + ".note.gnu.property", + ".export_symbol", + ".modinfo", + "__patchable_function_entries", + ".exitcall.exit", // not discarded for modules + }; + + if (!(sec->sh.sh_flags & SHF_ALLOC) || strstarts(sec->name, ".discard")) + return true; + + for (int i = 0; i < ARRAY_SIZE(discards); i++) + if (!strcmp(sec->name, discards[i])) + return true; + + return false; +} + +#define BOUNDS_SEC_NAME ".rodata.sec_bounds" + +static int create_bounds_section(struct objtool_file *file) +{ + struct section *bounds_sec, *sec; + unsigned int idx; + + sec = find_section_by_name(file->elf, BOUNDS_SEC_NAME); + if (sec) { + INIT_LIST_HEAD(&file->static_call_list); + WARN("file already has .sec_bounds section, skipping"); + return 0; + } + + idx = 0; + for_each_sec(file, sec) + if (sec->idx && !is_reloc_sec(sec) && !is_discarded_sec(sec)) + idx++; + + bounds_sec = elf_create_section_pair(file->elf, BOUNDS_SEC_NAME, + sizeof(long) * 2, idx, idx * 2); + if (!sec) + return -1; + + idx = 0; + for_each_sec(file, sec) { + if (sec->idx && !is_reloc_sec(sec) && !is_discarded_sec(sec)) { + + char sanitized_name[116]; + char start_name[128]; + char end_name[128]; + + if (!strcmp(sec->name, BOUNDS_SEC_NAME)) + continue; + + if (!sec->sym && !elf_create_section_symbol(file->elf, sec)) + return -1; + + strncpy(sanitized_name, sec->name, sizeof(sanitized_name) - 1); + for (char *s = sanitized_name; *s; s++) + if (*s == '.') + *s = '_'; + + snprintf(start_name, 256, "__sec%s_start", sanitized_name); + snprintf(end_name, 256, "__sec%s_end", sanitized_name); + + if (find_symbol_by_name(file->elf, start_name) || + find_symbol_by_name(file->elf, end_name)) + continue; + + /* 'start' symbol */ + if (!elf_create_symbol(file->elf, + start_name, + bounds_sec, + STB_GLOBAL, + STT_OBJECT, + idx * 2 * sizeof(long), + sizeof(long))) + return -1; + + if (!elf_create_symbol(file->elf, + end_name, + bounds_sec, + STB_GLOBAL, + STT_OBJECT, + (idx * 2 * sizeof(long)) + sizeof(long), + sizeof(long))) + return -1; + + /* 'start' reloc */ + if (!elf_init_reloc(file->elf, + bounds_sec->rsec, + idx * 2, + idx * 2 * sizeof(long), + sec->sym, + 0, + R_ABS64)) + return -1; + + /* 'end' reloc */ + if (!elf_init_reloc(file->elf, + bounds_sec->rsec, + (idx * 2) + 1, + (idx * 2 * sizeof(long)) + sizeof(long), + sec->sym, + sec->sh.sh_size, + R_ABS64)) + return -1; + + + idx++; + } + } + + + return 0; +} + static int validate_symbol(struct objtool_file *file, struct section *sec, struct symbol *sym, struct insn_state *state) { @@ -4826,6 +4944,13 @@ int check(struct objtool_file *file) warnings += ret; } + if (opts.bounds) { + ret = create_bounds_section(file); + if (ret < 0) + goto out; + warnings += ret; + } + if (opts.ibt) { ret = create_ibt_endbr_seal_sections(file); if (ret < 0) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 3d27983dc908..b596e992ca80 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -788,8 +788,7 @@ __elf_create_symbol(struct elf *elf, struct symbol *sym) return sym; } -static struct symbol * -elf_create_section_symbol(struct elf *elf, struct section *sec) +struct symbol *elf_create_section_symbol(struct elf *elf, struct section *sec) { struct symbol *sym = calloc(1, sizeof(*sym)); @@ -811,6 +810,8 @@ elf_create_section_symbol(struct elf *elf, struct section *sec) if (sym) elf_add_symbol(elf, sym); + sec->sym = sym; + return sym; } @@ -845,10 +846,37 @@ elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size) return sym; } -static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec, - unsigned int reloc_idx, - unsigned long offset, struct symbol *sym, - s64 addend, unsigned int type) +struct symbol *elf_create_symbol(struct elf *elf, char *name, + struct section *sec, unsigned int bind, + unsigned int type, unsigned long offset, + size_t size) +{ + struct symbol *sym = calloc(1, sizeof(*sym)); + + if (!sym) { + perror("calloc"); + return NULL; + } + + sym->name = strdup(name); + sym->sec = sec; + + sym->sym.st_name = elf_add_string(elf, NULL, sym->name); + sym->sym.st_info = GELF_ST_INFO(bind, type); + sym->sym.st_value = offset; + sym->sym.st_size = size; + + sym = __elf_create_symbol(elf, sym); + if (sym) + elf_add_symbol(elf, sym); + + return sym; +} + +struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec, + unsigned int reloc_idx, + unsigned long offset, struct symbol *sym, + s64 addend, unsigned int type) { struct reloc *reloc, empty = { 0 }; @@ -906,8 +934,6 @@ struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec, sym = elf_create_section_symbol(elf, insn_sec); if (!sym) return NULL; - - insn_sec->sym = sym; } return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend, diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h index fcca6662c8b4..c0a73e247722 100644 --- a/tools/objtool/include/objtool/builtin.h +++ b/tools/objtool/include/objtool/builtin.h @@ -30,6 +30,7 @@ struct opts { /* options: */ bool backtrace; bool backup; + bool bounds; bool dryrun; bool link; bool mnop; diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 2b8a69de4db8..a2f9c1b4ca88 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -113,8 +113,20 @@ struct section *elf_create_section_pair(struct elf *elf, const char *name, size_t entsize, unsigned int nr, unsigned int reloc_nr); +struct symbol *elf_create_symbol(struct elf *elf, char *name, + struct section *sec, unsigned int bind, + unsigned int type, unsigned long offset, + size_t size); + +struct symbol *elf_create_section_symbol(struct elf *elf, struct section *sec); + struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size); +struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec, + unsigned int reloc_idx, + unsigned long offset, struct symbol *sym, + s64 addend, unsigned int type); + struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec, unsigned long offset, unsigned int reloc_idx,