[PATCH] libelf: Treat elf_memory as if using ELF_C_READ_MMAP

Mark Wielaard mark@klomp.org
Thu Feb 1 14:38:58 GMT 2024


An Elf handle created through elf_memory was treated as if opened with
ELF_C_READ. Which means libelf believed it had read the memory itself
and could simply write to it if it wanted (because it wasn't mmaped
directly on top of a file). This causes issues when that memory was
actually read-only. Work around this by pretending the memory was
actually read with ELF_C_READ_MMAP (so directly readable, but not
writable).

Add extra tests to elfgetzdata to check using elf_memory with
read-only memory works as expected.

	  * libelf/elf_memory.c (elf_memory): Call
	  __libelf_read_mmaped_file with ELF_C_READ_MMAP.
	  * tests/elfgetzdata.c (main): Add new "mem" option.
	  * tests/run-elfgetzdata.sh: Also run all tests with new
	  "mem" option.

https://sourceware.org/bugzilla/show_bug.cgi?id=31225

Reported-by: Derek Bruening <bruening@google.com>
Signed-off-by: Mark Wielaard <mark@klomp.org>
---
 libelf/elf_memory.c      |  2 +-
 tests/elfgetzdata.c      | 70 +++++++++++++++++++++++++++---
 tests/run-elfgetzdata.sh | 92 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 158 insertions(+), 6 deletions(-)

diff --git a/libelf/elf_memory.c b/libelf/elf_memory.c
index a47f1d24..13d77cb7 100644
--- a/libelf/elf_memory.c
+++ b/libelf/elf_memory.c
@@ -46,5 +46,5 @@ elf_memory (char *image, size_t size)
       return NULL;
     }
 
-  return __libelf_read_mmaped_file (-1, image, 0, size, ELF_C_READ, NULL);
+  return __libelf_read_mmaped_file (-1, image, 0, size, ELF_C_READ_MMAP, NULL);
 }
diff --git a/tests/elfgetzdata.c b/tests/elfgetzdata.c
index 82afbe52..0af6c223 100644
--- a/tests/elfgetzdata.c
+++ b/tests/elfgetzdata.c
@@ -1,4 +1,5 @@
 /* Copyright (C) 2015 Red Hat, Inc.
+   Copyright (C) 2024 Mark J. Wielaard <mark@klomp.org>
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -18,16 +19,19 @@
 # include <config.h>
 #endif
 
+#include <assert.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <inttypes.h>
 #include <libelf.h>
+#include <errno.h>
 #include <gelf.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/mman.h>
 
 
 int
@@ -38,21 +42,62 @@ main (int argc, char *argv[])
 
   if (argc < 3
       || (strcmp (argv[1], "read") != 0
-          && strcmp (argv[1], "mmap") != 0))
+          && strcmp (argv[1], "mmap") != 0
+          && strcmp (argv[1], "mem") != 0))
     {
-      printf ("Usage: (read|mmap) files...\n");
+      printf ("Usage: (read|mmap|mem) files...\n");
       return -1;
     }
 
-  bool mmap = strcmp (argv[1], "mmap") == 0;
+  bool do_read = strcmp (argv[1], "read") == 0;
+  bool do_mmap = strcmp (argv[1], "mmap") == 0;
+  bool do_mem = strcmp (argv[1], "mem") == 0;
 
   elf_version (EV_CURRENT);
 
   for (cnt = 2; cnt < argc; ++cnt)
     {
       int fd = open (argv[cnt], O_RDONLY);
-
-      Elf *elf = elf_begin (fd, mmap ? ELF_C_READ_MMAP : ELF_C_READ, NULL);
+      void *map_address = NULL;
+      size_t map_size = 0;
+
+      Elf *elf;
+      if (do_read)
+	elf = elf_begin (fd, ELF_C_READ, NULL);
+      else if (do_mmap)
+	elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
+      else
+        {
+	  assert (do_mem);
+	  // We mmap the memory ourselves, explicitly PROT_READ only
+	  struct stat st;
+	  if (fstat (fd, &st) != 0)
+	    {
+	      printf ("%s cannot stat %s\n", argv[cnt], strerror (errno));
+	      result = 1;
+	      close (fd);
+	      continue;
+	    }
+	  map_size = st.st_size;
+	  map_address = mmap (NULL, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	  if (map_address == MAP_FAILED)
+	    {
+	      printf ("%s cannot mmap %s\n", argv[cnt], strerror (errno));
+	      result = 1;
+	      close (fd);
+	      continue;
+	    }
+	  if (map_size < EI_NIDENT
+	      || memcmp (map_address, ELFMAG, SELFMAG) != 0)
+	    {
+	      printf ("%s isn't an ELF file\n", argv[cnt]);
+	      result = 1;
+	      munmap (map_address, map_size);
+	      close (fd);
+	      continue;
+	    }
+	  elf = elf_memory (map_address, map_size);
+        }
       if (elf == NULL)
 	{
 	  printf ("%s not usable %s\n", argv[cnt], elf_errmsg (-1));
@@ -107,6 +152,21 @@ main (int argc, char *argv[])
 
       elf_end (elf);
       close (fd);
+
+      if (do_mem)
+        {
+          /* Make sure we can still get at the memory.  */
+	  if (memcmp (map_address, ELFMAG, SELFMAG) != 0)
+	    {
+	      printf ("%s isn't an ELF file anymore???\n", argv[cnt]);
+	      result = 1;
+	    }
+	  if (munmap (map_address, map_size) != 0)
+	    {
+	      printf ("%s cannot munmap %s\n", argv[cnt], strerror (errno));
+	      result = 1;
+	    }
+        }
     }
 
   return result;
