Fix: erroneous computation of ELF in-memory size
authorAntoine Busque <abusque@efficios.com>
Mon, 9 May 2016 21:54:44 +0000 (17:54 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 10 May 2016 02:36:50 +0000 (22:36 -0400)
The current algorithm for computation of ELF in-memory size computed
values using the `p_align` field from program headers to align loaded
segments, when in fact `p_align` is only used to describe the
relationship between a segment's offset in the ELF file and its
virtual address once loaded in memory (`p_vaddr`), not the alignment
between segments. (Refer to the ELF specification version 1.1 at pages
2-2 and 2-8 for more details.)

This implementation instead uses the `p_memsz` and `p_vaddr` fields to
compute the highest virtual address of the executable, and uses the
difference from its base address as the in-memory size.

Signed-off-by: Antoine Busque <abusque@efficios.com>
include/lttng/ust-elf.h
liblttng-ust/lttng-ust-elf.c

index e9b0ac7b4e3ea22b86a53781b908f26f27749623..c4abee2dbf1158717cbb0fd0e91485a155965bcf 100644 (file)
@@ -77,6 +77,7 @@
                bswap((phdr).p_filesz); \
                bswap((phdr).p_memsz);  \
                bswap((phdr).p_align);  \
+               bswap((phdr).p_vaddr);  \
        } while (0)
 
 #define bswap_shdr(shdr)                   \
                (dst_phdr).p_filesz = (src_phdr).p_filesz;      \
                (dst_phdr).p_memsz = (src_phdr).p_memsz;        \
                (dst_phdr).p_align = (src_phdr).p_align;        \
+               (dst_phdr).p_vaddr = (src_phdr).p_vaddr;        \
        } while (0)
 
 #define copy_shdr(src_shdr, dst_shdr)                                  \
@@ -172,6 +174,7 @@ struct lttng_ust_elf_phdr {
        uint64_t p_filesz;
        uint64_t p_memsz;
        uint64_t p_align;
+       uint64_t p_vaddr;
 };
 
 struct lttng_ust_elf_shdr {
index 346545583c3a23b399b9a71911c59e5ded6bc387..c9d2b6b3c406dcb33a8a39dfaab51af7dbe39917 100644 (file)
@@ -354,7 +354,7 @@ void lttng_ust_elf_destroy(struct lttng_ust_elf *elf)
 int lttng_ust_elf_get_memsz(struct lttng_ust_elf *elf, uint64_t *memsz)
 {
        uint16_t i;
-       uint64_t _memsz = 0;
+       uint64_t low_addr = UINT64_MAX, high_addr = 0;
 
        if (!elf || !memsz) {
                goto error;
@@ -362,7 +362,6 @@ int lttng_ust_elf_get_memsz(struct lttng_ust_elf *elf, uint64_t *memsz)
 
        for (i = 0; i < elf->ehdr->e_phnum; ++i) {
                struct lttng_ust_elf_phdr *phdr;
-               uint64_t align;
 
                phdr = lttng_ust_elf_get_phdr(elf, i);
                if (!phdr) {
@@ -377,27 +376,19 @@ int lttng_ust_elf_get_memsz(struct lttng_ust_elf *elf, uint64_t *memsz)
                        goto next_loop;
                }
 
-               /*
-                * A p_align of 0 means no alignment, i.e. aligned to
-                * 1 byte.
-                */
-               align = phdr->p_align == 0 ? 1 : phdr->p_align;
-               /* Align the start of the segment. */
-               _memsz += offset_align(_memsz, align);
-               _memsz += phdr->p_memsz;
-               /*
-                * Add padding at the end of the segment, so it ends
-                * on a multiple of the align value (which usually
-                * means a page boundary). This makes the computation
-                * valid even in cases where p_align would change from
-                * one segment to the next.
-                */
-               _memsz += offset_align(_memsz, align);
+               low_addr = phdr->p_vaddr < low_addr ? phdr->p_vaddr : low_addr;
+               high_addr = phdr->p_vaddr + phdr->p_memsz > high_addr ?
+                               phdr->p_vaddr + phdr->p_memsz : high_addr;
        next_loop:
                free(phdr);
        }
 
-       *memsz = _memsz;
+       if (high_addr < low_addr) {
+               /* No PT_LOAD segments or corrupted data. */
+               goto error;
+       }
+
+       *memsz = high_addr - low_addr;
        return 0;
 error:
        return -1;
This page took 0.026308 seconds and 4 git commands to generate.