1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26 /*
27 * Copyright (c) 2018, Joyent, Inc.
28 * Copyright 2022 Oxide Computer Company
29 */
30
31 /*
32 * amd64 specific setup routine - relocate ld.so's symbols, setup its
33 * environment, map in loadable sections of the executable.
34 *
35 * Takes base address ld.so was loaded at, address of ld.so's dynamic
36 * structure, address of process environment pointers, address of auxiliary
37 * vector and * argv[0] (process name).
38 * If errors occur, send process signal - otherwise
39 * return executable's entry point to the bootstrap routine.
40 */
41
42 #include <signal.h>
43 #include <stdlib.h>
44 #include <sys/auxv.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <link.h>
48 #include <dlfcn.h>
49 #include "_rtld.h"
50 #include "_audit.h"
51 #include "msg.h"
52
53 /*
54 * Number of bytes to save for register usage.
55 */
56 uint_t _plt_save_size;
57 void (*_plt_fp_save)(void *);
58 void (*_plt_fp_restore)(void *);
59
60 extern void _elf_rtbndr_fp_save_orig(void *);
61 extern void _elf_rtbndr_fp_restore_orig(void *);
62 extern void _elf_rtbndr_fp_fxsave(void *);
63 extern void _elf_rtbndr_fp_fxrestore(void *);
64 extern void _elf_rtbndr_fp_xsave(void *);
65 extern void _elf_rtbndr_fp_xrestore(void *);
66
67 /*
68 * Based on what the kernel has told us, go through and set up the various
69 * pointers that we'll need for elf_rtbndr for the FPU.
70 */
71 static void
_setup_plt_fpu(int kind,size_t len)72 _setup_plt_fpu(int kind, size_t len)
73 {
74 /*
75 * If we didn't get a length for some reason, fall back to the old
76 * implementation.
77 */
78 if (len == 0)
79 kind = -1;
80
81 switch (kind) {
82 case AT_386_FPINFO_FXSAVE:
83 _plt_fp_save = _elf_rtbndr_fp_fxsave;
84 _plt_fp_restore = _elf_rtbndr_fp_fxrestore;
85 _plt_save_size = len;
86 break;
87 /*
88 * We can treat processors that don't correctly handle the exception
89 * information in xsave the same way we do others. The information
90 * that may or may not be properly saved and restored should not be
91 * relevant to us because of the ABI.
92 */
93 case AT_386_FPINFO_XSAVE:
94 case AT_386_FPINFO_XSAVE_AMD:
95 _plt_fp_save = _elf_rtbndr_fp_xsave;
96 _plt_fp_restore = _elf_rtbndr_fp_xrestore;
97 _plt_save_size = len;
98 break;
99 default:
100 _plt_fp_save = _elf_rtbndr_fp_save_orig;
101 _plt_fp_restore = _elf_rtbndr_fp_restore_orig;
102 /*
103 * The ABI says that 8 floating point registers are used for
104 * passing arguments (%xmm0 through %xmm7). Because these
105 * registers on some platforms may shadow the %ymm and %zmm
106 * registers, we end up needing to size this for the maximally
107 * sized register we care about, a 512-bit (64-byte) zmm
108 * register.
109 */
110 _plt_save_size = 64 * 8;
111 break;
112 }
113 }
114
115 /* VARARGS */
116 unsigned long
_setup(Boot * ebp,Dyn * ld_dyn)117 _setup(Boot *ebp, Dyn *ld_dyn)
118 {
119 ulong_t reladdr, relacount, ld_base = 0;
120 ulong_t relaent = 0, pltrelsz = 0;
121 ulong_t strtab, soname, interp_base = 0;
122 char *_rt_name, **_envp, **_argv;
123 int _syspagsz = 0, fd = -1;
124 uint_t _flags = 0;
125 uint_t hwcap[3] = { 0, 0, 0 };
126 Dyn *dyn_ptr;
127 Phdr *phdr = NULL;
128 Rt_map *lmp;
129 auxv_t *auxv, *_auxv;
130 uid_t uid = (uid_t)-1, euid = (uid_t)-1;
131 gid_t gid = (gid_t)-1, egid = (gid_t)-1;
132 char *_platform = NULL, *_execname = NULL, *_emulator = NULL;
133 int auxflags = -1, fpkind = -1;
134 size_t fpsize = 0;
135
136 /*
137 * Scan the bootstrap structure to pick up the basics.
138 */
139 for (; ebp->eb_tag != EB_NULL; ebp++)
140 switch (ebp->eb_tag) {
141 case EB_LDSO_BASE:
142 ld_base = (unsigned long)ebp->eb_un.eb_val;
143 break;
144 case EB_ARGV:
145 _argv = (char **)ebp->eb_un.eb_ptr;
146 break;
147 case EB_ENVP:
148 _envp = (char **)ebp->eb_un.eb_ptr;
149 break;
150 case EB_AUXV:
151 _auxv = (auxv_t *)ebp->eb_un.eb_ptr;
152 break;
153 case EB_PAGESIZE:
154 _syspagsz = (int)ebp->eb_un.eb_val;
155 break;
156 }
157
158 /*
159 * Search the aux. vector for the information passed by exec.
160 */
161 for (auxv = _auxv; auxv->a_type != AT_NULL; auxv++) {
162 switch (auxv->a_type) {
163 case AT_EXECFD:
164 /* this is the old exec that passes a file descriptor */
165 fd = (int)auxv->a_un.a_val;
166 break;
167 case AT_FLAGS:
168 /* processor flags (MAU available, etc) */
169 _flags = auxv->a_un.a_val;
170 break;
171 case AT_PAGESZ:
172 /* system page size */
173 _syspagsz = (int)auxv->a_un.a_val;
174 break;
175 case AT_PHDR:
176 /* address of the segment table */
177 phdr = (Phdr *)auxv->a_un.a_ptr;
178 break;
179 case AT_BASE:
180 /* interpreter base address */
181 if (ld_base == 0)
182 ld_base = auxv->a_un.a_val;
183 interp_base = auxv->a_un.a_val;
184 break;
185 case AT_SUN_UID:
186 /* effective user id for the executable */
187 euid = (uid_t)auxv->a_un.a_val;
188 break;
189 case AT_SUN_RUID:
190 /* real user id for the executable */
191 uid = (uid_t)auxv->a_un.a_val;
192 break;
193 case AT_SUN_GID:
194 /* effective group id for the executable */
195 egid = (gid_t)auxv->a_un.a_val;
196 break;
197 case AT_SUN_RGID:
198 /* real group id for the executable */
199 gid = (gid_t)auxv->a_un.a_val;
200 break;
201 case AT_SUN_PLATFORM:
202 /* platform name */
203 _platform = auxv->a_un.a_ptr;
204 break;
205 case AT_SUN_EXECNAME:
206 /* full pathname of execed object */
207 _execname = auxv->a_un.a_ptr;
208 break;
209 case AT_SUN_AUXFLAGS:
210 /* auxiliary flags */
211 auxflags = (int)auxv->a_un.a_val;
212 break;
213 case AT_SUN_HWCAP:
214 /* hardware capabilities */
215 hwcap[0] = (uint_t)auxv->a_un.a_val;
216 break;
217 case AT_SUN_HWCAP2:
218 /* hardware capabilities */
219 hwcap[1] = (uint_t)auxv->a_un.a_val;
220 break;
221 case AT_SUN_HWCAP3:
222 /* hardware capabilities */
223 hwcap[2] = (uint_t)auxv->a_un.a_val;
224 break;
225 case AT_SUN_EMULATOR:
226 /* name of emulation library, if any */
227 _emulator = auxv->a_un.a_ptr;
228 break;
229 case AT_SUN_FPTYPE:
230 fpkind = (int)auxv->a_un.a_val;
231 break;
232 case AT_SUN_FPSIZE:
233 fpsize = (size_t)auxv->a_un.a_val;
234 break;
235 }
236 }
237
238 /*
239 * Get needed info from ld.so's dynamic structure.
240 */
241 /* LINTED */
242 dyn_ptr = (Dyn *)((char *)ld_dyn + ld_base);
243 for (ld_dyn = dyn_ptr; ld_dyn->d_tag != DT_NULL; ld_dyn++) {
244 switch (ld_dyn->d_tag) {
245 case DT_RELA:
246 reladdr = ld_dyn->d_un.d_ptr + ld_base;
247 break;
248 case DT_RELACOUNT:
249 relacount = ld_dyn->d_un.d_val;
250 break;
251 case DT_RELAENT:
252 relaent = ld_dyn->d_un.d_val;
253 break;
254 case DT_PLTRELSZ:
255 pltrelsz = ld_dyn->d_un.d_val;
256 break;
257 case DT_STRTAB:
258 strtab = ld_dyn->d_un.d_ptr + ld_base;
259 break;
260 case DT_SONAME:
261 soname = ld_dyn->d_un.d_val;
262 break;
263 }
264 }
265 _rt_name = (char *)strtab + soname;
266
267 /*
268 * If we don't have a RELAENT, just assume the size.
269 */
270 if (relaent == 0)
271 relaent = sizeof (Rela);
272
273 /*
274 * As all global symbol references within ld.so.1 are protected
275 * (symbolic), only RELATIVE and JMPSLOT relocations should be left
276 * to process at runtime. Process all relocations now.
277 */
278 relacount += (pltrelsz / relaent);
279 for (; relacount; relacount--) {
280 ulong_t roffset;
281
282 roffset = ((Rela *)reladdr)->r_offset + ld_base;
283 *((ulong_t *)roffset) += ld_base +
284 ((Rela *)reladdr)->r_addend;
285 reladdr += relaent;
286 }
287
288 /*
289 * If an emulation library is being used, use that as the linker's
290 * effective executable name. The real executable is not linked by this
291 * linker.
292 */
293 if (_emulator != NULL) {
294 _execname = _emulator;
295 rtld_flags2 |= RT_FL2_BRANDED;
296 }
297
298 /*
299 * Initialize the dyn_plt_ent_size field. It currently contains the
300 * size of the dyn_plt_template. It still needs to be aligned and have
301 * space for the 'dyn_data' area added.
302 */
303 dyn_plt_ent_size = ROUND(dyn_plt_ent_size, M_WORD_ALIGN) +
304 sizeof (uintptr_t) + sizeof (uintptr_t) + sizeof (ulong_t) +
305 sizeof (ulong_t) + sizeof (Sym);
306
307 /*
308 * Initialize the amd64 specific PLT relocation constants based on the
309 * FP information that we have.
310 */
311 _setup_plt_fpu(fpkind, fpsize);
312
313 /*
314 * Continue with generic startup processing.
315 */
316 if ((lmp = setup((char **)_envp, (auxv_t *)_auxv, _flags, _platform,
317 _syspagsz, _rt_name, ld_base, interp_base, fd, phdr,
318 _execname, _argv, uid, euid, gid, egid, auxflags,
319 hwcap)) == NULL) {
320 rtldexit(&lml_main, 1);
321 }
322
323 return (LM_ENTRY_PT(lmp)());
324 }
325