From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ua1-x92c.google.com (mail-ua1-x92c.google.com [IPv6:2607:f8b0:4864:20::92c]) by sourceware.org (Postfix) with ESMTPS id 3A719385800C for ; Fri, 19 Nov 2021 17:06:38 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 3A719385800C Received: by mail-ua1-x92c.google.com with SMTP id b17so22690626uas.0 for ; Fri, 19 Nov 2021 09:06:38 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:date:mime-version:user-agent:subject :content-language:to:cc:references:from:in-reply-to :content-transfer-encoding; bh=a46fZdqhAke5nHkLsmW2+fGWsH+4KizdUcGdPT/K+5E=; b=jt3zzqU6aS6412r8e+qFe3GuIfDqhsGZ8U0l79C+X7B4dzldIVF45O+QNerB08gwMW NoO4QNeQDidAF5zgo2aY+oSuK52NZDXTItj4dKSlk7hQzsMZJL1+7EiHp5VEv+gXkx3E eFiie7Q12lDkD364gESRNLVFQL0wC5oo56zj22p2MrkvvnL2L64QRmiVEMqoOusYzKa+ 3/EueZeu14LF+kF0H+D5aW+hAyekBdPcaXp++D9h2UJicEa11aHQeOUiAyhNO44W3mnr ZvUCJtTEIYYyi20Pqt/HiLbddoZFbDIgny8nnsG+O03YT8mnRF5vkt/kFZPBTvEa5Bgq FMqQ== X-Gm-Message-State: AOAM5302Y75I66SFsWHfDkV6VTw/zo5sX03VIbF+WcKNUMrJ34Fnnto0 urped3BRCl+VzDJxhIALlNG0kA== X-Google-Smtp-Source: ABdhPJwA7rpyhWe9tmSNHBbUe1lpd2pIyXb0jbRXYlpwcJNrRxUIhzQxjQmLIUYbnGqPQ0p8FZqRqQ== X-Received: by 2002:ab0:3359:: with SMTP id h25mr50876388uap.59.1637341597283; Fri, 19 Nov 2021 09:06:37 -0800 (PST) Received: from ?IPV6:2804:431:c7ca:66dc:bc2c:d33d:22b3:25d7? ([2804:431:c7ca:66dc:bc2c:d33d:22b3:25d7]) by smtp.gmail.com with ESMTPSA id w2sm211585vsw.29.2021.11.19.09.06.35 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 19 Nov 2021 09:06:37 -0800 (PST) Message-ID: Date: Fri, 19 Nov 2021 14:06:34 -0300 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.3.1 Subject: Re: [PATCH] elf: Add elf checks for main executable Content-Language: en-US To: "H.J. Lu" Cc: GNU C Library , Florian Weimer References: <20211119150329.2200675-1-adhemerval.zanella@linaro.org> From: Adhemerval Zanella In-Reply-To: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, NICE_REPLY_A, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP 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, 19 Nov 2021 17:06:42 -0000 On 19/11/2021 13:05, H.J. Lu wrote: > On Fri, Nov 19, 2021 at 7:33 AM H.J. Lu wrote: >> >> On Fri, Nov 19, 2021 at 7:03 AM Adhemerval Zanella >> wrote: >>> >>> The ELF header integrity check is only done on open_verify(), i.e, >>> for objects explicitly loaded. For main executable (issued with >>> execve() for the binary) only kernel checks are done, which does >>> not check EI_ABIVERSION. >>> >>> To enable it, the loader needs to find where the ELF header is placed >>> at program start, however Linux auxiliary vectors only provides >> >> Is it possible to check __ehdr_start? > > Probably not. I added this to binutils master branch: I forgot about __ehdr_start, but at rtld.c context the __ehdr_start is the loader one (not really what we want). We might try to get the symbol from the main application (with the extra complication it is a hidden one), but since we already parse the programs headers it seems simpler to get from PT_LOAD. > > $ elfedit > ... > --output-abiversion [0-255] > Set output ABIVERSION > > Please use it for both executable and shared library tests. Is this really an improvement? It will need to either copy it to testroot along with all its depedencies and/or make multiples copies, elfedit them, and copy them on testroot. It seems that edit the ELF directly seem simpler, since it is only the header that require adjustments. > >>> the program header table (AT_EHDR). To avoid require upstream >>> kernel support, the ELF header is implicitly obtained from the PT_LOAD >>> values by checking for a segment with offset 0 and memory size >>> different than 0 (For Linux it is start the ELF file issued by >>> execve()). >>> >>> Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. >>> --- >>> elf/Makefile | 8 +- >>> elf/dl-check-err.h | 14 ++ >>> elf/dl-check.c | 151 ++++++++++++++++++ >>> elf/dl-check.h | 45 ++++++ >>> elf/dl-load.c | 114 ++------------ >>> elf/rtld.c | 8 + >>> elf/tst-elf-check.c | 209 +++++++++++++++++++++++++ >>> sysdeps/generic/dl-elf-check.h | 28 ++++ >>> sysdeps/unix/sysv/linux/dl-elf-check.h | 32 ++++ >>> 9 files changed, 507 insertions(+), 102 deletions(-) >>> create mode 100644 elf/dl-check-err.h >>> create mode 100644 elf/dl-check.c >>> create mode 100644 elf/dl-check.h >>> create mode 100644 elf/tst-elf-check.c >>> create mode 100644 sysdeps/generic/dl-elf-check.h >>> create mode 100644 sysdeps/unix/sysv/linux/dl-elf-check.h >>> >>> diff --git a/elf/Makefile b/elf/Makefile >>> index 4723c159cb..f09fc5c6ec 100644 >>> --- a/elf/Makefile >>> +++ b/elf/Makefile >>> @@ -36,7 +36,8 @@ dl-routines = $(addprefix dl-,load lookup object reloc deps \ >>> exception sort-maps lookup-direct \ >>> call-libc-early-init write \ >>> thread_gscope_wait tls_init_tp \ >>> - debug-symbols minimal-malloc) >>> + debug-symbols minimal-malloc \ >>> + check) >>> ifeq (yes,$(use-ldconfig)) >>> dl-routines += dl-cache >>> endif >>> @@ -238,7 +239,8 @@ tests-internal += loadtest unload unload2 circleload1 \ >>> tst-ptrguard1 tst-stackguard1 \ >>> tst-create_format1 tst-tls-surplus tst-dl-hwcaps_split >>> tests-container += tst-pldd tst-dlopen-tlsmodid-container \ >>> - tst-dlopen-self-container tst-preload-pthread-libc >>> + tst-dlopen-self-container tst-preload-pthread-libc \ >>> + tst-elf-check >>> test-srcs = tst-pathopt >>> selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null) >>> ifneq ($(selinux-enabled),1) >>> @@ -494,6 +496,8 @@ tests-special += $(objpfx)order-cmp.out $(objpfx)tst-array1-cmp.out \ >>> $(objpfx)tst-unused-dep-cmp.out >>> endif >>> >>> +tst-elf-check-ARGS = -- $(host-test-program-cmd) >>> + >>> ifndef avoid-generated >>> # DSO sorting tests: >>> # The dso-ordering-test.py script generates testcase source files in $(objpfx), >>> diff --git a/elf/dl-check-err.h b/elf/dl-check-err.h >>> new file mode 100644 >>> index 0000000000..6ca5246eb8 >>> --- /dev/null >>> +++ b/elf/dl-check-err.h >>> @@ -0,0 +1,14 @@ >>> +_S(DL_ELFHDR_OK, "") >>> +_S(DL_ELFHDR_ERR_ELFMAG, N_("invalid ELF header")) >>> +_S(DL_ELFHDR_ERR_CLASS32, N_("wrong ELF class: ELFCLASS32")) >>> +_S(DL_ELFHDR_ERR_CLASS64, N_("wrong ELF class: ELFCLASS64")) >>> +_S(DL_ELFHDR_ERR_BENDIAN, N_("ELF file data encoding not big-endian")) >>> +_S(DL_ELFHDR_ERR_LENDIAN, N_("ELF file data encoding not little-endian")) >>> +_S(DL_ELFHDR_ERR_EIVERSION, N_("ELF file version ident does not match current one")) >>> +_S(DL_ELFHDR_ERR_OSABI, N_("ELF file OS ABI invalid")) >>> +_S(DL_ELFHDR_ERR_ABIVERSION, N_("ELF file ABI version invalid")) >>> +_S(DL_ELFHDR_ERR_PAD, N_("nonzero padding in e_ident")) >>> +_S(DL_ELFHDR_ERR_VERSION, N_("ELF file version does not match current one")) >>> +_S(DL_ELFHDR_ERR_TYPE, N_("only ET_DYN and ET_EXEC can be loaded")) >>> +_S(DL_ELFHDR_ERR_PHENTSIZE, N_("ELF file's phentsize not the expected size")) >>> +_S(DL_ELFHDR_ERR_INTERNAL, N_("internal error")) >>> diff --git a/elf/dl-check.c b/elf/dl-check.c >>> new file mode 100644 >>> index 0000000000..ef1720df2a >>> --- /dev/null >>> +++ b/elf/dl-check.c >>> @@ -0,0 +1,151 @@ >>> +/* ELF header consistency and ABI checks. >>> + Copyright (C) 1995-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 >>> + . */ >>> + >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> + >>> +int >>> +_dl_elfhdr_check (const ElfW(Ehdr) *ehdr) >>> +{ >>> +#define ELF32_CLASS ELFCLASS32 >>> +#define ELF64_CLASS ELFCLASS64 >>> +#if BYTE_ORDER == BIG_ENDIAN >>> +# define byteorder ELFDATA2MSB >>> +#elif BYTE_ORDER == LITTLE_ENDIAN >>> +# define byteorder ELFDATA2LSB >>> +#else >>> +# error "Unknown BYTE_ORDER " BYTE_ORDER >>> +# define byteorder ELFDATANONE >>> +#endif >>> + MORE_ELF_HEADER_DATA; >>> + static const unsigned char expected[EI_NIDENT] = >>> + { >>> + [EI_MAG0] = ELFMAG0, >>> + [EI_MAG1] = ELFMAG1, >>> + [EI_MAG2] = ELFMAG2, >>> + [EI_MAG3] = ELFMAG3, >>> + [EI_CLASS] = ELFW(CLASS), >>> + [EI_DATA] = byteorder, >>> + [EI_VERSION] = EV_CURRENT, >>> + [EI_OSABI] = ELFOSABI_SYSV, >>> + [EI_ABIVERSION] = 0 >>> + }; >>> + >>> + /* See whether the ELF header is what we expect. */ >>> + if (__glibc_unlikely (! VALID_ELF_HEADER (ehdr->e_ident, expected, >>> + EI_ABIVERSION) >>> + || !VALID_ELF_ABIVERSION (ehdr->e_ident[EI_OSABI], >>> + ehdr->e_ident[EI_ABIVERSION]) >>> + || memcmp (&ehdr->e_ident[EI_PAD], >>> + &expected[EI_PAD], >>> + EI_NIDENT - EI_PAD) != 0)) >>> + { >>> + /* Something is wrong. */ >>> + const Elf32_Word *magp = (const void *) ehdr->e_ident; >>> + if (*magp != >>> +#if BYTE_ORDER == LITTLE_ENDIAN >>> + ((ELFMAG0 << (EI_MAG0 * 8)) >>> + | (ELFMAG1 << (EI_MAG1 * 8)) >>> + | (ELFMAG2 << (EI_MAG2 * 8)) >>> + | (ELFMAG3 << (EI_MAG3 * 8))) >>> +#else >>> + ((ELFMAG0 << (EI_MAG3 * 8)) >>> + | (ELFMAG1 << (EI_MAG2 * 8)) >>> + | (ELFMAG2 << (EI_MAG1 * 8)) >>> + | (ELFMAG3 << (EI_MAG0 * 8))) >>> +#endif >>> + ) >>> + return DL_ELFHDR_ERR_ELFMAG; >>> + else if (ehdr->e_ident[EI_CLASS] != ELFW(CLASS)) >>> + return ELFW(CLASS) == ELFCLASS32 >>> + ? DL_ELFHDR_ERR_CLASS64 >>> + : DL_ELFHDR_ERR_CLASS32; >>> + else if (ehdr->e_ident[EI_DATA] != byteorder) >>> + { >>> + if (BYTE_ORDER == BIG_ENDIAN) >>> + return DL_ELFHDR_ERR_BENDIAN; >>> + else >>> + return DL_ELFHDR_ERR_LENDIAN; >>> + } >>> + else if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) >>> + return DL_ELFHDR_ERR_EIVERSION; >>> + /* XXX We should be able so set system specific versions which are >>> + allowed here. */ >>> + else if (!VALID_ELF_OSABI (ehdr->e_ident[EI_OSABI])) >>> + return DL_ELFHDR_ERR_OSABI; >>> + else if (!VALID_ELF_ABIVERSION (ehdr->e_ident[EI_OSABI], >>> + ehdr->e_ident[EI_ABIVERSION])) >>> + return DL_ELFHDR_ERR_ABIVERSION; >>> + else if (memcmp (&ehdr->e_ident[EI_PAD], &expected[EI_PAD], >>> + EI_NIDENT - EI_PAD) != 0) >>> + return DL_ELFHDR_ERR_PAD; >>> + else >>> + return DL_ELFHDR_ERR_INTERNAL; >>> + } >>> + >>> + if (__glibc_unlikely (ehdr->e_version != EV_CURRENT)) >>> + return DL_ELFHDR_ERR_VERSION; >>> + else if (__glibc_unlikely (ehdr->e_type != ET_DYN >>> + && ehdr->e_type != ET_EXEC)) >>> + return DL_ELFHDR_ERR_TYPE; >>> + else if (__glibc_unlikely (ehdr->e_phentsize != sizeof (ElfW(Phdr)))) >>> + return DL_ELFHDR_ERR_PHENTSIZE; >>> + >>> + return DL_ELFHDR_OK; >>> +} >>> + >>> +static const union elfhdr_errstr_t >>> +{ >>> + struct >>> + { >>> +#define _S(n, s) char str##n[sizeof (s)]; >>> +#include "dl-check-err.h" >>> +#undef _S >>> + }; >>> + char str[0]; >>> +} elfhdr_errstr = >>> +{ >>> + { >>> +#define _S(n, s) s, >>> +#include "dl-check-err.h" >>> +#undef _S >>> + } >>> +}; >>> + >>> +static const unsigned short elfhder_erridx[] = >>> +{ >>> +#define _S(n, s) [n] = offsetof(union elfhdr_errstr_t, str##n), >>> +#include "dl-check-err.h" >>> +#undef _S >>> +}; >>> + >>> +const char * >>> +_dl_elfhdr_errstr (int err) >>> +{ >>> +#if 0 >>> + if (err >= 0 && err < array_length (elfhdr_errstr)) >>> + return elfhdr_errstr[err]; >>> + return NULL; >>> +#endif >>> + if (err < 0 || err >= array_length (elfhder_erridx)) >>> + err = 0; >>> + return elfhdr_errstr.str + elfhder_erridx[err]; >>> +} >>> diff --git a/elf/dl-check.h b/elf/dl-check.h >>> new file mode 100644 >>> index 0000000000..5104a353ed >>> --- /dev/null >>> +++ b/elf/dl-check.h >>> @@ -0,0 +1,45 @@ >>> +/* ELF header consistency and ABI checks. >>> + Copyright (C) 1995-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 >>> + . */ >>> + >>> +#ifndef _DL_OPENCHECK_H >>> +#define _DL_OPENCHECK_H >>> + >>> +#include >>> + >>> +enum >>> + { >>> + DL_ELFHDR_OK, >>> + DL_ELFHDR_ERR_ELFMAG, /* Invalid ELFMAGX value. */ >>> + DL_ELFHDR_ERR_CLASS32, /* Mismatched EI_CLASS. */ >>> + DL_ELFHDR_ERR_CLASS64, /* Mismatched EI_CLASS. */ >>> + DL_ELFHDR_ERR_BENDIAN, /* Mismatched EI_DATA (not big-endian). */ >>> + DL_ELFHDR_ERR_LENDIAN, /* Mismatched EI_DATA (not little-endian). */ >>> + DL_ELFHDR_ERR_EIVERSION, /* Invalid EI_VERSION. */ >>> + DL_ELFHDR_ERR_OSABI, /* Invalid EI_OSABI. */ >>> + DL_ELFHDR_ERR_ABIVERSION, /* Invalid ABI vrsion. */ >>> + DL_ELFHDR_ERR_PAD, /* Invalid EI_PAD value. */ >>> + DL_ELFHDR_ERR_VERSION, /* Invalid e_version. */ >>> + DL_ELFHDR_ERR_TYPE, /* Invalid e_type. */ >>> + DL_ELFHDR_ERR_PHENTSIZE, /* Invalid e_phentsize. */ >>> + DL_ELFHDR_ERR_INTERNAL /* Internal error. */ >>> + }; >>> + >>> +int _dl_elfhdr_check (const ElfW(Ehdr) *ehdr) attribute_hidden; >>> +const char *_dl_elfhdr_errstr (int err) attribute_hidden; >>> + >>> +#endif >>> diff --git a/elf/dl-load.c b/elf/dl-load.c >>> index bf8957e73c..45266c3501 100644 >>> --- a/elf/dl-load.c >>> +++ b/elf/dl-load.c >>> @@ -73,19 +73,9 @@ struct filebuf >>> #include >>> #include >>> #include >>> +#include >>> #include >>> >>> -#include >>> -#if BYTE_ORDER == BIG_ENDIAN >>> -# define byteorder ELFDATA2MSB >>> -#elif BYTE_ORDER == LITTLE_ENDIAN >>> -# define byteorder ELFDATA2LSB >>> -#else >>> -# error "Unknown BYTE_ORDER " BYTE_ORDER >>> -# define byteorder ELFDATANONE >>> -#endif >>> - >>> -#define STRING(x) __STRING (x) >>> >>> >>> int __stack_prot attribute_hidden attribute_relro >>> @@ -1598,25 +1588,6 @@ open_verify (const char *name, int fd, >>> /* This is the expected ELF header. */ >>> #define ELF32_CLASS ELFCLASS32 >>> #define ELF64_CLASS ELFCLASS64 >>> -#ifndef VALID_ELF_HEADER >>> -# define VALID_ELF_HEADER(hdr,exp,size) (memcmp (hdr, exp, size) == 0) >>> -# define VALID_ELF_OSABI(osabi) (osabi == ELFOSABI_SYSV) >>> -# define VALID_ELF_ABIVERSION(osabi,ver) (ver == 0) >>> -#elif defined MORE_ELF_HEADER_DATA >>> - MORE_ELF_HEADER_DATA; >>> -#endif >>> - static const unsigned char expected[EI_NIDENT] = >>> - { >>> - [EI_MAG0] = ELFMAG0, >>> - [EI_MAG1] = ELFMAG1, >>> - [EI_MAG2] = ELFMAG2, >>> - [EI_MAG3] = ELFMAG3, >>> - [EI_CLASS] = ELFW(CLASS), >>> - [EI_DATA] = byteorder, >>> - [EI_VERSION] = EV_CURRENT, >>> - [EI_OSABI] = ELFOSABI_SYSV, >>> - [EI_ABIVERSION] = 0 >>> - }; >>> static const struct >>> { >>> ElfW(Word) vendorlen; >>> @@ -1709,83 +1680,26 @@ open_verify (const char *name, int fd, >>> } >>> >>> /* See whether the ELF header is what we expect. */ >>> - if (__glibc_unlikely (! VALID_ELF_HEADER (ehdr->e_ident, expected, >>> - EI_ABIVERSION) >>> - || !VALID_ELF_ABIVERSION (ehdr->e_ident[EI_OSABI], >>> - ehdr->e_ident[EI_ABIVERSION]) >>> - || memcmp (&ehdr->e_ident[EI_PAD], >>> - &expected[EI_PAD], >>> - EI_NIDENT - EI_PAD) != 0)) >>> + int err = _dl_elfhdr_check (ehdr); >>> + switch (err) >>> { >>> - /* Something is wrong. */ >>> - const Elf32_Word *magp = (const void *) ehdr->e_ident; >>> - if (*magp != >>> -#if BYTE_ORDER == LITTLE_ENDIAN >>> - ((ELFMAG0 << (EI_MAG0 * 8)) >>> - | (ELFMAG1 << (EI_MAG1 * 8)) >>> - | (ELFMAG2 << (EI_MAG2 * 8)) >>> - | (ELFMAG3 << (EI_MAG3 * 8))) >>> -#else >>> - ((ELFMAG0 << (EI_MAG3 * 8)) >>> - | (ELFMAG1 << (EI_MAG2 * 8)) >>> - | (ELFMAG2 << (EI_MAG1 * 8)) >>> - | (ELFMAG3 << (EI_MAG0 * 8))) >>> -#endif >>> - ) >>> - errstring = N_("invalid ELF header"); >>> - else if (ehdr->e_ident[EI_CLASS] != ELFW(CLASS)) >>> - { >>> - /* This is not a fatal error. On architectures where >>> - 32-bit and 64-bit binaries can be run this might >>> - happen. */ >>> - *found_other_class = true; >>> - goto close_and_out; >>> - } >>> - else if (ehdr->e_ident[EI_DATA] != byteorder) >>> - { >>> - if (BYTE_ORDER == BIG_ENDIAN) >>> - errstring = N_("ELF file data encoding not big-endian"); >>> - else >>> - errstring = N_("ELF file data encoding not little-endian"); >>> - } >>> - else if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) >>> - errstring >>> - = N_("ELF file version ident does not match current one"); >>> - /* XXX We should be able so set system specific versions which are >>> - allowed here. */ >>> - else if (!VALID_ELF_OSABI (ehdr->e_ident[EI_OSABI])) >>> - errstring = N_("ELF file OS ABI invalid"); >>> - else if (!VALID_ELF_ABIVERSION (ehdr->e_ident[EI_OSABI], >>> - ehdr->e_ident[EI_ABIVERSION])) >>> - errstring = N_("ELF file ABI version invalid"); >>> - else if (memcmp (&ehdr->e_ident[EI_PAD], &expected[EI_PAD], >>> - EI_NIDENT - EI_PAD) != 0) >>> - errstring = N_("nonzero padding in e_ident"); >>> - else >>> - /* Otherwise we don't know what went wrong. */ >>> - errstring = N_("internal error"); >>> + case DL_ELFHDR_OK: >>> + break; >>> >>> - goto lose; >>> - } >>> + case DL_ELFHDR_ERR_CLASS32: >>> + case DL_ELFHDR_ERR_CLASS64: >>> + /* This is not a fatal error. On architectures where 32-bit and >>> + 64-bit binaries can be run this might happen. */ >>> + *found_other_class = true; >>> + goto close_and_out; >>> >>> - if (__glibc_unlikely (ehdr->e_version != EV_CURRENT)) >>> - { >>> - errstring = N_("ELF file version does not match current one"); >>> + default: >>> + errstring = _dl_elfhdr_errstr (err); >>> goto lose; >>> } >>> + >>> if (! __glibc_likely (elf_machine_matches_host (ehdr))) >>> goto close_and_out; >>> - else if (__glibc_unlikely (ehdr->e_type != ET_DYN >>> - && ehdr->e_type != ET_EXEC)) >>> - { >>> - errstring = N_("only ET_DYN and ET_EXEC can be loaded"); >>> - goto lose; >>> - } >>> - else if (__glibc_unlikely (ehdr->e_phentsize != sizeof (ElfW(Phdr)))) >>> - { >>> - errstring = N_("ELF file's phentsize not the expected size"); >>> - goto lose; >>> - } >>> >>> maplength = ehdr->e_phnum * sizeof (ElfW(Phdr)); >>> if (ehdr->e_phoff + maplength <= (size_t) fbp->len) >>> diff --git a/elf/rtld.c b/elf/rtld.c >>> index 847141e21d..89b3157f31 100644 >>> --- a/elf/rtld.c >>> +++ b/elf/rtld.c >>> @@ -50,6 +50,7 @@ >>> #include >>> #include >>> #include >>> +#include >>> >>> #include >>> >>> @@ -1112,6 +1113,7 @@ dl_main (const ElfW(Phdr) *phdr, >>> ElfW(Addr) *user_entry, >>> ElfW(auxv_t) *auxv) >>> { >>> + const ElfW(Ehdr) *ehdr = NULL; >>> const ElfW(Phdr) *ph; >>> struct link_map *main_map; >>> size_t file_size; >>> @@ -1518,6 +1520,9 @@ dl_main (const ElfW(Phdr) *phdr, >>> ElfW(Addr) mapstart; >>> ElfW(Addr) allocend; >>> >>> + if (ph->p_offset == 0 && ph->p_memsz > 0) >>> + ehdr = (void *) ph->p_vaddr; >>> + >>> /* Remember where the main program starts in memory. */ >>> mapstart = (main_map->l_addr >>> + (ph->p_vaddr & ~(GLRO(dl_pagesize) - 1))); >>> @@ -1577,6 +1582,9 @@ dl_main (const ElfW(Phdr) *phdr, >>> break; >>> } >>> >>> + if (ehdr != NULL) >>> + _dl_check_ehdr (ehdr); >>> + >>> /* Adjust the address of the TLS initialization image in case >>> the executable is actually an ET_DYN object. */ >>> if (main_map->l_tls_initimage != NULL) >>> diff --git a/elf/tst-elf-check.c b/elf/tst-elf-check.c >>> new file mode 100644 >>> index 0000000000..175ba6fb5a >>> --- /dev/null >>> +++ b/elf/tst-elf-check.c >>> @@ -0,0 +1,209 @@ >>> +/* Check ELF header error paths. >>> + 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 >>> + . */ >>> + >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> + >>> +static char *spargv[6]; >>> +static char *tmpbin; >>> + >>> +static void >>> +do_prepare (int argc, char *argv[]) >>> +{ >>> + int fdin = xopen (argv[0], O_RDONLY | O_LARGEFILE, 0); >>> + struct stat64 st; >>> + xfstat (fdin, &st); >>> + int fdout = create_temp_file ("tst-elf-check-", &tmpbin); >>> + xfchmod (fdout, S_IXUSR | S_IRUSR | S_IWUSR); >>> + TEST_VERIFY_EXIT (fdout >= 0); >>> + xcopy_file_range (fdin, NULL, fdout, NULL, st.st_size, 0); >>> + xclose (fdin); >>> + xclose (fdout); >>> +} >>> + >>> +static void >>> +run_test_expect_failure (void (*modify)(ElfW(Ehdr) *), const char *errmsg) >>> +{ >>> + int fd = xopen (tmpbin, O_RDWR | O_LARGEFILE, 0); >>> + ElfW(Ehdr) orig_hdr; >>> + if (read (fd, &orig_hdr, sizeof (orig_hdr)) != sizeof (orig_hdr)) >>> + FAIL_EXIT1 ("read (%s): %m\n", tmpbin); >>> + ElfW(Ehdr) hdr = orig_hdr; >>> + modify (&hdr); >>> + if (lseek (fd, 0, SEEK_SET) != 0) >>> + FAIL_EXIT1 ("lseek: %m"); >>> + xwrite (fd, &hdr, sizeof (hdr)); >>> + xclose (fd); >>> + >>> + struct support_capture_subprocess proc = >>> + support_capture_subprogram (spargv[0], spargv); >>> + support_capture_subprocess_check (&proc, "tst-elf-check", 127, >>> + sc_allow_stderr); >>> + TEST_VERIFY (strstr (proc.err.buffer, errmsg) != NULL); >>> + support_capture_subprocess_free (&proc); >>> + >>> + /* Restore previous header. */ >>> + fd = xopen (tmpbin, O_RDWR | O_LARGEFILE, 0); >>> + xwrite (fd, &orig_hdr, sizeof (orig_hdr)); >>> + xclose (fd); >>> +} >>> + >>> +static void >>> +modify_mag (ElfW(Ehdr) *ehdr) >>> +{ >>> + ehdr->e_ident[EI_MAG0] = EI_MAG3; >>> + ehdr->e_ident[EI_MAG1] = EI_MAG2; >>> + ehdr->e_ident[EI_MAG2] = EI_MAG1; >>> + ehdr->e_ident[EI_MAG3] = EI_MAG0; >>> +} >>> + >>> +static void >>> +modify_class (ElfW(Ehdr) *ehdr) >>> +{ >>> + ehdr->e_ident[EI_CLASS] = ELFCLASSNONE; >>> +} >>> + >>> +static void >>> +modify_endian (ElfW(Ehdr) *ehdr) >>> +{ >>> + ehdr->e_ident[EI_DATA] = ELFDATANUM; >>> +} >>> + >>> +static void >>> +modify_eiversion (ElfW(Ehdr) *ehdr) >>> +{ >>> + ehdr->e_ident[EI_VERSION] = EV_CURRENT + 1; >>> +} >>> + >>> +static void >>> +modify_osabi (ElfW(Ehdr) *ehdr) >>> +{ >>> + ehdr->e_ident[EI_OSABI] = ELFOSABI_STANDALONE; >>> +} >>> + >>> +static void >>> +modify_abiversion (ElfW(Ehdr) *ehdr) >>> +{ >>> + ehdr->e_ident[EI_ABIVERSION] = LIBC_ABI_MAX; >>> +} >>> + >>> +static void >>> +modify_pad (ElfW(Ehdr) *ehdr) >>> +{ >>> + memset (&ehdr->e_ident[EI_PAD], 0xff, EI_NIDENT - EI_PAD); >>> +} >>> + >>> +static void >>> +modify_version (ElfW(Ehdr) *ehdr) >>> +{ >>> + ehdr->e_version = EV_NONE; >>> +} >>> + >>> +static void >>> +modify_type (ElfW(Ehdr) *ehdr) >>> +{ >>> + ehdr->e_type = ET_NONE; >>> +} >>> + >>> +static void >>> +modify_phentsize (ElfW(Ehdr) *ehdr) >>> +{ >>> + ehdr->e_phentsize = sizeof (ElfW(Phdr)) + 1; >>> +} >>> + >>> +static void >>> +do_test_kernel (void) >>> +{ >>> + run_test_expect_failure (modify_mag, >>> + "invalid ELF header"); >>> + run_test_expect_failure (modify_type, >>> + "only ET_DYN and ET_EXEC can be loaded"); >>> + run_test_expect_failure (modify_phentsize, >>> + "ELF file's phentsize not the expected size"); >>> + run_test_expect_failure (modify_class, >>> + "wrong ELF class"); >>> +} >>> + >>> +static void >>> +do_test_common (void) >>> +{ >>> + run_test_expect_failure (modify_endian, >>> + "ELF file data encoding not"); >>> + run_test_expect_failure (modify_eiversion, >>> + "ELF file version ident does not match current one"); >>> + run_test_expect_failure (modify_pad, >>> + "nonzero padding in e_ident"); >>> + run_test_expect_failure (modify_osabi, >>> + "ELF file OS ABI invalid"); >>> + run_test_expect_failure (modify_abiversion, >>> + "ELF file ABI version invalid"); >>> + run_test_expect_failure (modify_version, >>> + "ELF file version does not match current one"); >>> +} >>> + >>> +static int >>> +do_test (int argc, char *argv[]) >>> +{ >>> + /* We must have one or four parameters: >>> + + argv[0]: the application name >>> + + argv[1]: path for ld.so optional >>> + + argv[2]: "--library-path" optional >>> + + argv[3]: the library path optional >>> + + argv[4/1]: the application name */ >>> + >>> + bool hardpath = argc == 2; >>> + >>> + int i; >>> + for (i = 0; i < argc - 2; i++) >>> + spargv[i] = argv[i+1]; >>> + spargv[i++] = tmpbin; >>> + spargv[i++] = (char *) "--direct"; >>> + spargv[i] = NULL; >>> + >>> + /* Some fields are checked by the kernel results in a execve failure, so skip >>> + them for --enable-hardcoded-path-in-tests. */ >>> + if (!hardpath) >>> + do_test_kernel (); >>> + do_test_common (); >>> + >>> + /* Also run the tests without issuing the loader. */ >>> + if (hardpath) >>> + return 0; >>> + >>> + spargv[0] = tmpbin; >>> + spargv[1] = (char *) "--direct"; >>> + spargv[2] = NULL; >>> + >>> + do_test_common (); >>> + >>> + return 0; >>> +} >>> + >>> +#define PREPARE do_prepare >>> +#define TEST_FUNCTION_ARGV do_test >>> +#include >>> diff --git a/sysdeps/generic/dl-elf-check.h b/sysdeps/generic/dl-elf-check.h >>> new file mode 100644 >>> index 0000000000..48eb82e9e7 >>> --- /dev/null >>> +++ b/sysdeps/generic/dl-elf-check.h >>> @@ -0,0 +1,28 @@ >>> +/* ELF header consistency and ABI checks. >>> + 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 >>> + . */ >>> + >>> +#ifndef _DL_ELF_CHECK_H >>> +#define _DL_ELF_CHECK_H >>> + >>> +/* Called from the loader just after the program headers are processed. */ >>> +static inline void >>> +_dl_check_ehdr (const ElfW(Ehdr) *ehdr) >>> +{ >>> +} >>> + >>> +#endif >>> diff --git a/sysdeps/unix/sysv/linux/dl-elf-check.h b/sysdeps/unix/sysv/linux/dl-elf-check.h >>> new file mode 100644 >>> index 0000000000..9e4925c090 >>> --- /dev/null >>> +++ b/sysdeps/unix/sysv/linux/dl-elf-check.h >>> @@ -0,0 +1,32 @@ >>> +/* ELF header consistency and ABI checks. >>> + 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 >>> + . */ >>> + >>> +#ifndef _DL_ELF_CHECK_H >>> +#define _DL_ELF_CHECK_H >>> + >>> +#include >>> + >>> +static inline void >>> +_dl_check_ehdr (const ElfW(Ehdr) *ehdr) >>> +{ >>> + int err = _dl_elfhdr_check (ehdr); >>> + if (err != DL_ELFHDR_OK) >>> + _dl_fatal_printf ("program loading error: %s\n", _dl_elfhdr_errstr (err)); >>> +} >>> + >>> +#endif >>> -- >>> 2.32.0 >>> >> >> >> -- >> H.J. > > >