From 9fe6594da91e86280c9d71877a91cee83aaedae6 Mon Sep 17 00:00:00 2001 Message-Id: <9fe6594da91e86280c9d71877a91cee83aaedae6.1566225007.git.aquini@redhat.com> In-Reply-To: References: From: Sandipan Das Date: Wed, 12 Jun 2019 12:34:30 +0530 Subject: [RHEL7 PATCH 13/31] elflink: Fix program header address calculation This fixes the virtual address calculation for the ELF program header. Based on the man page of dl_iterate_phdr(), the location of a particular program header in virtual memory should be the sum of the base address of the shared object and the segment's virtual address. Signed-off-by: Sandipan Das Signed-off-by: Eric B Munson Signed-off-by: Rafael Aquini --- elflink.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/elflink.c b/elflink.c index ffc84dd..1150bde 100644 --- a/elflink.c +++ b/elflink.c @@ -374,7 +374,8 @@ static int get_shared_file_name(struct seg_info *htlb_seg_info, char *file_path) } /* Find the .dynamic program header */ -static int find_dynamic(Elf_Dyn **dyntab, const Elf_Phdr *phdr, int phnum) +static int find_dynamic(Elf_Dyn **dyntab, const ElfW(Addr) addr, + const Elf_Phdr *phdr, int phnum) { int i = 1; @@ -382,7 +383,7 @@ static int find_dynamic(Elf_Dyn **dyntab, const Elf_Phdr *phdr, int phnum) ++i; } if (phdr[i].p_type == PT_DYNAMIC) { - *dyntab = (Elf_Dyn *)phdr[i].p_vaddr; + *dyntab = (Elf_Dyn *)(addr + phdr[i].p_vaddr); return 0; } else { DEBUG("No dynamic segment found\n"); @@ -473,7 +474,8 @@ ElfW(Word) __attribute__ ((weak)) plt_extrasz(ElfW(Dyn) *dyntab) * include these initialized variables in our copy. */ -static void get_extracopy(struct seg_info *seg, const Elf_Phdr *phdr, int phnum) +static void get_extracopy(struct seg_info *seg, const ElfW(Addr) addr, + const Elf_Phdr *phdr, int phnum) { Elf_Dyn *dyntab; /* dynamic segment table */ Elf_Sym *symtab = NULL; /* dynamic symbol table */ @@ -492,7 +494,7 @@ static void get_extracopy(struct seg_info *seg, const Elf_Phdr *phdr, int phnum) goto bail2; /* Find dynamic program header */ - ret = find_dynamic(&dyntab, phdr, phnum); + ret = find_dynamic(&dyntab, addr, phdr, phnum); if (ret < 0) goto bail; @@ -608,7 +610,8 @@ static unsigned long hugetlb_prev_slice_end(unsigned long addr) /* * Store a copy of the given program header */ -static int save_phdr(int table_idx, int phnum, const ElfW(Phdr) *phdr) +static int save_phdr(int table_idx, int phnum, const ElfW(Addr) addr, + const ElfW(Phdr) *phdr) { int prot = 0; @@ -626,7 +629,7 @@ static int save_phdr(int table_idx, int phnum, const ElfW(Phdr) *phdr) if (phdr->p_flags & PF_X) prot |= PROT_EXEC; - htlb_seg_table[table_idx].vaddr = (void *) phdr->p_vaddr; + htlb_seg_table[table_idx].vaddr = (void *)(addr + phdr->p_vaddr); htlb_seg_table[table_idx].filesz = phdr->p_filesz; htlb_seg_table[table_idx].memsz = phdr->p_memsz; htlb_seg_table[table_idx].prot = prot; @@ -634,8 +637,8 @@ static int save_phdr(int table_idx, int phnum, const ElfW(Phdr) *phdr) INFO("Segment %d (phdr %d): %#0lx-%#0lx (filesz=%#0lx) " "(prot = %#0x)\n", table_idx, phnum, - (unsigned long) phdr->p_vaddr, - (unsigned long) phdr->p_vaddr + phdr->p_memsz, + (unsigned long) addr + phdr->p_vaddr, + (unsigned long) addr + phdr->p_vaddr + phdr->p_memsz, (unsigned long) phdr->p_filesz, (unsigned int) prot); return 0; @@ -718,16 +721,19 @@ int parse_elf_normal(struct dl_phdr_info *info, size_t size, void *data) seg_psize = segment_requested_page_size(&info->dlpi_phdr[i]); if (seg_psize != page_size) { - if (save_phdr(htlb_num_segs, i, &info->dlpi_phdr[i])) + if (save_phdr(htlb_num_segs, i, info->dlpi_addr, + &info->dlpi_phdr[i])) return 1; get_extracopy(&htlb_seg_table[htlb_num_segs], - &info->dlpi_phdr[0], info->dlpi_phnum); + info->dlpi_addr, info->dlpi_phdr, + info->dlpi_phnum); htlb_seg_table[htlb_num_segs].page_size = seg_psize; htlb_num_segs++; } - start = ALIGN_DOWN(info->dlpi_phdr[i].p_vaddr, seg_psize); - end = ALIGN(info->dlpi_phdr[i].p_vaddr + - info->dlpi_phdr[i].p_memsz, seg_psize); + start = ALIGN_DOWN(info->dlpi_addr + + info->dlpi_phdr[i].p_vaddr, seg_psize); + end = ALIGN(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr + + info->dlpi_phdr[i].p_memsz, seg_psize); segments[num_segs].page_size = seg_psize; segments[num_segs].start = start; @@ -771,8 +777,9 @@ int parse_elf_partial(struct dl_phdr_info *info, size_t size, void *data) * in this forced way won't violate any contiguity * constraints. */ - vaddr = hugetlb_next_slice_start(info->dlpi_phdr[i].p_vaddr); - gap = vaddr - info->dlpi_phdr[i].p_vaddr; + vaddr = hugetlb_next_slice_start(info->dlpi_addr + + info->dlpi_phdr[i].p_vaddr); + gap = vaddr - (info->dlpi_addr + info->dlpi_phdr[i].p_vaddr); slice_end = hugetlb_slice_end(vaddr); /* * we should stop remapping just before the slice @@ -795,7 +802,8 @@ int parse_elf_partial(struct dl_phdr_info *info, size_t size, void *data) } memsz = hugetlb_prev_slice_end(vaddr + memsz) - vaddr; - if (save_phdr(htlb_num_segs, i, &info->dlpi_phdr[i])) + if (save_phdr(htlb_num_segs, i, info->dlpi_addr, + &info->dlpi_phdr[i])) return 1; /* -- 1.8.3.1