From patchwork Fri Mar 17 06:32:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stsp X-Patchwork-Id: 66498 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E1EA13858431 for ; Fri, 17 Mar 2023 06:33:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E1EA13858431 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1679034792; bh=ZNJh/PMadX/JJdXrTT94aYfnaHtH+vBKczuQQv+lyPY=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=NHnBt9sv1qsh0EVYaS0l3j+Ml+0tkj7YNFgiBfJplsnsEG609AIb8XdutQY25K+m9 BJTA3ItSvSCr6od3ROVcVFqRbFMa31sQvRf79founqymX16LRKifK0bzkX0nTNoEpB TAtbkamtMocYi+8hWXILf9zP9sUoqJfBFb1RpDI8= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from forward101j.mail.yandex.net (forward101j.mail.yandex.net [IPv6:2a02:6b8:0:801:2::101]) by sourceware.org (Postfix) with ESMTPS id A611238555A0 for ; Fri, 17 Mar 2023 06:32:40 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A611238555A0 Received: from sas9-2d24a7e69f58.qloud-c.yandex.net (sas9-2d24a7e69f58.qloud-c.yandex.net [IPv6:2a02:6b8:c11:2298:0:640:2d24:a7e6]) by forward101j.mail.yandex.net (Yandex) with ESMTP id B7E6969B7C7F for ; Fri, 17 Mar 2023 09:32:33 +0300 (MSK) Received: by sas9-2d24a7e69f58.qloud-c.yandex.net (smtp/Yandex) with ESMTPSA id QWeJF9abi0U1-fRG4jtp9; Fri, 17 Mar 2023 09:32:33 +0300 X-Yandex-Fwd: 1 To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 06/11] elf: load elf hdr fully in open_verify() Date: Fri, 17 Mar 2023 11:32:05 +0500 Message-Id: <20230317063210.4118076-7-stsp2@yandex.ru> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20230317063210.4118076-1-stsp2@yandex.ru> References: <20230317063210.4118076-1-stsp2@yandex.ru> MIME-Version: 1.0 X-Spam-Status: No, score=-11.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM, GIT_PATCH_0, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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: Stas Sergeev via Libc-alpha From: stsp Reply-To: Stas Sergeev Errors-To: libc-alpha-bounces+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" open_verify() reads an elf header, putting only the ehdr part into the filebuf, and reading the rest of the header into the alloca() space. This requires _ld_map_object_1() (former _ld_map_object_from_fd()) to read parts of an elf header again, getting only ehdr from filebuf. This patch makes filebuf sizeable and reads an entire elf header there, avoiding the code duplication and getting rid of file reads in _ld_map_object_1(). The test-suite was run on x86_64/64 and showed no regressions. Signed-off-by: Stas Sergeev --- elf/dl-load.c | 122 +++++++++++++++++++++++++++----------------------- 1 file changed, 66 insertions(+), 56 deletions(-) diff --git a/elf/dl-load.c b/elf/dl-load.c index 353dc2aa13..45656d8fa5 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -55,7 +55,8 @@ struct filebuf #else # define FILEBUF_SIZE 832 #endif - char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr))))); + ssize_t allocated; + char *buf; }; #include "dynamic-link.h" @@ -124,6 +125,29 @@ static const size_t system_dirs_len[] = }; #define nsystem_dirs_len array_length (system_dirs_len) +static void +filebuf_done (struct filebuf *fb) +{ + free (fb->buf); + fb->buf = NULL; + fb->allocated = 0; +} + +static bool +filebuf_ensure (struct filebuf *fb, size_t size) +{ + bool ret = false; + + if (size > fb->allocated) + { + size_t new_len = size + FILEBUF_SIZE; + fb->buf = realloc (fb->buf, new_len); + fb->allocated = new_len; + ret = true; + } + return ret; +} + static bool is_trusted_path_normalize (const char *path, size_t len) { @@ -955,18 +979,8 @@ _ld_map_object_1 (struct link_map *l, int fd, l->l_phnum = header->e_phnum; maplength = header->e_phnum * sizeof (ElfW(Phdr)); - if (header->e_phoff + maplength <= (size_t) fbp->len) - phdr = (void *) (fbp->buf + header->e_phoff); - else - { - phdr = alloca (maplength); - if ((size_t) __pread64_nocancel (fd, (void *) phdr, maplength, - header->e_phoff) != maplength) - { - errstring = N_("cannot read file data"); - goto lose_errno; - } - } + assert (header->e_phoff + maplength <= (size_t) fbp->len); + phdr = (void *) (fbp->buf + header->e_phoff); /* On most platforms presume that PT_GNU_STACK is absent and the stack is * executable. Other platforms default to a nonexecutable stack and don't @@ -1629,31 +1643,16 @@ do_open_verify (const char *name, int fd, /* Initialize it to make the compiler happy. */ const char *errstring = NULL; int errval = 0; - ElfW(Ehdr) *ehdr; + ElfW(Ehdr) _ehdr; + ElfW(Ehdr) *ehdr = &_ehdr; ElfW(Phdr) *phdr; size_t maplength; /* We successfully opened the file. Now verify it is a file we can use. */ __set_errno (0); - fbp->len = 0; - assert (sizeof (fbp->buf) > sizeof (ElfW(Ehdr))); /* Read in the header. */ - do - { - ssize_t retlen = __read_nocancel (fd, fbp->buf + fbp->len, - sizeof (fbp->buf) - fbp->len); - if (retlen <= 0) - break; - fbp->len += retlen; - } - while (__glibc_unlikely (fbp->len < sizeof (ElfW(Ehdr)))); - - /* This is where the ELF header is loaded. */ - ehdr = (ElfW(Ehdr) *) fbp->buf; - - /* Now run the tests. */ - if (__glibc_unlikely (fbp->len < (ssize_t) sizeof (ElfW(Ehdr)))) + if (__pread64_nocancel (fd, &_ehdr, sizeof(_ehdr), 0) != sizeof(_ehdr)) { errval = errno; errstring = (errval == 0 @@ -1754,19 +1753,17 @@ do_open_verify (const char *name, int fd, } maplength = ehdr->e_phnum * sizeof (ElfW(Phdr)); - if (ehdr->e_phoff + maplength <= (size_t) fbp->len) - phdr = (void *) (fbp->buf + ehdr->e_phoff); - else + filebuf_ensure (fbp, maplength + ehdr->e_phoff); + if ((size_t) __pread64_nocancel (fd, fbp->buf, maplength + + ehdr->e_phoff, 0) != maplength + + ehdr->e_phoff) { - phdr = alloca (maplength); - if ((size_t) __pread64_nocancel (fd, (void *) phdr, maplength, - ehdr->e_phoff) != maplength) - { - errval = errno; - errstring = N_("cannot read file data"); - goto lose; - } + errval = errno; + errstring = N_("cannot read file data"); + goto lose; } + fbp->len = maplength + ehdr->e_phoff; + phdr = (void *) (fbp->buf + ehdr->e_phoff); if (__glibc_unlikely (elf_machine_reject_phdr_p (phdr, ehdr->e_phnum, fbp->buf, fbp->len, @@ -1992,16 +1989,16 @@ open_path (const char *name, size_t namelen, int mode, /* Map in the shared object file NAME. */ -struct link_map * -_dl_map_object (struct link_map *loader, const char *name, - int type, int trace_mode, int mode, Lmid_t nsid) +static struct link_map * +___dl_map_object (struct link_map *loader, const char *name, + int type, int trace_mode, int mode, Lmid_t nsid, + struct filebuf *fbp) { int fd; const char *origname = NULL; char *realname; char *name_copy; struct link_map *l; - struct filebuf fb; assert (nsid >= 0); assert (nsid < GL(dl_nns)); @@ -2091,7 +2088,7 @@ _dl_map_object (struct link_map *loader, const char *name, { fd = open_path (name, namelen, mode, &l->l_rpath_dirs, - &realname, &fb, loader, LA_SER_RUNPATH, + &realname, fbp, loader, LA_SER_RUNPATH, &found_other_class); if (fd != -1) break; @@ -2107,7 +2104,7 @@ _dl_map_object (struct link_map *loader, const char *name, "RPATH")) fd = open_path (name, namelen, mode, &main_map->l_rpath_dirs, - &realname, &fb, loader ?: main_map, LA_SER_RUNPATH, + &realname, fbp, loader ?: main_map, LA_SER_RUNPATH, &found_other_class); /* Also try DT_RUNPATH in the executable for LD_AUDIT dlopen @@ -2121,7 +2118,7 @@ _dl_map_object (struct link_map *loader, const char *name, if (cache_rpath (main_map, &l_rpath_dirs, DT_RUNPATH, "RUNPATH")) fd = open_path (name, namelen, mode, &l_rpath_dirs, - &realname, &fb, loader ?: main_map, + &realname, fbp, loader ?: main_map, LA_SER_RUNPATH, &found_other_class); } } @@ -2129,7 +2126,7 @@ _dl_map_object (struct link_map *loader, const char *name, /* Try the LD_LIBRARY_PATH environment variable. */ if (fd == -1 && __rtld_env_path_list.dirs != (void *) -1) fd = open_path (name, namelen, mode, &__rtld_env_path_list, - &realname, &fb, + &realname, fbp, loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded, LA_SER_LIBPATH, &found_other_class); @@ -2138,7 +2135,7 @@ _dl_map_object (struct link_map *loader, const char *name, && cache_rpath (loader, &loader->l_runpath_dirs, DT_RUNPATH, "RUNPATH")) fd = open_path (name, namelen, mode, - &loader->l_runpath_dirs, &realname, &fb, loader, + &loader->l_runpath_dirs, &realname, fbp, loader, LA_SER_RUNPATH, &found_other_class); if (fd == -1) @@ -2147,7 +2144,7 @@ _dl_map_object (struct link_map *loader, const char *name, if (realname != NULL) { fd = open_verify (realname, fd, - &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, + fbp, loader ?: GL(dl_ns)[nsid]._ns_loaded, LA_SER_CONFIG, mode, &found_other_class, false); if (fd == -1) @@ -2201,7 +2198,7 @@ _dl_map_object (struct link_map *loader, const char *name, if (cached != NULL) { fd = open_verify (cached, -1, - &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, + fbp, loader ?: GL(dl_ns)[nsid]._ns_loaded, LA_SER_CONFIG, mode, &found_other_class, false); if (__glibc_likely (fd != -1)) @@ -2219,7 +2216,7 @@ _dl_map_object (struct link_map *loader, const char *name, || __glibc_likely (!(l->l_flags_1 & DF_1_NODEFLIB))) && __rtld_search_dirs.dirs != (void *) -1) fd = open_path (name, namelen, mode, &__rtld_search_dirs, - &realname, &fb, l, LA_SER_DEFAULT, &found_other_class); + &realname, fbp, l, LA_SER_DEFAULT, &found_other_class); /* Add another newline when we are tracing the library loading. */ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) @@ -2235,7 +2232,7 @@ _dl_map_object (struct link_map *loader, const char *name, fd = -1; else { - fd = open_verify (realname, -1, &fb, + fd = open_verify (realname, -1, fbp, loader ?: GL(dl_ns)[nsid]._ns_loaded, 0, mode, &found_other_class, true); if (__glibc_unlikely (fd == -1)) @@ -2296,10 +2293,23 @@ _dl_map_object (struct link_map *loader, const char *name, } void *stack_end = __libc_stack_end; - return _dl_map_object_from_fd (name, origname, fd, &fb, realname, loader, + return _dl_map_object_from_fd (name, origname, fd, fbp, realname, loader, type, mode, &stack_end, nsid); } +struct link_map * +_dl_map_object (struct link_map *loader, const char *name, + int type, int trace_mode, + int mode, Lmid_t nsid) +{ + struct link_map *ret; + struct filebuf fb = {}; + + ret = ___dl_map_object (loader, name, type, trace_mode, mode, nsid, &fb); + filebuf_done (&fb); + return ret; +} + struct add_path_state { bool counting;