[PATCH] elf: Add elf checks for main executable
Adhemerval Zanella
adhemerval.zanella@linaro.org
Fri Nov 19 15:03:29 GMT 2021
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
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+#include <dl-check.h>
+#include <endian.h>
+#include <ldsodefs.h>
+#include <libintl.h>
+
+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
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _DL_OPENCHECK_H
+#define _DL_OPENCHECK_H
+
+#include <link.h>
+
+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 <dl-machine-reject-phdr.h>
#include <dl-sysdep-open.h>
#include <dl-prop.h>
+#include <dl-check.h>
#include <not-cancel.h>
-#include <endian.h>
-#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 <gnu/lib-names.h>
#include <dl-tunables.h>
#include <get-dynamic-info.h>
+#include <dl-elf-check.h>
#include <assert.h>
@@ -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
+ <https://www.gnu.org/licenses/>. */
+
+#include <elf.h>
+#include <link.h>
+#include <libc-abis.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+#include <support/temp_file.h>
+
+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 <support/test-driver.c>
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
+ <https://www.gnu.org/licenses/>. */
+
+#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
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _DL_ELF_CHECK_H
+#define _DL_ELF_CHECK_H
+
+#include <dl-check.h>
+
+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
More information about the Libc-alpha
mailing list