From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS17314 8.43.84.0/22 X-Spam-Status: No, score=-3.7 required=3.0 tests=AWL,BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,MAILING_LIST_MULTI, PDS_RDNS_DYNAMIC_FP,RCVD_IN_DNSWL_MED,RDNS_DYNAMIC,SPF_HELO_PASS, SPF_PASS shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from sourceware.org (ip-8-43-85-97.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by dcvr.yhbt.net (Postfix) with ESMTPS id F0E351F9F4 for ; Fri, 19 Nov 2021 16:06:45 +0000 (UTC) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id EF733385BF85 for ; Fri, 19 Nov 2021 16:06:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org EF733385BF85 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1637338005; bh=JI6VfZ/Q6ySPsxnkAwHzFMuRUDmQCW2uVnEMHEdeGV8=; h=References:In-Reply-To:Date:Subject:To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=szg3wCZd7zc0GBCehH0AiXkEQloC0QLWYBUGDr/wmY089tRfDYG9UlWBNrcVV7wb+ vPfiEMindee1sekpSjIF1PT4aNsMZqFWcQW6uNSjTg5iP7DLi423hRD9bO01cyGRmN tgcArSl3uIbZMGZpoz6oHOtBpF40HUD+jKTfUNJs= 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 EB7B4385800C for ; Fri, 19 Nov 2021 16:06:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org EB7B4385800C Received: by mail-pj1-x1035.google.com with SMTP id p18-20020a17090ad31200b001a78bb52876so11331851pju.3 for ; Fri, 19 Nov 2021 08:06:21 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=JI6VfZ/Q6ySPsxnkAwHzFMuRUDmQCW2uVnEMHEdeGV8=; b=27ULfHMvDHnsGUQAkoVglNYsrkvhmRYg0E8unINAicVef6yz8K0+kxhxpXwRAdu80g BSaE3sO0dORVfZZgEeL9woU9euqvEGb3/q1hqKroSmJOk6zMyCh9Snt7QlTkjmGy14S2 1jDd4Jlk0IIjV3MelYoUY+eywnEcIjMdIEgkSIoqmZFcQHv7PFcUBQpJ4N69kbj7ckNZ DPLcJu6lxKx/Nry6BBzn/2PGJHu1PFT2Y8zRCne3RRAmp6BuvaGGi9mlkYQ+ixkji3ME IfQgK7XuRgN4crbbuE2qRmGFsDrgBfOaN2TTyl4hh2jMTwPN+LYPYZfoYAaNlG4dlC1K 7U/Q== X-Gm-Message-State: AOAM533Y8mOeLkXDh6YGE7drXziMcK+Js0bPUdSPo24k9/ZcTLp9otdi jvQl0teTQhkCrb8eSO96qNXtb2z/g017eLwCvvnhj5+Qcx8= X-Google-Smtp-Source: ABdhPJzPnBO10tL9EJU4LDytE8XUYsPyp0NNJde3OArhBQsvkGKRGBJZIgVczRzxcEh6j3W4gxCY2LdV2pfQxWNkKxM= X-Received: by 2002:a17:902:ced1:b0:141:e15d:49e0 with SMTP id d17-20020a170902ced100b00141e15d49e0mr78419967plg.27.1637337980643; Fri, 19 Nov 2021 08:06:20 -0800 (PST) MIME-Version: 1.0 References: <20211119150329.2200675-1-adhemerval.zanella@linaro.org> In-Reply-To: Date: Fri, 19 Nov 2021 08:05:44 -0800 Message-ID: Subject: Re: [PATCH] elf: Add elf checks for main executable To: Adhemerval Zanella Content-Type: text/plain; charset="UTF-8" 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: , From: "H.J. Lu via Libc-alpha" Reply-To: "H.J. Lu" Cc: Florian Weimer , GNU C Library Errors-To: libc-alpha-bounces+e=80x24.org@sourceware.org Sender: "Libc-alpha" 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: $ elfedit ... --output-abiversion [0-255] Set output ABIVERSION Please use it for both executable and shared library tests. > > 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. -- H.J.