From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pj1-x1035.google.com (mail-pj1-x1035.google.com [IPv6:2607:f8b0:4864:20::1035]) by sourceware.org (Postfix) with ESMTPS id C60D53858022 for ; Fri, 10 Dec 2021 14:52:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C60D53858022 Received: by mail-pj1-x1035.google.com with SMTP id p18-20020a17090ad31200b001a78bb52876so9600515pju.3 for ; Fri, 10 Dec 2021 06:52:23 -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:mime-version :content-transfer-encoding; bh=Vcr8RwSzd3nCHBP27OpA7dLadeCed0MNDSIIUodn+Mk=; b=5gZSeZ7f1973C02dJ1NpDiElWB+0rgG74Hutiub/9QgtZltKRHik5wvzHblwdC/g39 9TCStJ34YLS6Z8tllVZvfdAiezC3shoxhMei53p0+A7+AMgRTgirl0iFgnbK89zhy5Bh DwwcLwi6i3rpTN0XuWKqI7ydnxouFs7sVnqqiHqUj/A8lPoxj7b3b8MOO0vZKbxIQlTF 13zkQG4PYAHaOrsgwTIARXMKOevQctN/fKOnOSYj6xjqu2Fyjov6/Hg4hOyM/ftaqLMU cG8xdVPLtVNFOkh7XKs0BtCx3QbF8bmuTJ/5wICMZrqTZOEnr7daNR6QI2iAJ51pWi97 IjeQ== X-Gm-Message-State: AOAM530lpXRNxRe/++uxpGd5lvfYIJWvIsOQYXjcWJ0bwuQr4ThP95Yj sdOkcv1zCzd+HPQawGQ6ev3lV3MHeQY= X-Google-Smtp-Source: ABdhPJya8ClBkvIC8f7RDJhMbjKZ8lUFbHAU30LXD+x/4OM/qBCWISrcmHyRsbH1e4/uCV5eVjG++g== X-Received: by 2002:a17:902:db12:b0:142:3ac:7ec3 with SMTP id m18-20020a170902db1200b0014203ac7ec3mr75216975plx.2.1639147942794; Fri, 10 Dec 2021 06:52:22 -0800 (PST) Received: from gnu-cfl-2.localdomain ([172.58.35.133]) by smtp.gmail.com with ESMTPSA id qe2sm3395098pjb.42.2021.12.10.06.52.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Dec 2021 06:52:22 -0800 (PST) Received: from gnu-tgl-2.localdomain (gnu-tgl-2 [192.168.1.34]) by gnu-cfl-2.localdomain (Postfix) with ESMTPS id 7E6AC42096C; Fri, 10 Dec 2021 06:52:21 -0800 (PST) Received: from gnu-tgl-2.. (localhost [IPv6:::1]) by gnu-tgl-2.localdomain (Postfix) with ESMTP id 431073003D5; Fri, 10 Dec 2021 06:52:20 -0800 (PST) From: "H.J. Lu" To: libc-alpha@sourceware.org Cc: Florian Weimer Subject: [PATCH v4] elf: Only allow execute libc.so.6 directly [BZ #28453] Date: Fri, 10 Dec 2021 06:52:20 -0800 Message-Id: <20211210145220.3750010-1-hjl.tools@gmail.com> X-Mailer: git-send-email 2.33.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-3028.6 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_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, 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: Fri, 10 Dec 2021 14:52:26 -0000 Changes in the v4 patch: 1. Only allow executing executables and libc.s.6 directly. Changes in the v3 patch: 1. Delay zero entry point value check. 2. Build testobj1.so with -Wl,--entry=0 Changes in the v2 patch: 1. Use rtld_progname in the error message. A shared library can have an invalid non-zero entry point value generated by the old linkers, which leads to ld.so crash when it executes such shared library directly. Since we can't rely on entry point values to decide if it is a valid entry point, we should only allow executing executables and libc.s.6 directly. Now we get $ ./elf/ld.so ./libc.so.6 GNU C Library (GNU libc) development release version 2.34.9000. Copyright (C) 2021 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Compiled by GNU CC version 11.2.1 20211203 (Red Hat 11.2.1-7). libc ABIs: UNIQUE IFUNC ABSOLUTE For bug reporting instructions, please see: . $ ./elf/ld.so /lib64/libstdc++.so.6.0.29 ./elf/ld.so: cannot execute '/lib64/libstdc++.so.6.0.29' without entry point $ instead of $ /lib64/ld-linux-x86-64.so.2 /lib64/libstdc++.so.6.0.29 Segmentation fault (core dumped) $ This fixes [BZ #28453]. --- elf/Makefile | 10 ++++++++++ elf/rtld.c | 37 ++++++++++++++++++++++++++----------- elf/tst-rtld-run-dso.sh | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 11 deletions(-) create mode 100755 elf/tst-rtld-run-dso.sh diff --git a/elf/Makefile b/elf/Makefile index ef36008673..1832dfa537 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -50,6 +50,10 @@ ifeq (yesyes,$(build-shared)$(run-built-tests)) tests-special += $(objpfx)list-tunables.out endif +ifeq (yes,$(build-shared)) +tests-special += $(objpfx)tst-rtld-run-dso.out +endif + # Make sure that the compiler does not insert any library calls in tunables # code paths. ifeq (yes,$(have-loop-to-function)) @@ -1877,6 +1881,12 @@ $(objpfx)list-tunables.out: tst-rtld-list-tunables.sh $(objpfx)ld.so $(objpfx)/tst-rtld-list-tunables.out > $@; \ $(evaluate-test) +$(objpfx)tst-rtld-run-dso.out: tst-rtld-run-dso.sh $(objpfx)ld.so \ + $(objpfx)testobj1.so + $(SHELL) tst-rtld-run-dso.sh $(objpfx)ld.so $(objpfx)testobj1.so \ + '$(test-wrapper-env)' '$(run_program_env)' > $@ + $(evaluate-test) + tst-dst-static-ENV = LD_LIBRARY_PATH='$$ORIGIN' $(objpfx)tst-rtld-help.out: $(objpfx)ld.so diff --git a/elf/rtld.c b/elf/rtld.c index 6ce1e07dc0..f6b80444fa 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -1108,8 +1108,9 @@ load_audit_modules (struct link_map *main_map, struct audit_list *audit_list) } /* Check if the executable is not actualy dynamically linked, and - invoke it directly in that case. */ -static void + invoke it directly in that case. Return true if it can be executed + directly by ld.so. */ +static bool rtld_chain_load (struct link_map *main_map, char *argv0) { /* The dynamic loader run against itself. */ @@ -1122,17 +1123,22 @@ rtld_chain_load (struct link_map *main_map, char *argv0) + main_map->l_info[DT_SONAME]->d_un.d_val)) == 0) _dl_fatal_printf ("%s: loader cannot load itself\n", rtld_soname); - /* With DT_NEEDED dependencies, the executable is dynamically - linked. */ - if (__glibc_unlikely (main_map->l_info[DT_NEEDED] != NULL)) - return; - - /* If the executable has program interpreter, it is dynamically - linked. */ + /* If it has program interpreter, it is dynamically linked + executable. */ for (size_t i = 0; i < main_map->l_phnum; ++i) if (main_map->l_phdr[i].p_type == PT_INTERP) - return; + return true; + + /* With DT_NEEDED dependencies, it is a shared library. Only allow + execute libc.so directly. */ + if (__glibc_unlikely (main_map->l_info[DT_NEEDED] != NULL)) + return (main_map->l_info[DT_SONAME] != NULL + && strncmp ("libc.so.6", + ((const char *) D_PTR (main_map, l_info[DT_STRTAB]) + + main_map->l_info[DT_SONAME]->d_un.d_val), + sizeof ("libc.so.6") - 1) == 0); + /* This is a static executable. */ const char *pathname = _dl_argv[0]; if (argv0 != NULL) _dl_argv[0] = argv0; @@ -1144,6 +1150,7 @@ rtld_chain_load (struct link_map *main_map, char *argv0) else _dl_fatal_printf("%s: cannot execute %s: %d\n", rtld_soname, pathname, errno); + return true; } static void @@ -1181,6 +1188,8 @@ dl_main (const ElfW(Phdr) *phdr, _dl_starting_up = 1; #endif + bool can_execute = true; + const char *ld_so_name = _dl_argv[0]; if (*user_entry == (ElfW(Addr)) ENTRY_POINT) { @@ -1415,7 +1424,7 @@ dl_main (const ElfW(Phdr) *phdr, main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded; if (__glibc_likely (state.mode == rtld_mode_normal)) - rtld_chain_load (main_map, argv0); + can_execute = rtld_chain_load (main_map, argv0); phdr = main_map->l_phdr; phnum = main_map->l_phnum; @@ -2491,6 +2500,12 @@ dl_main (const ElfW(Phdr) *phdr, rtld_timer_accum (&relocate_time, start); } + /* Stop if it can't be executed. */ + if (!can_execute) + _dl_fatal_printf("%s: cannot execute shared object '%s' directly " + "without entry point\n", + ld_so_name, rtld_progname); + /* Relocation is complete. Perform early libc initialization. This is the initial libc, even if audit modules have been loaded with other libcs. */ diff --git a/elf/tst-rtld-run-dso.sh b/elf/tst-rtld-run-dso.sh new file mode 100755 index 0000000000..5192f64210 --- /dev/null +++ b/elf/tst-rtld-run-dso.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# Test for ld.so on a shared library with no associated entry point. +# Copyright (C) 2021 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# . + +set -e + +rtld=$1 +dso=$2 +test_wrapper_env=$3 +run_program_env=$4 + +LC_ALL=C +export LC_ALL + +${test_wrapper_env} \ +${run_program_env} \ +$rtld $dso 2>&1 \ +| grep "cannot execute" -- 2.33.1