From patchwork Wed Apr 13 18:25:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 1616930 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.a=rsa-sha256 header.s=default header.b=GbGG2v1A; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KdrdG0WvGz9s5V for ; Thu, 14 Apr 2022 04:26:10 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3DF143857830 for ; Wed, 13 Apr 2022 18:26:08 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3DF143857830 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1649874368; bh=MOi96q2BDCLXw6vfPPxgWYYEjGyj6vv2raliLsmPWhw=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=GbGG2v1AU2bXG1wnvH9roMOVBagQgWWLu4witRPnEnSV9/qFgD9vRj0CeDEEbr1sm 0pXnQGEpwiDNQgSSz7kJEuouJ3IqPmpr8eGjOrO78KYZsp0b0P3ZV/ogpMs6NEn0J9 yef+/2Lg3lhrUCbpe7Jd5Tc7YfDgFkmFEmjlQGKw= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-pj1-x102f.google.com (mail-pj1-x102f.google.com [IPv6:2607:f8b0:4864:20::102f]) by sourceware.org (Postfix) with ESMTPS id 98F153858C53 for ; Wed, 13 Apr 2022 18:25:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 98F153858C53 Received: by mail-pj1-x102f.google.com with SMTP id h23-20020a17090a051700b001c9c1dd3acbso3146551pjh.3 for ; Wed, 13 Apr 2022 11:25:12 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=MOi96q2BDCLXw6vfPPxgWYYEjGyj6vv2raliLsmPWhw=; b=frhGkSis0597zaTPWIs1svzI4MWxi8LS2gK5L/BiNE9m2gRsrMh8eKMLc+wWu2oX8x P66ZUfjFqPB6AOsSmk73ASB6YUb2dnkR8KKC84y8ig6l0NryTHr1tlwsEfHQLVlN7cB7 +NqGu0jvROIXRPO+69D/JsqN/0aVL+zg74DIwG+dImvyymqoAzB7lrMcBk6EcSuiCOD1 jxGfaSxbN5Ux+/RfOeK9b6UNUc8wdcmlbxpDPA4ZaTEESZUkQipPLXMlEtjGyvinAMvP I0NT+R4Fkr6VtQn2knMDMRaQUxusfiuZxfqOhaiOHNu2f2JZCEsS+nAdsMY547lKs78M wuPQ== X-Gm-Message-State: AOAM533LlomzMtYvdxpORYKnVOSMVq+OaD26rEYy/rpyO697YP73DOhT hu7NEQn7llRYwJh1VjYEjHrJr/yR26Y= X-Google-Smtp-Source: ABdhPJyMe73ohpGioBUor+HImcjVwahqzIWpfqt2shtIFC4ff9PlHp6VgkRnCFar0Mm/agBVm6w0+g== X-Received: by 2002:a17:902:d5cd:b0:156:6263:bbc7 with SMTP id g13-20020a170902d5cd00b001566263bbc7mr45244684plh.160.1649874311553; Wed, 13 Apr 2022 11:25:11 -0700 (PDT) Received: from gnu-tgl-3.localdomain ([172.58.35.207]) by smtp.gmail.com with ESMTPSA id f16-20020a056a00229000b004fabe756ba6sm47138492pfe.54.2022.04.13.11.25.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 13 Apr 2022 11:25:09 -0700 (PDT) Received: from gnu-tgl-3.. (localhost [IPv6:::1]) by gnu-tgl-3.localdomain (Postfix) with ESMTP id D150CC0249; Wed, 13 Apr 2022 11:25:07 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH v8 2/6] Add GLIBC_ABI_DT_RELR for DT_RELR support Date: Wed, 13 Apr 2022 11:25:03 -0700 Message-Id: <20220413182507.896862-3-hjl.tools@gmail.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220413182507.896862-1-hjl.tools@gmail.com> References: <20220413182507.896862-1-hjl.tools@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-3027.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE, URIBL_BLACK autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: "H.J. Lu via Libc-alpha" From: "H.J. Lu" Reply-To: "H.J. Lu" Errors-To: libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org Sender: "Libc-alpha" The EI_ABIVERSION field of the ELF header in executables and shared libraries can be bumped to indicate the minimum ABI requirement on the dynamic linker. However, EI_ABIVERSION in executables isn't checked by the Linux kernel ELF loader nor the existing dynamic linker. Executables will crash mysteriously if the dynamic linker doesn't support the ABI features required by the EI_ABIVERSION field. The dynamic linker should be changed to check EI_ABIVERSION in executables. Add a glibc version, GLIBC_ABI_DT_RELR, to indicate DT_RELR support so that the existing dynamic linkers will issue an error on executables with GLIBC_ABI_DT_RELR dependency. Issue an error if there is a DT_RELR entry without GLIBC_ABI_DT_RELR dependency nor GLIBC_PRIVATE definition. Support __placeholder_only_for_empty_version_map as the placeholder symbol used only for empty version map to generate GLIBC_ABI_DT_RELR without any symbols. Reviewed-by: Fangrui Song --- elf/Makefile | 14 ++++++++++++-- elf/Versions | 5 +++++ elf/dl-version.c | 38 ++++++++++++++++++++++++++++++++------ include/link.h | 6 ++++++ scripts/abilist.awk | 2 ++ scripts/versions.awk | 7 ++++++- 6 files changed, 63 insertions(+), 9 deletions(-) diff --git a/elf/Makefile b/elf/Makefile index c96924e9c2..09d3d88336 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -1105,8 +1105,12 @@ $(eval $(call include_dsosort_tests,dso-sort-tests-1.def)) $(eval $(call include_dsosort_tests,dso-sort-tests-2.def)) endif -check-abi: $(objpfx)check-abi-ld.out -tests-special += $(objpfx)check-abi-ld.out +check-abi: $(objpfx)check-abi-ld.out \ + $(objpfx)check-abi-version-libc.out +tests-special += \ + $(objpfx)check-abi-ld.out \ + $(objpfx)check-abi-version-libc.out \ +# tests-special update-abi: update-abi-ld update-all-abi: update-all-abi-ld @@ -2725,3 +2729,9 @@ $(objpfx)tst-p_align3: $(objpfx)tst-p_alignmod3.so $(objpfx)tst-p_align3.out: tst-p_align3.sh $(objpfx)tst-p_align3 $(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \ $(evaluate-test) + +$(objpfx)check-abi-version-libc.out: $(common-objpfx)libc.so + LC_ALL=C $(READELF) -V -W $< \ + | sed -ne '/.gnu.version_d/, /.gnu.version_r/ p' \ + | grep GLIBC_ABI_DT_RELR > $@; \ + $(evaluate-test) diff --git a/elf/Versions b/elf/Versions index 8bed855d8c..a9ff278de7 100644 --- a/elf/Versions +++ b/elf/Versions @@ -23,6 +23,11 @@ libc { GLIBC_2.35 { _dl_find_object; } + GLIBC_ABI_DT_RELR { + # This symbol is used only for empty version map and will be removed + # by scripts/versions.awk. + __placeholder_only_for_empty_version_map; + } GLIBC_PRIVATE { # functions used in other libraries __libc_early_init; diff --git a/elf/dl-version.c b/elf/dl-version.c index b47bd91727..0537b1c7de 100644 --- a/elf/dl-version.c +++ b/elf/dl-version.c @@ -214,12 +214,20 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode) while (1) { /* Match the symbol. */ + const char *string = strtab + aux->vna_name; result |= match_symbol (DSO_FILENAME (map->l_name), map->l_ns, aux->vna_hash, - strtab + aux->vna_name, - needed->l_real, verbose, + string, needed->l_real, verbose, aux->vna_flags & VER_FLG_WEAK); + if (map->l_abi_version == lav_none + /* 0xfd0e42: _dl_elf_hash ("GLIBC_ABI_DT_RELR"). */ + && aux->vna_hash == 0xfd0e42 + && __glibc_likely (strcmp (string, + "GLIBC_ABI_DT_RELR") + == 0)) + map->l_abi_version = lav_dt_relr_ref; + /* Compare the version index. */ if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high) ndx_high = aux->vna_other & 0x7fff; @@ -243,16 +251,23 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode) } /* We also must store the names of the defined versions. Determine - the maximum index here as well. - - XXX We could avoid the loop by just taking the number of definitions - as an upper bound of new indices. */ + the maximum index here as well. */ if (def != NULL) { ElfW(Verdef) *ent; ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr); while (1) { + /* 0x0963cf85: _dl_elf_hash ("GLIBC_PRIVATE"). */ + if (ent->vd_hash == 0x0963cf85) + { + ElfW(Verdaux) *aux = (ElfW(Verdaux) *) ((char *) ent + + ent->vd_aux); + if (__glibc_likely (strcmp ("GLIBC_PRIVATE", + strtab + aux->vda_name) == 0)) + map->l_abi_version = lav_private_def; + } + if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high) ndx_high = ent->vd_ndx & 0x7fff; @@ -352,6 +367,17 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode) } } + /* Issue an error if there is a DT_RELR entry without GLIBC_ABI_DT_RELR + dependency nor GLIBC_PRIVATE definition. */ + if (map->l_info[DT_RELR] != NULL + && __glibc_unlikely (map->l_abi_version == lav_none)) + { + _dl_exception_create + (&exception, DSO_FILENAME (map->l_name), + N_("DT_RELR without GLIBC_ABI_DT_RELR dependency")); + goto call_error; + } + return result; } diff --git a/include/link.h b/include/link.h index 03db14c7b0..8ec5e35cf2 100644 --- a/include/link.h +++ b/include/link.h @@ -177,6 +177,12 @@ struct link_map lt_library, /* Library needed by main executable. */ lt_loaded /* Extra run-time loaded shared object. */ } l_type:2; + enum /* ABI dependency of this object. */ + { + lav_none, /* No ABI dependency. */ + lav_dt_relr_ref, /* Need GLIBC_ABI_DT_RELR. */ + lav_private_def /* Define GLIBC_PRIVATE. */ + } l_abi_version:2; unsigned int l_relocated:1; /* Nonzero if object's relocations done. */ unsigned int l_init_called:1; /* Nonzero if DT_INIT function called. */ unsigned int l_global:1; /* Nonzero if object in _dl_global_scope. */ diff --git a/scripts/abilist.awk b/scripts/abilist.awk index 24a34ccbed..6cc7af6ac8 100644 --- a/scripts/abilist.awk +++ b/scripts/abilist.awk @@ -55,6 +55,8 @@ $2 == "g" || $2 == "w" && (NF == 7 || NF == 8) { # caused STV_HIDDEN symbols to appear in .dynsym, though that is useless. if (NF > 7 && $7 == ".hidden") next; + if (version ~ /^GLIBC_ABI_/ && !include_abi_version) next; + if (version == "GLIBC_PRIVATE" && !include_private) next; desc = ""; diff --git a/scripts/versions.awk b/scripts/versions.awk index 357ad1355e..d70b07bd1a 100644 --- a/scripts/versions.awk +++ b/scripts/versions.awk @@ -185,8 +185,13 @@ END { closeversion(oldver, veryoldver); veryoldver = oldver; } - printf("%s {\n global:\n", $2) > outfile; oldver = $2; + # Skip the placeholder symbol used only for empty version map. + if ($3 == "__placeholder_only_for_empty_version_map;") { + printf("%s {\n", $2) > outfile; + continue; + } + printf("%s {\n global:\n", $2) > outfile; } printf(" ") > outfile; for (n = 3; n <= NF; ++n) {