From patchwork Tue May 22 19:49:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 27407 Received: (qmail 94798 invoked by alias); 22 May 2018 19:50:05 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 92930 invoked by uid 89); 22 May 2018 19:50:02 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.5 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=1746, 9607, asks, filling X-HELO: mail-qt0-f196.google.com X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:references:from:openpgp:autocrypt :message-id:date:user-agent:mime-version:in-reply-to :content-language:content-transfer-encoding; bh=C1vduZJEBHrcBSPW7GffBXtkEbfK68M76tGHh00tgz8=; b=eOk3zaIpQ5ZL+K7B+OTKCIpuvoruCZVjTf+zLHVx18YaJoOhzeUljrrmeUkVVaFKU+ h1twUlYYX+S1q+/HZ0RN2UD0dM8j+F8APbHbfD/KbU7xlUqyG3eymXHH0b7HtVbD7A8N k8CYYJbsIlfJnhqZUsByOHOXY+l+AGCyIn6bOri2dhvr4+JVRsGiRi141+0qtfAhJobz mYYCckkhEl71RIY2jvME7ApRq807zZH6uodTiFctKnhR/H8tHkIS/H4pwCu2jTPJZ22B J1hkFd+jpDPcRhJEdZo5lycE6ojMf/ppWNr2rKyOVa2qYfoPFM3fVhNRZS6C9Ygryj7S 7Asw== X-Gm-Message-State: ALKqPwfxR5rcvTmiSh5OeBHwEn5xN8NGFz/XE8W9y268aNqmkBSlBy3B dkyb6cVNdQ8TurHUuVu4wCwNbfzFla8= X-Google-Smtp-Source: AB8JxZqpv10NEXnML5ihtGuMvgeRJHXOlmuY+II8rIPzde4ifv/Yx1ai/W3UMNRxHnOBXjlhGEZ8mw== X-Received: by 2002:ac8:2c98:: with SMTP id 24-v6mr24226817qtw.420.1527018596126; Tue, 22 May 2018 12:49:56 -0700 (PDT) Subject: Re: [patch] Fix BZ 23187 -- stack overflow for many Phdr[]s To: libc-alpha@sourceware.org References: From: Adhemerval Zanella Openpgp: preference=signencrypt Autocrypt: addr=adhemerval.zanella@linaro.org; prefer-encrypt=mutual; keydata= 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 Message-ID: Date: Tue, 22 May 2018 16:49:50 -0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0 MIME-Version: 1.0 In-Reply-To: On 21/05/2018 17:34, Paul Pluzhnikov wrote: > Greetings, > > Attached patch fixes several instances of unconstrained stack allocation, > which causes ld.so to overflow stack and crash while processing DSO with > 1000s of Phdr[]s, and adds a test case. > > 2018-05-21 Paul Pluzhnikov > > [BZ #23187] > * elf/Makefile (tst-many-phdrs): New test. > * elf/tst-many-phdrs.c: New. > * elf/dl-load.c (_dl_map_object_from_fd): Constrain stack > allocation. Looks like the CL is mangled somehow, 'allocation' should be aligned with tab. > @@ -960,7 +966,18 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, > phdr = (void *) (fbp->buf + header->e_phoff); > else > { > - phdr = alloca (maplength); > + if (maplength < __MAX_ALLOCA_CUTOFF) > + phdr = alloca (maplength); > + else > + { > + phdr_malloced = malloc (maplength); > + if (phdr_malloced == NULL) > + { > + errstring = N_("cannot allocate memory for program header"); > + goto call_lose_errno; > + } > + phdr = phdr_malloced; > + } I think we should avoid use alloca in newer code in favor of current framework that tries to leverage this kind of behaviour (initial stack allocation with potential heap usage). They also have the advantage of avoid using __MAX_ALLOCA_CUTOFF, which is kind arbitrary and do not really address total stack usage over multiple function calls. What about use dynarray for this as below. The initial sizes are still arbitraty and should cover most common cases, but I do not have a strong opinion here (they have total stack usage of 384 bytes for loadcmd_list and 896 for phdr_list on 64 bits architectures). --- --- > __lseek (fd, header->e_phoff, SEEK_SET); > if ((size_t) __libc_read (fd, (void *) phdr, maplength) != maplength) > { > @@ -976,10 +993,24 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, > > { > /* Scan the program header table, collecting its load commands. */ > - struct loadcmd loadcmds[l->l_phnum]; > + struct loadcmd *loadcmds; > size_t nloadcmds = 0; > + const size_t loadcmds_size = sizeof (*loadcmds) * l->l_phnum; > bool has_holes = false; > > + if (loadcmds_size < __MAX_ALLOCA_CUTOFF) > + loadcmds = alloca (loadcmds_size); > + else > + { > + loadcmds_malloced = malloc (loadcmds_size); > + if (loadcmds_malloced == NULL) > + { > + errstring = N_("cannot allocate memory for program header"); > + goto call_lose_errno; > + } > + loadcmds = loadcmds_malloced; > + } > + > /* The struct is initialized to zero so this is not necessary: > l->l_ld = 0; > l->l_phdr = 0; > @@ -1126,6 +1157,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, > maplength, has_holes, loader); > if (__glibc_unlikely (errstring != NULL)) > goto call_lose; > + > + free (phdr_malloced); > + free (loadcmds_malloced); > + phdr_malloced = NULL; > + loadcmds_malloced = NULL; > } > > if (l->l_ld == 0) > @@ -1460,7 +1496,7 @@ open_verify (const char *name, int fd, > if (fd != -1) > { > ElfW(Ehdr) *ehdr; > - ElfW(Phdr) *phdr, *ph; > + ElfW(Phdr) *phdr, *ph, *phdr_malloced = NULL; > ElfW(Word) *abi_note; > ElfW(Word) *abi_note_malloced = NULL; > unsigned int osversion; > @@ -1596,7 +1632,18 @@ open_verify (const char *name, int fd, > phdr = (void *) (fbp->buf + ehdr->e_phoff); > else > { > - phdr = alloca (maplength); > + if (maplength < __MAX_ALLOCA_CUTOFF) > + phdr = alloca (maplength); > + else > + { > + phdr_malloced = malloc (maplength); > + if (phdr_malloced == NULL) > + { > + errstring = N_("cannot allocate memory for program header"); > + goto call_lose; > + } > + phdr = phdr_malloced; > + } > __lseek (fd, ehdr->e_phoff, SEEK_SET); > if ((size_t) __libc_read (fd, (void *) phdr, maplength) != maplength) > { > @@ -1687,6 +1734,7 @@ open_verify (const char *name, int fd, > > break; > } > + free (phdr_malloced); > free (abi_note_malloced); > } > > diff --git a/elf/tst-many-phdrs.c b/elf/tst-many-phdrs.c > new file mode 100644 > index 0000000000..ea8b0a4ec5 > --- /dev/null > +++ b/elf/tst-many-phdrs.c > @@ -0,0 +1,170 @@ > +/* Copyright (C) 2018 Free Software Foundation, Inc. Missing initial descriptive line. > + 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 > + . */ > + > +/* A test that generates DSO with 65535 Phdr[]s, and asks ld.so > + to list its dependencies (after adjusting stack limits). > + > + This is used to test for stack overflow in dl-load.c */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +static const char * > +get_ld_so (void) > +{ > + struct link_map *lm = _r_debug.r_map; > + while (lm != NULL) > + { > + if (lm->l_name != NULL && strstr (lm->l_name, "elf/ld") != NULL) > + return lm->l_name; > + lm = lm->l_next; > + } > + FAIL_EXIT1 ("Did not find ld.so"); > +} > + > +static const char * > +write_dso (void) > +{ > + ElfW(Ehdr) ehdr; > + ElfW(Phdr) phdr; > + ElfW(Dyn) dyn; > + const char *const ld_so = get_ld_so (); > + > + FILE *fp = fopen (ld_so, "rb"); > + if (fp == NULL) > + FAIL_EXIT1 ("fopen %s: %m", ld_so); > + > + /* Use Ehdr from ld.so so we don't have to depend on specific e_machine > + and e_ident[EI_DATA] -- we simply use the same values as ld.so. */ > + if (fread (&ehdr, sizeof (ehdr), 1, fp) != 1) > + FAIL_EXIT1 ("fread: %m"); > + fclose (fp); > + > + static char fname[] = "/tmp/tst-many-phdrs-XXXXXX"; > + int fd = mkstemp (fname); > + if (fd == -1) > + FAIL_EXIT1 ("mkstemp failed: %m"); > + > + fp = fdopen (fd, "wb"); > + if (fp == NULL) > + FAIL_EXIT1 ("fdopen failed: %m"); > + > + ehdr.e_phoff = sizeof (ehdr) + sizeof (dyn); > + ehdr.e_phentsize = sizeof (phdr); > + ehdr.e_phnum = 0xFFFF; /* Max possible number of Phdr[]s. */ > + > + if (1 != fwrite (&ehdr, sizeof (ehdr), 1, fp)) > + FAIL_EXIT1 ("fwrite ehdr: %m"); > + > + /* Write a single Dyn DT_NUL entry. That isn't enough to make this a > + valid DSO (dynstr and dynsym and hash are also necessary), but is enough > + to trigger stack overflow when listing its dependencies. */ > + memset (&dyn, 0, sizeof (dyn)); > + if (1 != fwrite (&dyn, sizeof (dyn), 1, fp)) > + FAIL_EXIT1 ("fwrite dyn: %m"); > + > + /* Add PT_DYNAMIC pointing to the Dyn entry we just wrote. */ > + memset (&phdr, 0, sizeof (phdr)); > + phdr.p_offset = sizeof (ehdr); > + phdr.p_vaddr = sizeof (ehdr); > + phdr.p_paddr = sizeof (ehdr); > + phdr.p_filesz = sizeof (dyn); > + phdr.p_memsz = sizeof (dyn); > + phdr.p_flags = PF_R; > + phdr.p_type = PT_DYNAMIC; > + > + if (1 != fwrite (&phdr, sizeof (phdr), 1, fp)) > + FAIL_EXIT1 ("fwrite phdr: %m"); > + > + /* Now the rest of Phdr[]s. */ > + memset (&phdr, 0, sizeof (phdr)); > + phdr.p_offset = 0; > + phdr.p_filesz = sizeof (ehdr); > + phdr.p_memsz = sizeof (ehdr); > + phdr.p_flags = PF_R; > + > + for (int j = 1; j < ehdr.e_phnum; j++) > + { > + /* At least one PT_LOAD is required. */ > + phdr.p_type = j == 1 ? PT_LOAD : PT_NOTE; > + if (1 != fwrite (&phdr, sizeof (phdr), 1, fp)) > + FAIL_EXIT1 ("fwrite phdr: %m"); > + } > + > + fclose (fp); > + return fname; > +} > + > +static int > +do_test (int argc, char *argv[]) > +{ > + const char *const dso = write_dso (); > + const char *const ld_so = get_ld_so (); > + struct rlimit rl; > + > + if (getrlimit (RLIMIT_STACK, &rl) == -1) > + FAIL_EXIT1 ("getrlimit (RLIMIT_STACK): %m"); > + > + char cmd[4 * 4096]; > + int n = snprintf (cmd, sizeof (cmd), "%s --list %s", ld_so, dso); > + if (n >= sizeof (cmd)) > + FAIL_EXIT1 ("buffer too small: need %d bytes", n); > + > + printf ("cmd: %s\n", cmd); > + > + if (rl.rlim_cur == RLIM_INFINITY) > + { > + printf ("Capping stack at 8MiB\n"); > + rl.rlim_cur = 8 << 20; > + } > + > + while (rl.rlim_cur >= 128 * 1024) > + { > + printf ("Stack size: %zu\n", (size_t) rl.rlim_cur); > + int rc = system (cmd); > + > + if (rc != 0) > + { > + /* Clean up. Comment this out to debug ld.so. */ > + unlink (dso); > + > + if (WIFEXITED (rc)) > + FAIL_EXIT1 ("child exited with %d", WEXITSTATUS (rc)); > + else if (WIFSIGNALED (rc)) > + FAIL_EXIT1 ("child exited with signal %d", WTERMSIG (rc)); > + else > + FAIL_EXIT1 ("child exited with rc %d", rc); > + } > + > + rl.rlim_cur /= 2; > + if (setrlimit (RLIMIT_STACK, &rl) == -1) > + FAIL_EXIT1 ("setrlimit: %m"); > + } > + > + unlink (dso); > + return 0; > +} > + > +#define TEST_FUNCTION_ARGV do_test > +#include > diff --git a/elf/dl-load.c b/elf/dl-load.c index 4312369..807cba6 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -792,6 +792,17 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l, _dl_signal_error (code, name, NULL, msg); } +#define DYNARRAY_STRUCT loadcmd_list +#define DYNARRAY_ELEMENT struct loadcmd +#define DYNARRAY_PREFIX loadcmd_list_ +#define DYNARRAY_INITIAL_SIZE 8 +#include + +#define DYNARRAY_STRUCT phdr_list +#define DYNARRAY_ELEMENT ElfW(Phdr) +#define DYNARRAY_PREFIX phdr_list_ +#define DYNARRAY_INITIAL_SIZE 16 +#include /* Map in the shared object NAME, actually located in REALNAME, and already opened on FD. */ @@ -809,6 +820,8 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, const ElfW(Ehdr) *header; const ElfW(Phdr) *phdr; const ElfW(Phdr) *ph; + struct loadcmd_list loadcmds; + struct phdr_list phdrlist; size_t maplength; int type; /* Initialize to keep the compiler happy. */ @@ -817,6 +830,9 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, struct r_debug *r = _dl_debug_initialize (0, nsid); bool make_consistent = false; + loadcmd_list_init (&loadcmds); + phdr_list_init (&phdrlist); + /* Get file information. */ struct r_file_id id; if (__glibc_unlikely (!_dl_get_file_id (fd, &id))) @@ -827,6 +843,8 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, call_lose: lose (errval, fd, name, realname, l, errstring, make_consistent ? r : NULL, nsid); + phdr_list_free (&phdrlist); + loadcmd_list_free (&loadcmds); } /* Look again to see if the real name matched another already loaded. */ @@ -960,7 +978,13 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, phdr = (void *) (fbp->buf + header->e_phoff); else { - phdr = alloca (maplength); + if (!phdr_list_resize (&phdrlist, header->e_phnum)) + { + errstring = N_("cannot allocate memory for program header"); + goto call_lose_errno; + } + phdr = phdr_list_begin (&phdrlist); + __lseek (fd, header->e_phoff, SEEK_SET); if ((size_t) __libc_read (fd, (void *) phdr, maplength) != maplength) { @@ -976,7 +1000,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, { /* Scan the program header table, collecting its load commands. */ - struct loadcmd loadcmds[l->l_phnum]; + if (!loadcmd_list_resize (&loadcmds, l->l_phnum)) + { + errstring = N_("cannot allocate memory for program header"); + goto call_lose_errno; + } size_t nloadcmds = 0; bool has_holes = false; @@ -1021,7 +1049,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, goto call_lose; } - struct loadcmd *c = &loadcmds[nloadcmds++]; + struct loadcmd *c = loadcmd_list_at (&loadcmds, nloadcmds++); c->mapstart = ALIGN_DOWN (ph->p_vaddr, GLRO(dl_pagesize)); c->mapend = ALIGN_UP (ph->p_vaddr + ph->p_filesz, GLRO(dl_pagesize)); c->dataend = ph->p_vaddr + ph->p_filesz; @@ -1116,16 +1144,21 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, } /* Length of the sections to be loaded. */ - maplength = loadcmds[nloadcmds - 1].allocend - loadcmds[0].mapstart; + const struct loadcmd *lc = loadcmd_list_at (&loadcmds, nloadcmds - 1); + const struct loadcmd *l0 = loadcmd_list_begin (&loadcmds); + maplength = lc->allocend - l0->mapstart; /* Now process the load commands and map segments into memory. This is responsible for filling in: l_map_start, l_map_end, l_addr, l_contiguous, l_text_end, l_phdr */ - errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds, + errstring = _dl_map_segments (l, fd, header, type, l0, nloadcmds, maplength, has_holes, loader); if (__glibc_unlikely (errstring != NULL)) goto call_lose; + + phdr_list_free (&phdrlist); + loadcmd_list_free (&loadcmds); } if (l->l_ld == 0) @@ -1463,9 +1496,12 @@ open_verify (const char *name, int fd, ElfW(Phdr) *phdr, *ph; ElfW(Word) *abi_note; ElfW(Word) *abi_note_malloced = NULL; + struct phdr_list phdrlist; unsigned int osversion; size_t maplength; + phdr_list_init (&phdrlist); + /* We successfully opened the file. Now verify it is a file we can use. */ __set_errno (0); @@ -1596,7 +1632,13 @@ open_verify (const char *name, int fd, phdr = (void *) (fbp->buf + ehdr->e_phoff); else { - phdr = alloca (maplength); + if (!phdr_list_resize (&phdrlist, ehdr->e_phnum)) + { + errstring = N_("cannot allocate memory for program header"); + goto call_lose; + } + phdr = phdr_list_begin (&phdrlist); + __lseek (fd, ehdr->e_phoff, SEEK_SET); if ((size_t) __libc_read (fd, (void *) phdr, maplength) != maplength) { @@ -1687,6 +1729,7 @@ open_verify (const char *name, int fd, break; } + phdr_list_free (&phdrlist); free (abi_note_malloced); } diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c index 25ceded..943a960 100644 --- a/elf/dl-minimal.c +++ b/elf/dl-minimal.c @@ -28,6 +28,7 @@ #include #include <_itoa.h> #include +#include #include @@ -191,6 +192,15 @@ __libc_fatal (const char *message) rtld_hidden_def (__libc_fatal) void +__libc_dynarray_at_failure (size_t size, size_t index) +{ + _dl_fatal_printf ("Fatal glibc error: " + "array index %zu not less than array length %zu\n", + index, size); +} +rtld_hidden_def (__libc_dynarray_at_failure) + +void __attribute__ ((noreturn)) __chk_fail (void) { diff --git a/malloc/dynarray.h b/malloc/dynarray.h index 0b171da..c4df88b 100644 --- a/malloc/dynarray.h +++ b/malloc/dynarray.h @@ -174,6 +174,7 @@ libc_hidden_proto (__libc_dynarray_resize) libc_hidden_proto (__libc_dynarray_resize_clear) libc_hidden_proto (__libc_dynarray_finalize) libc_hidden_proto (__libc_dynarray_at_failure) +rtld_hidden_proto (__libc_dynarray_at_failure) #endif #endif /* _DYNARRAY_H */