1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 1998 John D. Polstra
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#if !defined(IN_LIBDL) || defined(PIC)
30
31/*
32 * Linkage to services provided by the dynamic linker.
33 */
34#include <sys/types.h>
35#include <sys/mman.h>
36#include <machine/atomic.h>
37#include <dlfcn.h>
38#include <link.h>
39#include <stddef.h>
40#include <string.h>
41#include "namespace.h"
42#include <pthread.h>
43#include "un-namespace.h"
44#include "rtld.h"
45#include "libc_private.h"
46#include "reentrant.h"
47
48static const char sorry[] = "Service unavailable";
49
50void _rtld_thread_init(void *);
51void _rtld_atfork_pre(int *);
52void _rtld_atfork_post(int *);
53
54/*
55 * For ELF, the dynamic linker directly resolves references to its
56 * services to functions inside the dynamic linker itself.  These
57 * weak-symbol stubs are necessary so that "ld" won't complain about
58 * undefined symbols.  The stubs are executed only when the program is
59 * linked statically, or when a given service isn't implemented in the
60 * dynamic linker.  They must return an error if called, and they must
61 * be weak symbols so that the dynamic linker can override them.
62 */
63
64#pragma weak _rtld_error
65void
66_rtld_error(const char *fmt __unused, ...)
67{
68}
69
70#pragma weak dladdr
71int
72dladdr(const void *addr __unused, Dl_info *dlip __unused)
73{
74
75	_rtld_error(sorry);
76	return (0);
77}
78
79#pragma weak dlclose
80int
81dlclose(void *handle __unused)
82{
83
84	_rtld_error(sorry);
85	return (-1);
86}
87
88#pragma weak dlerror
89char *
90dlerror(void)
91{
92
93	return (__DECONST(char *, sorry));
94}
95
96#pragma weak dllockinit
97void
98dllockinit(void *context,
99    void *(*lock_create)(void *context) __unused,
100    void (*rlock_acquire)(void *lock) __unused,
101    void (*wlock_acquire)(void *lock) __unused,
102    void (*lock_release)(void *lock) __unused,
103    void (*lock_destroy)(void *lock) __unused,
104    void (*context_destroy)(void *context) __unused)
105{
106
107	if (context_destroy != NULL)
108		context_destroy(context);
109}
110
111#pragma weak dlopen
112void *
113dlopen(const char *name __unused, int mode __unused)
114{
115
116	_rtld_error(sorry);
117	return (NULL);
118}
119
120#pragma weak dlsym
121void *
122dlsym(void * __restrict handle __unused, const char * __restrict name __unused)
123{
124
125	_rtld_error(sorry);
126	return (NULL);
127}
128
129#pragma weak dlfunc
130dlfunc_t
131dlfunc(void * __restrict handle __unused, const char * __restrict name __unused)
132{
133
134	_rtld_error(sorry);
135	return (NULL);
136}
137
138#pragma weak dlvsym
139void *
140dlvsym(void * __restrict handle __unused, const char * __restrict name __unused,
141    const char * __restrict version __unused)
142{
143
144	_rtld_error(sorry);
145	return (NULL);
146}
147
148#pragma weak dlinfo
149int
150dlinfo(void * __restrict handle __unused, int request __unused,
151    void * __restrict p __unused)
152{
153
154	_rtld_error(sorry);
155	return (0);
156}
157
158#pragma weak _rtld_thread_init
159void
160_rtld_thread_init(void *li __unused)
161{
162
163	_rtld_error(sorry);
164}
165
166#ifndef IN_LIBDL
167static pthread_once_t dl_phdr_info_once = PTHREAD_ONCE_INIT;
168static struct dl_phdr_info phdr_info;
169#ifndef PIC
170static mutex_t dl_phdr_info_lock = MUTEX_INITIALIZER;
171#endif
172
173static void
174dl_init_phdr_info(void)
175{
176	Elf_Auxinfo *auxp;
177	unsigned int i;
178
179	for (auxp = __elf_aux_vector; auxp->a_type != AT_NULL; auxp++) {
180		switch (auxp->a_type) {
181		case AT_BASE:
182			phdr_info.dlpi_addr = (Elf_Addr)auxp->a_un.a_ptr;
183			break;
184		case AT_EXECPATH:
185			phdr_info.dlpi_name = (const char *)auxp->a_un.a_ptr;
186			break;
187		case AT_PHDR:
188			phdr_info.dlpi_phdr =
189			    (const Elf_Phdr *)auxp->a_un.a_ptr;
190			break;
191		case AT_PHNUM:
192			phdr_info.dlpi_phnum = (Elf_Half)auxp->a_un.a_val;
193			break;
194		}
195	}
196	for (i = 0; i < phdr_info.dlpi_phnum; i++) {
197		if (phdr_info.dlpi_phdr[i].p_type == PT_TLS) {
198			phdr_info.dlpi_tls_modid = 1;
199		}
200	}
201	phdr_info.dlpi_adds = 1;
202}
203#endif
204
205#pragma weak dl_iterate_phdr
206int
207dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *) __unused,
208    void *data __unused)
209{
210#if defined IN_LIBDL
211	return (0);
212#elif defined PIC
213	int (*r)(int (*)(struct dl_phdr_info *, size_t, void *), void *);
214
215	r = dlsym(RTLD_DEFAULT, "dl_iterate_phdr");
216	if (r == NULL)
217		return (0);
218	return (r(callback, data));
219#else
220	tls_index ti;
221	int ret;
222
223	__init_elf_aux_vector();
224	if (__elf_aux_vector == NULL)
225		return (1);
226	_once(&dl_phdr_info_once, dl_init_phdr_info);
227	ti.ti_module = 1;
228	ti.ti_offset = 0;
229	mutex_lock(&dl_phdr_info_lock);
230	phdr_info.dlpi_tls_data = __tls_get_addr(&ti);
231	ret = callback(&phdr_info, sizeof(phdr_info), data);
232	mutex_unlock(&dl_phdr_info_lock);
233	return (ret);
234#endif
235}
236
237#pragma weak fdlopen
238void *
239fdlopen(int fd __unused, int mode __unused)
240{
241
242	_rtld_error(sorry);
243	return (NULL);
244}
245
246#pragma weak _rtld_atfork_pre
247void
248_rtld_atfork_pre(int *locks __unused)
249{
250}
251
252#pragma weak _rtld_atfork_post
253void
254_rtld_atfork_post(int *locks __unused)
255{
256}
257
258#ifndef IN_LIBDL
259struct _rtld_addr_phdr_cb_data {
260	const void *addr;
261	struct dl_phdr_info *dli;
262};
263
264static int
265_rtld_addr_phdr_cb(struct dl_phdr_info *dli, size_t sz, void *arg)
266{
267	struct _rtld_addr_phdr_cb_data *rd;
268	const Elf_Phdr *ph;
269	unsigned i;
270
271	rd = arg;
272	for (i = 0; i < dli->dlpi_phnum; i++) {
273		ph = &dli->dlpi_phdr[i];
274		if (ph->p_type == PT_LOAD &&
275		    dli->dlpi_addr + ph->p_vaddr <= (uintptr_t)rd->addr &&
276		    (uintptr_t)rd->addr < dli->dlpi_addr + ph->p_vaddr +
277		    ph->p_memsz) {
278			memcpy(rd->dli, dli, sz);
279			return (1);
280		}
281	}
282	return (0);
283}
284#endif
285
286#pragma weak _rtld_addr_phdr
287int
288_rtld_addr_phdr(const void *addr __unused,
289    struct dl_phdr_info *phdr_info_a __unused)
290{
291#ifndef IN_LIBDL
292	struct _rtld_addr_phdr_cb_data rd;
293
294	rd.addr = addr;
295	rd.dli = phdr_info_a;
296	return (dl_iterate_phdr(_rtld_addr_phdr_cb, &rd));
297#else
298	return (0);
299#endif
300}
301
302#pragma weak _rtld_get_stack_prot
303int
304_rtld_get_stack_prot(void)
305{
306#ifndef IN_LIBDL
307	unsigned i;
308	int r;
309	static int ret;
310
311	r = atomic_load_int(&ret);
312	if (r != 0)
313		return (r);
314
315	_once(&dl_phdr_info_once, dl_init_phdr_info);
316	r = PROT_EXEC | PROT_READ | PROT_WRITE;
317	for (i = 0; i < phdr_info.dlpi_phnum; i++) {
318		if (phdr_info.dlpi_phdr[i].p_type != PT_GNU_STACK)
319			continue;
320		r = PROT_READ | PROT_WRITE;
321		if ((phdr_info.dlpi_phdr[i].p_flags & PF_X) != 0)
322			r |= PROT_EXEC;
323		break;
324	}
325	atomic_store_int(&ret, r);
326	return (r);
327#else
328	return (0);
329#endif
330}
331
332#pragma weak _rtld_is_dlopened
333int
334_rtld_is_dlopened(void *arg __unused)
335{
336
337	return (0);
338}
339
340#endif /* !defined(IN_LIBDL) || defined(PIC) */
341