summaryrefslogtreecommitdiffstats
path: root/libelf
diff options
context:
space:
mode:
authorMark Wielaard <[email protected]>2018-08-12 15:35:18 +0200
committerMark Wielaard <[email protected]>2018-09-13 14:25:22 +0200
commitfb0457f4671e7e0f8331453348005ed6beab275e (patch)
tree5efa18a7afd9543e644e4e2ab2b14a4d9f887498 /libelf
parenta1e892e920bbde60a9daa1f98c105c227ee7427d (diff)
libelf: Fix some issues with ELF_C_RDWR_MMAP.
When ELF_C_RDWR_MMAP is used libelf might have to write overlapping memory when moving the section data or headers. Make sure to use memmove, not memcpy. Also the size of the underlying file might have to change. That means we will have to also extend the mmap region with mremap. Since we are using direct pointers into the mmapped area we cannot move the mmap, only extend it. This might still fail if there is not enough free memory available to extend the mmap region. Two new test programs have been added. elfcopy which copies a whole elf file (using either ELF_C_WRITE or ELF_C_WRITE_MMAP). And addsections which adds new sections to an existing ELF file (using either ELF_C_RDWR or ELF_C_RDWR_MMAP). The newly added test will fail under valgrind without the fixes. Signed-off-by: Mark Wielaard <[email protected]>
Diffstat (limited to 'libelf')
-rw-r--r--libelf/ChangeLog6
-rw-r--r--libelf/elf32_updatefile.c10
-rw-r--r--libelf/elf_update.c30
3 files changed, 35 insertions, 11 deletions
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 7c884b00..35421222 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,9 @@
+2018-09-12 Mark Wielaard <[email protected]>
+
+ * elf32_updatefile.c (updatemmap): Use memmove, not memcpy.
+ * elf_update.c (write_file): Try to mremap if file needs to be
+ extended.
+
2018-08-18 Mark Wielaard <[email protected]>
* libelf.h (elf_compress_gnu): Add documentation about
diff --git a/libelf/elf32_updatefile.c b/libelf/elf32_updatefile.c
index 7ac99510..545ce083 100644
--- a/libelf/elf32_updatefile.c
+++ b/libelf/elf32_updatefile.c
@@ -203,7 +203,7 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
}
else
- memcpy (elf->map_address + elf->start_offset + ehdr->e_phoff,
+ memmove (elf->map_address + elf->start_offset + ehdr->e_phoff,
elf->state.ELFW(elf,LIBELFBITS).phdr,
sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
@@ -371,9 +371,11 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
last_position += dl->data.d.d_size;
}
else if (dl->data.d.d_size != 0)
- last_position = mempcpy (last_position,
- dl->data.d.d_buf,
- dl->data.d.d_size);
+ {
+ memmove (last_position, dl->data.d.d_buf,
+ dl->data.d.d_size);
+ last_position += dl->data.d.d_size;
+ }
scn_changed = true;
}
diff --git a/libelf/elf_update.c b/libelf/elf_update.c
index 8ce07829..36997c2b 100644
--- a/libelf/elf_update.c
+++ b/libelf/elf_update.c
@@ -93,13 +93,29 @@ write_file (Elf *elf, off_t size, int change_bo, size_t shnum)
ENOSPC. Otherwise we ignore the error and treat it as just hint. */
if (elf->parent == NULL
&& (elf->maximum_size == ~((size_t) 0)
- || (size_t) size > elf->maximum_size)
- && unlikely (posix_fallocate (elf->fildes, 0, size) != 0))
- if (errno == ENOSPC)
- {
- __libelf_seterrno (ELF_E_WRITE_ERROR);
- return -1;
- }
+ || (size_t) size > elf->maximum_size))
+ {
+ if (unlikely (posix_fallocate (elf->fildes, 0, size) != 0))
+ if (errno == ENOSPC)
+ {
+ __libelf_seterrno (ELF_E_WRITE_ERROR);
+ return -1;
+ }
+
+ /* Extend the mmap address if needed. */
+ if (elf->cmd == ELF_C_RDWR_MMAP
+ && (size_t) size > elf->maximum_size)
+ {
+ if (mremap (elf->map_address, elf->maximum_size,
+ size, 0) == MAP_FAILED)
+ {
+ __libelf_seterrno (ELF_E_WRITE_ERROR);
+ return -1;
+ }
+ elf->maximum_size = size;
+ }
+
+ }
/* The file is mmaped. */
if ((class == ELFCLASS32