diff --git a/tests/run-elfgetzdata.sh b/tests/run-elfgetzdata.sh
index e2df3081..7d3d1a5e 100755
--- a/tests/run-elfgetzdata.sh
+++ b/tests/run-elfgetzdata.sh
@@ -42,6 +42,17 @@ testrun_compare ${abs_top_builddir}/tests/elfgetzdata mmap testfile-zgnu64 <<\EO
 8: .strtab, NOT compressed
 EOF
 
+testrun_compare ${abs_top_builddir}/tests/elfgetzdata mem testfile-zgnu64 <<\EOF
+1: .text, NOT compressed
+2: .zdebug_aranges, GNU compressed, size: 60
+3: .zdebug_info, GNU compressed, size: aa
+4: .debug_abbrev, NOT compressed
+5: .zdebug_line, GNU compressed, size: 8d
+6: .shstrtab, NOT compressed
+7: .symtab, NOT compressed
+8: .strtab, NOT compressed
+EOF
+
 testfiles testfile-zgnu64be
 testrun_compare ${abs_top_builddir}/tests/elfgetzdata read testfile-zgnu64be <<\EOF
 1: .text, NOT compressed
@@ -67,6 +78,18 @@ testrun_compare ${abs_top_builddir}/tests/elfgetzdata mmap testfile-zgnu64be <<\
 9: .strtab, NOT compressed
 EOF
 
+testrun_compare ${abs_top_builddir}/tests/elfgetzdata mem testfile-zgnu64be <<\EOF
+1: .text, NOT compressed
+2: .eh_frame, NOT compressed
+3: .zdebug_aranges, GNU compressed, size: 60
+4: .zdebug_info, GNU compressed, size: 7e
+5: .debug_abbrev, NOT compressed
+6: .zdebug_line, GNU compressed, size: 8d
+7: .shstrtab, NOT compressed
+8: .symtab, NOT compressed
+9: .strtab, NOT compressed
+EOF
+
 testfiles testfile-zgabi64
 testrun_compare ${abs_top_builddir}/tests/elfgetzdata read testfile-zgabi64 <<\EOF
 1: .text, NOT compressed
@@ -90,6 +113,17 @@ testrun_compare ${abs_top_builddir}/tests/elfgetzdata mmap testfile-zgabi64 <<\E
 8: .strtab, NOT compressed
 EOF
 
+testrun_compare ${abs_top_builddir}/tests/elfgetzdata mem testfile-zgabi64 <<\EOF
+1: .text, NOT compressed
+2: .debug_aranges, ELF compressed, size: 60
+3: .debug_info, ELF compressed, size: aa
+4: .debug_abbrev, NOT compressed
+5: .debug_line, ELF compressed, size: 8d
+6: .shstrtab, NOT compressed
+7: .symtab, NOT compressed
+8: .strtab, NOT compressed
+EOF
+
 testfiles testfile-zgabi64be
 testrun_compare ${abs_top_builddir}/tests/elfgetzdata read testfile-zgabi64be <<\EOF
 1: .text, NOT compressed
@@ -115,6 +149,18 @@ testrun_compare ${abs_top_builddir}/tests/elfgetzdata mmap testfile-zgabi64be <<
 9: .strtab, NOT compressed
 EOF
 
