xref: /openbsd-src/lib/libelf/libelf_phdr.c (revision 63b9365298cb9b8f7a9d67494526f438709cd72a)
1a1b5ec25Sjsg /*-
2a1b5ec25Sjsg  * Copyright (c) 2006,2008 Joseph Koshy
3a1b5ec25Sjsg  * All rights reserved.
4a1b5ec25Sjsg  *
5a1b5ec25Sjsg  * Redistribution and use in source and binary forms, with or without
6a1b5ec25Sjsg  * modification, are permitted provided that the following conditions
7a1b5ec25Sjsg  * are met:
8a1b5ec25Sjsg  * 1. Redistributions of source code must retain the above copyright
9a1b5ec25Sjsg  *    notice, this list of conditions and the following disclaimer.
10a1b5ec25Sjsg  * 2. Redistributions in binary form must reproduce the above copyright
11a1b5ec25Sjsg  *    notice, this list of conditions and the following disclaimer in the
12a1b5ec25Sjsg  *    documentation and/or other materials provided with the distribution.
13a1b5ec25Sjsg  *
14a1b5ec25Sjsg  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15a1b5ec25Sjsg  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16a1b5ec25Sjsg  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17a1b5ec25Sjsg  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18a1b5ec25Sjsg  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19a1b5ec25Sjsg  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20a1b5ec25Sjsg  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21a1b5ec25Sjsg  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22a1b5ec25Sjsg  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23a1b5ec25Sjsg  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24a1b5ec25Sjsg  * SUCH DAMAGE.
25a1b5ec25Sjsg  */
26a1b5ec25Sjsg 
27a1b5ec25Sjsg #include <assert.h>
28a1b5ec25Sjsg #include <gelf.h>
29a1b5ec25Sjsg #include <libelf.h>
30a1b5ec25Sjsg #include <stdlib.h>
31a1b5ec25Sjsg 
32a1b5ec25Sjsg #include "_libelf.h"
33a1b5ec25Sjsg 
34*63b93652Sjsg ELFTC_VCSID("$Id: libelf_phdr.c,v 1.3 2020/05/18 06:46:23 jsg Exp $");
35a1b5ec25Sjsg 
36a1b5ec25Sjsg void *
_libelf_getphdr(Elf * e,int ec)37a1b5ec25Sjsg _libelf_getphdr(Elf *e, int ec)
38a1b5ec25Sjsg {
39a1b5ec25Sjsg 	size_t phnum;
40a1b5ec25Sjsg 	size_t fsz, msz;
41a1b5ec25Sjsg 	uint64_t phoff;
42a1b5ec25Sjsg 	Elf32_Ehdr *eh32;
43a1b5ec25Sjsg 	Elf64_Ehdr *eh64;
44a1b5ec25Sjsg 	void *ehdr, *phdr;
45a1b5ec25Sjsg 	_libelf_translator_function *xlator;
46a1b5ec25Sjsg 
47a1b5ec25Sjsg 	assert(ec == ELFCLASS32 || ec == ELFCLASS64);
48a1b5ec25Sjsg 
49a1b5ec25Sjsg 	if (e == NULL) {
50a1b5ec25Sjsg 		LIBELF_SET_ERROR(ARGUMENT, 0);
51a1b5ec25Sjsg 		return (NULL);
52a1b5ec25Sjsg 	}
53a1b5ec25Sjsg 
54a1b5ec25Sjsg 	if ((phdr = (ec == ELFCLASS32 ?
55a1b5ec25Sjsg 		 (void *) e->e_u.e_elf.e_phdr.e_phdr32 :
56a1b5ec25Sjsg 		 (void *) e->e_u.e_elf.e_phdr.e_phdr64)) != NULL)
57a1b5ec25Sjsg 		return (phdr);
58a1b5ec25Sjsg 
59a1b5ec25Sjsg 	/*
60a1b5ec25Sjsg 	 * Check the PHDR related fields in the EHDR for sanity.
61a1b5ec25Sjsg 	 */
62a1b5ec25Sjsg 
63a1b5ec25Sjsg 	if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
64a1b5ec25Sjsg 		return (NULL);
65a1b5ec25Sjsg 
66a1b5ec25Sjsg 	phnum = e->e_u.e_elf.e_nphdr;
67a1b5ec25Sjsg 
68a1b5ec25Sjsg 	if (ec == ELFCLASS32) {
69a1b5ec25Sjsg 		eh32      = (Elf32_Ehdr *) ehdr;
70a1b5ec25Sjsg 		phoff     = (uint64_t) eh32->e_phoff;
71a1b5ec25Sjsg 	} else {
72a1b5ec25Sjsg 		eh64      = (Elf64_Ehdr *) ehdr;
73a1b5ec25Sjsg 		phoff     = (uint64_t) eh64->e_phoff;
74a1b5ec25Sjsg 	}
75a1b5ec25Sjsg 
76a1b5ec25Sjsg 	fsz = gelf_fsize(e, ELF_T_PHDR, phnum, e->e_version);
77a1b5ec25Sjsg 
78a1b5ec25Sjsg 	assert(fsz > 0);
79a1b5ec25Sjsg 
80e219834fSjsg 	if (phoff + fsz < phoff) {	/* Numeric overflow. */
81e219834fSjsg 		LIBELF_SET_ERROR(HEADER, 0);
82e219834fSjsg 		return (NULL);
83e219834fSjsg 	}
84e219834fSjsg 
85a1b5ec25Sjsg 	if ((uint64_t) e->e_rawsize < (phoff + fsz)) {
86a1b5ec25Sjsg 		LIBELF_SET_ERROR(HEADER, 0);
87a1b5ec25Sjsg 		return (NULL);
88a1b5ec25Sjsg 	}
89a1b5ec25Sjsg 
90*63b93652Sjsg 	if ((msz = _libelf_msize(ELF_T_PHDR, ec, EV_CURRENT)) == 0)
91*63b93652Sjsg 		return (NULL);
92a1b5ec25Sjsg 
93a1b5ec25Sjsg 	if ((phdr = calloc(phnum, msz)) == NULL) {
94a1b5ec25Sjsg 		LIBELF_SET_ERROR(RESOURCE, 0);
95a1b5ec25Sjsg 		return (NULL);
96a1b5ec25Sjsg 	}
97a1b5ec25Sjsg 
98a1b5ec25Sjsg 	if (ec == ELFCLASS32)
99a1b5ec25Sjsg 		e->e_u.e_elf.e_phdr.e_phdr32 = phdr;
100a1b5ec25Sjsg 	else
101a1b5ec25Sjsg 		e->e_u.e_elf.e_phdr.e_phdr64 = phdr;
102a1b5ec25Sjsg 
103a1b5ec25Sjsg 
104a1b5ec25Sjsg 	xlator = _libelf_get_translator(ELF_T_PHDR, ELF_TOMEMORY, ec,
105a1b5ec25Sjsg 	    _libelf_elfmachine(e));
106a1b5ec25Sjsg 	(*xlator)(phdr, phnum * msz, e->e_rawfile + phoff, phnum,
107a1b5ec25Sjsg 	    e->e_byteorder != LIBELF_PRIVATE(byteorder));
108a1b5ec25Sjsg 
109a1b5ec25Sjsg 	return (phdr);
110a1b5ec25Sjsg }
111a1b5ec25Sjsg 
112a1b5ec25Sjsg void *
_libelf_newphdr(Elf * e,int ec,size_t count)113a1b5ec25Sjsg _libelf_newphdr(Elf *e, int ec, size_t count)
114a1b5ec25Sjsg {
115a1b5ec25Sjsg 	void *ehdr, *newphdr, *oldphdr;
116a1b5ec25Sjsg 	size_t msz;
117a1b5ec25Sjsg 
118a1b5ec25Sjsg 	if (e == NULL) {
119a1b5ec25Sjsg 		LIBELF_SET_ERROR(ARGUMENT, 0);
120a1b5ec25Sjsg 		return (NULL);
121a1b5ec25Sjsg 	}
122a1b5ec25Sjsg 
123a1b5ec25Sjsg 	if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) {
124a1b5ec25Sjsg 		LIBELF_SET_ERROR(SEQUENCE, 0);
125a1b5ec25Sjsg 		return (NULL);
126a1b5ec25Sjsg 	}
127a1b5ec25Sjsg 
128a1b5ec25Sjsg 	assert(e->e_class == ec);
129a1b5ec25Sjsg 	assert(ec == ELFCLASS32 || ec == ELFCLASS64);
130a1b5ec25Sjsg 	assert(e->e_version == EV_CURRENT);
131a1b5ec25Sjsg 
132*63b93652Sjsg 	if ((msz = _libelf_msize(ELF_T_PHDR, ec, e->e_version)) == 0)
133*63b93652Sjsg 		return (NULL);
134a1b5ec25Sjsg 
135a1b5ec25Sjsg 	newphdr = NULL;
136a1b5ec25Sjsg 	if (count > 0 && (newphdr = calloc(count, msz)) == NULL) {
137a1b5ec25Sjsg 		LIBELF_SET_ERROR(RESOURCE, 0);
138a1b5ec25Sjsg 		return (NULL);
139a1b5ec25Sjsg 	}
140a1b5ec25Sjsg 
141a1b5ec25Sjsg 	if (ec == ELFCLASS32) {
142a1b5ec25Sjsg 		if ((oldphdr = (void *) e->e_u.e_elf.e_phdr.e_phdr32) != NULL)
143a1b5ec25Sjsg 			free(oldphdr);
144a1b5ec25Sjsg 		e->e_u.e_elf.e_phdr.e_phdr32 = (Elf32_Phdr *) newphdr;
145a1b5ec25Sjsg 	} else {
146a1b5ec25Sjsg 		if ((oldphdr = (void *) e->e_u.e_elf.e_phdr.e_phdr64) != NULL)
147a1b5ec25Sjsg 			free(oldphdr);
148a1b5ec25Sjsg 		e->e_u.e_elf.e_phdr.e_phdr64 = (Elf64_Phdr *) newphdr;
149a1b5ec25Sjsg 	}
150a1b5ec25Sjsg 
151a1b5ec25Sjsg 	e->e_u.e_elf.e_nphdr = count;
152a1b5ec25Sjsg 
153a1b5ec25Sjsg 	elf_flagphdr(e, ELF_C_SET, ELF_F_DIRTY);
154a1b5ec25Sjsg 
155a1b5ec25Sjsg 	return (newphdr);
156a1b5ec25Sjsg }
157