From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pl1-x629.google.com (mail-pl1-x629.google.com [IPv6:2607:f8b0:4864:20::629]) by sourceware.org (Postfix) with ESMTPS id 9C4A13858C27 for ; Mon, 7 Feb 2022 23:51:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 9C4A13858C27 Received: by mail-pl1-x629.google.com with SMTP id t9so10186170plg.13 for ; Mon, 07 Feb 2022 15:51:30 -0800 (PST) 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=M+Bv0okUpH5SiBFDo4EWW6yHRqdb9G7d9VWJLw44usM=; b=7sUl6NaPDc4xtc3AlZZFsp0pbXyZGfaFtz4+PK9orJqoKLFto2F9rYIPaRM68t1UNb sLzeKRRA2DXvA3Jqu6BCf0WEbuAOH8/HYCNwysnw7nzB/sxrk6ylnCBLz66Wems02BGi NuM5foY4V/KKh0G5qJuCMIv+d2WDz3Ay5X6dKulAMXlwllOjGAave4tLXCQH9xUIRG1E YZ+JE3UowfCO+7wsLHAD+DvYRRuLHFR2S5y1gJMCcYSSTfbChXXRA6dKLpJOqL3eRI2u xdtzi8Qyeb//4MLZBBFzTcSCfMJaSofk22aRz6/83UVZNLXrmz+XQbf993/6XSDyTzP3 /r0Q== X-Gm-Message-State: AOAM532mdN3HNayPC2iMEU20SDOKw5S1stdPHA9RoDTEjzpJrsGZuOQo ghU5pQ6eR7lofmy2ploF4e8= X-Google-Smtp-Source: ABdhPJyJCSIP1Namdm4MDSj0RU6Gk1+c2v4PO11uMjX9COdW2+ROOwuPTrWwxHK4qiGn+QqmYsR6Gw== X-Received: by 2002:a17:90a:ea94:: with SMTP id h20mr1417365pjz.199.1644277889269; Mon, 07 Feb 2022 15:51:29 -0800 (PST) Received: from gnu-tgl-2.localdomain ([172.58.38.240]) by smtp.gmail.com with ESMTPSA id dw20sm458768pjb.3.2022.02.07.15.51.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Feb 2022 15:51:28 -0800 (PST) Received: from gnu-tgl-2.. (localhost [IPv6:::1]) by gnu-tgl-2.localdomain (Postfix) with ESMTP id B31C53007E4; Mon, 7 Feb 2022 15:51:27 -0800 (PST) From: "H.J. Lu" To: libc-alpha@sourceware.org Cc: Fangrui Song , Joseph Myers Subject: [PATCH v3 3/5] Add GLIBC_ABI_DT_RELR for DT_RELR support Date: Mon, 7 Feb 2022 15:51:25 -0800 Message-Id: <20220207235127.1807294-4-hjl.tools@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220207235127.1807294-1-hjl.tools@gmail.com> References: <20220207235127.1807294-1-hjl.tools@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-3028.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, 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-List-Received-Date: Mon, 07 Feb 2022 23:51:32 -0000 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. --- elf/Makefile | 18 ++++++++++++++++-- elf/Versions | 5 +++++ elf/dl-version.c | 33 +++++++++++++++++++++++++++++++-- elf/libc-abi-version.exp | 1 + include/link.h | 6 ++++++ scripts/abilist.awk | 2 ++ scripts/versions.awk | 7 ++++++- 7 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 elf/libc-abi-version.exp diff --git a/elf/Makefile b/elf/Makefile index 71b08c75dd..a6515e8a21 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -48,6 +48,10 @@ routines = \ rtld_static_init \ # routines +ifeq ($(have-dt-relr),yes) +check-abi-version-libc = $(objpfx)check-abi-version-libc.out +endif + # The core dynamic linking functions are in libc for the static and # profiled libraries. dl-routines = \ @@ -1106,8 +1110,8 @@ $(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 $(check-abi-version-libc) +tests-special += $(objpfx)check-abi-ld.out $(check-abi-version-libc) update-abi: update-abi-ld update-all-abi: update-all-abi-ld @@ -2747,3 +2751,13 @@ $(objpfx)check-tst-relr-pie.out: $(objpfx)tst-relr-pie | sed -ne '/required from libc.so/,$$ p' \ | grep GLIBC_ABI_DT_RELR > $@; \ $(evaluate-test) + +$(objpfx)check-abi-version-libc.out: libc-abi-version.exp \ + $(objpfx)libc.symlist-abi-version + cmp $^ > $@; \ + $(evaluate-test) + +$(objpfx)libc.symlist-abi-version: $(common-objpfx)libc.so + LC_ALL=C $(NM) -D $< | grep " GLIBC_ABI_" \ + | sed "s/^0\+/00000000/" > $@T + mv -f $@T $@ 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..720ec596a5 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; @@ -253,6 +261,16 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode) 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 +370,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/elf/libc-abi-version.exp b/elf/libc-abi-version.exp new file mode 100644 index 0000000000..455088dc6b --- /dev/null +++ b/elf/libc-abi-version.exp @@ -0,0 +1 @@ +00000000 A GLIBC_ABI_DT_RELR diff --git a/include/link.h b/include/link.h index bef2820b40..ce9e3d5214 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) { -- 2.34.1