+testrun_compare ${abs_top_builddir}/tests/elfgetzdata mem testfile-zgabi64be <<\EOF
+1: .text, NOT compressed
+2: .eh_frame, NOT compressed
+3: .debug_aranges, ELF compressed, size: 60
+4: .debug_info, ELF compressed, size: 7e
+5: .debug_abbrev, NOT compressed
+6: .debug_line, ELF compressed, size: 8d
+7: .shstrtab, NOT compressed
+8: .symtab, NOT compressed
+9: .strtab, NOT compressed
+EOF
+
 testfiles testfile-zgnu32
 testrun_compare ${abs_top_builddir}/tests/elfgetzdata read testfile-zgnu32 <<\EOF
 1: .text, NOT compressed
@@ -138,6 +184,17 @@ testrun_compare ${abs_top_builddir}/tests/elfgetzdata mmap testfile-zgnu32 <<\EO
 8: .strtab, NOT compressed
 EOF
 
+testrun_compare ${abs_top_builddir}/tests/elfgetzdata mem testfile-zgnu32 <<\EOF
+1: .text, NOT compressed
+2: .zdebug_aranges, GNU compressed, size: 40
+3: .zdebug_info, GNU compressed, size: 9a
+4: .debug_abbrev, NOT compressed
+5: .zdebug_line, GNU compressed, size: 85
+6: .shstrtab, NOT compressed
+7: .symtab, NOT compressed
+8: .strtab, NOT compressed
+EOF
+
 testfiles testfile-zgnu32be
 testrun_compare ${abs_top_builddir}/tests/elfgetzdata read testfile-zgnu32be <<\EOF
 1: .text, NOT compressed
@@ -163,6 +220,18 @@ testrun_compare ${abs_top_builddir}/tests/elfgetzdata mmap testfile-zgnu32be <<\
 9: .strtab, NOT compressed
 EOF
 
+testrun_compare ${abs_top_builddir}/tests/elfgetzdata mem testfile-zgnu32be <<\EOF
+1: .text, NOT compressed
+2: .eh_frame, NOT compressed
+3: .zdebug_aranges, GNU compressed, size: 40
+4: .zdebug_info, GNU compressed, size: 6e
+5: .debug_abbrev, NOT compressed
+6: .zdebug_line, GNU compressed, size: 85
+7: .shstrtab, NOT compressed
+8: .symtab, NOT compressed
+9: .strtab, NOT compressed
+EOF
+
 testfiles testfile-zgabi32
 testrun_compare ${abs_top_builddir}/tests/elfgetzdata read testfile-zgabi32 <<\EOF
 1: .text, NOT compressed
@@ -186,6 +255,17 @@ testrun_compare ${abs_top_builddir}/tests/elfgetzdata mmap testfile-zgabi32 <<\E
 8: .strtab, NOT compressed
 EOF
 
+testrun_compare ${abs_top_builddir}/tests/elfgetzdata mem testfile-zgabi32 <<\EOF
+1: .text, NOT compressed
+2: .debug_aranges, ELF compressed, size: 40
+3: .debug_info, ELF compressed, size: 9a
+4: .debug_abbrev, NOT compressed
+5: .debug_line, ELF compressed, size: 85
+6: .shstrtab, NOT compressed
+7: .symtab, NOT compressed
+8: .strtab, NOT compressed
+EOF
+
 testfiles testfile-zgabi32be
 testrun_compare ${abs_top_builddir}/tests/elfgetzdata read testfile-zgabi32be <<\EOF
 1: .text, NOT compressed
@@ -211,4 +291,16 @@ testrun_compare ${abs_top_builddir}/tests/elfgetzdata mmap testfile-zgabi32be <<
 9: .strtab, NOT compressed
 EOF
 
+testrun_compare ${abs_top_builddir}/tests/elfgetzdata mem testfile-zgabi32be <<\EOF
+1: .text, NOT compressed
+2: .eh_frame, NOT compressed
+3: .debug_aranges, ELF compressed, size: 40
+4: .debug_info, ELF compressed, size: 6e
+5: .debug_abbrev, NOT compressed
+6: .debug_line, ELF compressed, size: 85
+7: .shstrtab, NOT compressed
+8: .symtab, NOT compressed
+9: .strtab, NOT compressed
+EOF
+
 exit 0
-- 
2.43.0



More information about the Elfutils-devel mailing list