xref: /xnu-10002.41.9/libkern/kxld/kxld_seg.c (revision 699cd48037512bf4380799317ca44ca453c82f57)
1 /*
2  * Copyright (c) 2008 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 #include <string.h>
29 #include <mach/vm_prot.h>
30 #include <mach-o/loader.h>
31 #include <sys/types.h>
32 
33 #if KERNEL
34     #include <mach/vm_param.h>
35 #else
36     #include <mach/mach_init.h>
37 #endif /* KERNEL */
38 
39 #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld"
40 #include <AssertMacros.h>
41 
42 #include "kxld_reloc.h"
43 #include "kxld_sect.h"
44 #include "kxld_seg.h"
45 #include "kxld_symtab.h"
46 #include "kxld_util.h"
47 
48 #define MAX_SEGS 20
49 
50 #define TEXT_SEG_PROT (VM_PROT_READ | VM_PROT_EXECUTE)
51 #define DATA_SEG_PROT (VM_PROT_READ | VM_PROT_WRITE)
52 
53 extern boolean_t isSplitKext;
54 extern boolean_t isOldInterface;
55 
56 #if KXLD_USER_OR_OBJECT
57 static kern_return_t reorder_sections(KXLDSeg *seg, KXLDArray *section_order);
58 static void reorder_section(KXLDArray *sects, u_int *sect_reorder_index,
59     KXLDSect **reorder_buffer, u_int reorder_buffer_index);
60 #endif /* KXLD_USER_OR_OBJECT */
61 
62 #if 0
63 static KXLDSeg * get_segment_by_name(KXLDArray *segarray, const char *name);
64 #endif
65 
66 #if KXLD_USER_OR_ILP32
67 static kern_return_t seg_export_macho_header_32(const KXLDSeg *seg, u_char *buf,
68     u_long *header_offset, u_long header_size, u_long data_offset);
69 #endif
70 #if KXLD_USER_OR_LP64
71 static kern_return_t seg_export_macho_header_64(const KXLDSeg *seg, u_char *buf,
72     u_long *header_offset, u_long header_size, u_long data_offset);
73 #endif
74 
75 static KXLDSect * get_sect_by_index(const KXLDSeg *seg, u_int idx);
76 
77 #if KXLD_USER_OR_ILP32
78 /*******************************************************************************
79 *******************************************************************************/
80 kern_return_t
kxld_seg_init_from_macho_32(KXLDSeg * seg,struct segment_command * src)81 kxld_seg_init_from_macho_32(KXLDSeg *seg, struct segment_command *src)
82 {
83 	kern_return_t rval = KERN_FAILURE;
84 	check(seg);
85 	check(src);
86 
87 	strlcpy(seg->segname, src->segname, sizeof(seg->segname));
88 	seg->base_addr = src->vmaddr;
89 	seg->link_addr = src->vmaddr;
90 	seg->vmsize = src->vmsize;
91 	seg->fileoff = src->fileoff;
92 	seg->maxprot = src->maxprot;
93 	seg->initprot = src->initprot;
94 	seg->flags = src->flags;
95 
96 	rval = kxld_array_init(&seg->sects, sizeof(KXLDSect *), src->nsects);
97 	require_noerr(rval, finish);
98 
99 	rval = KERN_SUCCESS;
100 
101 finish:
102 	return rval;
103 }
104 #endif /* KXLD_USER_OR_ILP32 */
105 
106 #if KXLD_USER_OR_LP64
107 /*******************************************************************************
108 *******************************************************************************/
109 kern_return_t
kxld_seg_init_from_macho_64(KXLDSeg * seg,struct segment_command_64 * src)110 kxld_seg_init_from_macho_64(KXLDSeg *seg, struct segment_command_64 *src)
111 {
112 	kern_return_t rval = KERN_FAILURE;
113 	check(seg);
114 	check(src);
115 
116 	strlcpy(seg->segname, src->segname, sizeof(seg->segname));
117 	seg->base_addr = src->vmaddr;
118 	seg->link_addr = src->vmaddr;
119 	seg->vmsize = src->vmsize;
120 
121 	seg->fileoff = src->fileoff;
122 	seg->maxprot = src->maxprot;
123 	seg->initprot = src->initprot;
124 	seg->flags = src->flags;
125 
126 	rval = kxld_array_init(&seg->sects, sizeof(KXLDSect *), src->nsects);
127 	require_noerr(rval, finish);
128 
129 	rval = KERN_SUCCESS;
130 
131 finish:
132 	return rval;
133 }
134 #endif /* KXLD_USER_OR_LP64 */
135 
136 #if KXLD_USER_OR_OBJECT
137 /*******************************************************************************
138 *******************************************************************************/
139 kern_return_t
kxld_seg_create_seg_from_sections(KXLDArray * segarray,KXLDArray * sectarray)140 kxld_seg_create_seg_from_sections(KXLDArray *segarray, KXLDArray *sectarray)
141 {
142 	kern_return_t rval = KERN_FAILURE;
143 	KXLDSeg *seg = NULL;
144 	KXLDSect *sect = NULL;
145 	KXLDSect **sectp = NULL;
146 	u_int i = 0;
147 
148 	/* Initialize the segment array to one segment */
149 
150 	rval = kxld_array_init(segarray, sizeof(KXLDSeg), 1);
151 	require_noerr(rval, finish);
152 
153 	/* Initialize the segment */
154 
155 	seg = kxld_array_get_item(segarray, 0);
156 	seg->initprot = VM_PROT_ALL;
157 	seg->maxprot = VM_PROT_ALL;
158 	seg->link_addr = 0;
159 
160 	/* Add the sections to the segment */
161 
162 	rval = kxld_array_init(&seg->sects, sizeof(KXLDSect *), sectarray->nitems);
163 	require_noerr(rval, finish);
164 
165 	for (i = 0; i < sectarray->nitems; ++i) {
166 		sect = kxld_array_get_item(sectarray, i);
167 		sectp = kxld_array_get_item(&seg->sects, i);
168 
169 		*sectp = sect;
170 	}
171 
172 	rval = KERN_SUCCESS;
173 finish:
174 	return rval;
175 }
176 
177 /*******************************************************************************
178 *******************************************************************************/
179 kern_return_t
kxld_seg_finalize_object_segment(KXLDArray * segarray,KXLDArray * section_order,u_long hdrsize)180 kxld_seg_finalize_object_segment(KXLDArray *segarray, KXLDArray *section_order,
181     u_long hdrsize)
182 {
183 	kern_return_t rval = KERN_FAILURE;
184 	KXLDSeg *seg = NULL;
185 	KXLDSect *sect = NULL;
186 	u_long sect_offset = 0;
187 	u_int i = 0;
188 
189 	check(segarray);
190 	check(section_order);
191 	require_action(segarray->nitems == 1, finish, rval = KERN_FAILURE);
192 
193 	seg = kxld_array_get_item(segarray, 0);
194 
195 	/* Reorder the sections */
196 
197 	rval = reorder_sections(seg, section_order);
198 	require_noerr(rval, finish);
199 
200 	/* Set the initial link address at the end of the header pages */
201 
202 	seg->link_addr = kxld_round_page_cross_safe(hdrsize);
203 
204 	/* Fix up all of the section addresses */
205 
206 	sect_offset = (u_long) seg->link_addr;
207 	for (i = 0; i < seg->sects.nitems; ++i) {
208 		sect = *(KXLDSect **)kxld_array_get_item(&seg->sects, i);
209 
210 		sect->link_addr = kxld_sect_align_address(sect, sect_offset);
211 		sect_offset = (u_long) (sect->link_addr + sect->size);
212 	}
213 
214 	/* Finish initializing the segment */
215 
216 	seg->vmsize = kxld_round_page_cross_safe(sect_offset) - seg->link_addr;
217 
218 	rval = KERN_SUCCESS;
219 finish:
220 	return rval;
221 }
222 
223 /*******************************************************************************
224 * The legacy section ordering used by kld was based of the order of sections
225 * in the kernel file.  To achieve the same layout, we save the kernel's
226 * section ordering as an array of section names when the kernel file itself
227 * is linked.  Then, when kexts are linked with the KXLD_LEGACY_LAYOUT flag,
228 * we refer to the kernel's section layout to order the kext's sections.
229 *
230 * The algorithm below is as follows.  We iterate through all of the kernel's
231 * sections grouped by segment name, so that we are processing all of the __TEXT
232 * sections, then all of the __DATA sections, etc.  We then iterate through the
233 * kext's sections with a similar grouping, looking for sections that match
234 * the current kernel's section.  In this way, we order all of the matching
235 * kext sections in the order in which they appear in the kernel, and then place
236 * all remaining kext sections at the end of the current segment grouping in
237 * the order in which they originally appeared.  Sections that only appear in
238 * the kernel are not created.  segments that only appear in the kext are
239 * left in their original ordering.
240 *
241 * An example:
242 *
243 * Kernel sections:
244 * __TEXT,__text
245 * __TEXT,__const
246 * __DATA,__data
247 *
248 * Kext sections:
249 * __TEXT,__const
250 * __TEXT,__literal4
251 * __TEXT,__text
252 * __DATA,__const
253 * __DATA,__data
254 *
255 * Reordered kext sections:
256 * __TEXT,__text
257 * __TEXT,__const
258 * __TEXT,__literal4
259 * __DATA,__data
260 * __DATA,__const
261 *
262 * In the implementation below, we use a reorder buffer to hold pointers to the
263 * sections of the current working segment.  We scan this buffer looking for
264 * matching sections, placing them in the segment's section index as we find them.
265 * If this function must exit early, the segment's section index is left in an
266 * unusable state.
267 *******************************************************************************/
268 static kern_return_t
reorder_sections(KXLDSeg * seg,KXLDArray * section_order)269 reorder_sections(KXLDSeg *seg, KXLDArray *section_order)
270 {
271 	kern_return_t rval = KERN_FAILURE;
272 	KXLDSect *sect = NULL;
273 	KXLDSect **reorder_buffer = NULL;
274 	KXLDSectionName *section_name = NULL;
275 	const char *segname = NULL;
276 	u_int sect_index = 0, legacy_index = 0, sect_reorder_index = 0;
277 	u_int i = 0, j = 0;
278 	u_int sect_start = 0, sect_end = 0, legacy_start = 0, legacy_end = 0;
279 	u_int nsects = 0;
280 
281 	check(seg);
282 	check(section_order);
283 
284 	/* Allocate the reorder buffer with enough space to hold all of the
285 	 * sections.
286 	 */
287 
288 	reorder_buffer = kxld_alloc(
289 		seg->sects.nitems * sizeof(*reorder_buffer));
290 	require_action(reorder_buffer, finish, rval = KERN_RESOURCE_SHORTAGE);
291 
292 	while (legacy_index < section_order->nitems) {
293 		/* Find the next group of sections with a common segment in the
294 		 * section_order array.
295 		 */
296 
297 		legacy_start = legacy_index++;
298 		legacy_end = legacy_index;
299 
300 		section_name = kxld_array_get_item(section_order, legacy_start);
301 		segname = section_name->segname;
302 		while (legacy_index < section_order->nitems) {
303 			section_name = kxld_array_get_item(section_order, legacy_index);
304 			if (!streq_safe(segname, section_name->segname,
305 			    sizeof(section_name->segname))) {
306 				break;
307 			}
308 
309 			++legacy_index;
310 			++legacy_end;
311 		}
312 
313 		/* Find a group of sections in the kext that match the current
314 		 * section_order segment.
315 		 */
316 
317 		sect_start = sect_index;
318 		sect_end = sect_index;
319 
320 		while (sect_index < seg->sects.nitems) {
321 			sect = *(KXLDSect **) kxld_array_get_item(&seg->sects, sect_index);
322 			if (!streq_safe(segname, sect->segname, sizeof(sect->segname))) {
323 				break;
324 			}
325 
326 			++sect_index;
327 			++sect_end;
328 		}
329 		nsects = sect_end - sect_start;
330 
331 		if (!nsects) {
332 			continue;
333 		}
334 
335 		/* Populate the reorder buffer with the current group of kext sections */
336 
337 		for (i = sect_start; i < sect_end; ++i) {
338 			reorder_buffer[i - sect_start] =
339 			    *(KXLDSect **) kxld_array_get_item(&seg->sects, i);
340 		}
341 
342 		/* For each section_order section, scan the reorder buffer for a matching
343 		 * kext section.  If one is found, copy it into the next slot in the
344 		 * segment's section index.
345 		 */
346 
347 		sect_reorder_index = sect_start;
348 		for (i = legacy_start; i < legacy_end; ++i) {
349 			section_name = kxld_array_get_item(section_order, i);
350 			sect = NULL;
351 
352 			for (j = 0; j < nsects; ++j) {
353 				sect = reorder_buffer[j];
354 				if (!sect) {
355 					continue;
356 				}
357 
358 				if (streq_safe(section_name->sectname, sect->sectname,
359 				    sizeof(section_name->sectname))) {
360 					break;
361 				}
362 
363 				sect = NULL;
364 			}
365 
366 			if (sect) {
367 				(void) reorder_section(&seg->sects, &sect_reorder_index,
368 				    reorder_buffer, j);
369 			}
370 		}
371 
372 		/* If any sections remain in the reorder buffer, they are not specified
373 		 * in the section_order array, so append them to the section index in
374 		 * in the order they are found.
375 		 */
376 
377 		for (i = 0; i < nsects; ++i) {
378 			if (!reorder_buffer[i]) {
379 				continue;
380 			}
381 			reorder_section(&seg->sects, &sect_reorder_index, reorder_buffer, i);
382 		}
383 	}
384 
385 	rval = KERN_SUCCESS;
386 
387 finish:
388 
389 	if (reorder_buffer) {
390 		kxld_free(reorder_buffer, seg->sects.nitems * sizeof(*reorder_buffer));
391 		reorder_buffer = NULL;
392 	}
393 
394 	return rval;
395 }
396 
397 /*******************************************************************************
398 *******************************************************************************/
399 static void
reorder_section(KXLDArray * sects,u_int * sect_reorder_index,KXLDSect ** reorder_buffer,u_int reorder_buffer_index)400 reorder_section(KXLDArray *sects, u_int *sect_reorder_index,
401     KXLDSect **reorder_buffer, u_int reorder_buffer_index)
402 {
403 	KXLDSect **tmp = NULL;
404 
405 	tmp = kxld_array_get_item(sects, *sect_reorder_index);
406 
407 	*tmp = reorder_buffer[reorder_buffer_index];
408 	reorder_buffer[reorder_buffer_index]->sectnum = *sect_reorder_index;
409 	reorder_buffer[reorder_buffer_index] = NULL;
410 
411 	++(*sect_reorder_index);
412 }
413 
414 /*******************************************************************************
415 *******************************************************************************/
416 kern_return_t
kxld_seg_init_linkedit(KXLDArray * segs)417 kxld_seg_init_linkedit(KXLDArray *segs)
418 {
419 	kern_return_t rval = KERN_FAILURE;
420 	KXLDSeg *seg = NULL;
421 	KXLDSeg *le = NULL;
422 
423 	rval = kxld_array_resize(segs, 2);
424 	require_noerr(rval, finish);
425 
426 	seg = kxld_array_get_item(segs, 0);
427 	le = kxld_array_get_item(segs, 1);
428 
429 	strlcpy(le->segname, SEG_LINKEDIT, sizeof(le->segname));
430 	le->link_addr = kxld_round_page_cross_safe(seg->link_addr + seg->vmsize);
431 	le->maxprot = VM_PROT_ALL;
432 	le->initprot = VM_PROT_DEFAULT;
433 
434 	rval = KERN_SUCCESS;
435 
436 finish:
437 	return rval;
438 }
439 #endif /* KXLD_USER_OR_OBJECT */
440 
441 /*******************************************************************************
442 *******************************************************************************/
443 void
kxld_seg_clear(KXLDSeg * seg)444 kxld_seg_clear(KXLDSeg *seg)
445 {
446 	check(seg);
447 
448 	bzero(seg->segname, sizeof(seg->segname));
449 	seg->base_addr = 0;
450 	seg->link_addr = 0;
451 	seg->vmsize = 0;
452 	seg->flags = 0;
453 	seg->maxprot = 0;
454 	seg->initprot = 0;
455 
456 	/* Don't clear the individual sections here because kxld_kext.c will take
457 	 * care of that.
458 	 */
459 	kxld_array_clear(&seg->sects);
460 }
461 
462 /*******************************************************************************
463 *******************************************************************************/
464 void
kxld_seg_deinit(KXLDSeg * seg)465 kxld_seg_deinit(KXLDSeg *seg)
466 {
467 	check(seg);
468 
469 	kxld_array_deinit(&seg->sects);
470 	bzero(seg, sizeof(*seg));
471 }
472 
473 /*******************************************************************************
474 *******************************************************************************/
475 kxld_size_t
kxld_seg_get_vmsize(const KXLDSeg * seg)476 kxld_seg_get_vmsize(const KXLDSeg *seg)
477 {
478 	check(seg);
479 
480 	return seg->vmsize;
481 }
482 
483 /*******************************************************************************
484 *******************************************************************************/
485 u_long
kxld_seg_get_macho_header_size(const KXLDSeg * seg,boolean_t is_32_bit)486 kxld_seg_get_macho_header_size(const KXLDSeg *seg, boolean_t is_32_bit)
487 {
488 	u_long size = 0;
489 
490 	check(seg);
491 
492 	if (is_32_bit) {
493 		size += sizeof(struct segment_command);
494 	} else {
495 		size += sizeof(struct segment_command_64);
496 	}
497 	size += seg->sects.nitems * kxld_sect_get_macho_header_size(is_32_bit);
498 
499 	return size;
500 }
501 
502 /*******************************************************************************
503 *******************************************************************************/
504 /* This is no longer used, but may be useful some day... */
505 #if 0
506 u_long
507 kxld_seg_get_macho_data_size(const KXLDSeg *seg)
508 {
509 	u_long size = 0;
510 	u_int i = 0;
511 	KXLDSect *sect = NULL;
512 
513 	check(seg);
514 
515 	for (i = 0; i < seg->sects.nitems; ++i) {
516 		sect = get_sect_by_index(seg, i);
517 		size = (u_long) kxld_sect_align_address(sect, size);
518 		size += kxld_sect_get_macho_data_size(sect);
519 	}
520 
521 	return kxld_round_page_cross_safe(size);
522 }
523 #endif
524 
525 /*******************************************************************************
526 *******************************************************************************/
527 static KXLDSect *
get_sect_by_index(const KXLDSeg * seg,u_int idx)528 get_sect_by_index(const KXLDSeg *seg, u_int idx)
529 {
530 	check(seg);
531 
532 	return *(KXLDSect **) kxld_array_get_item(&seg->sects, idx);
533 }
534 
535 /*******************************************************************************
536 *******************************************************************************/
537 kern_return_t
kxld_seg_export_macho_to_file_buffer(const KXLDSeg * seg,u_char * buf,u_long * header_offset,u_long header_size,u_long * data_offset,u_long data_size,boolean_t is_32_bit)538 kxld_seg_export_macho_to_file_buffer(const KXLDSeg *seg, u_char *buf,
539     u_long *header_offset, u_long header_size,
540     u_long *data_offset, u_long data_size,
541     boolean_t is_32_bit)
542 {
543 	kern_return_t rval = KERN_FAILURE;
544 	KXLDSect *sect = NULL;
545 	u_long base_data_offset = *data_offset;
546 	u_int i = 0;
547 	struct segment_command *hdr32 =
548 	    (struct segment_command *) ((void *) (buf + *header_offset));
549 	struct segment_command_64 *hdr64 =
550 	    (struct segment_command_64 *) ((void *) (buf + *header_offset));
551 
552 	check(seg);
553 	check(buf);
554 	check(header_offset);
555 	check(data_offset);
556 
557 	/* Write out the header */
558 
559 	KXLD_3264_FUNC(is_32_bit, rval,
560 	    seg_export_macho_header_32, seg_export_macho_header_64,
561 	    seg, buf, header_offset, header_size, *data_offset);
562 	require_noerr(rval, finish);
563 
564 	/* Write out each section */
565 
566 	for (i = 0; i < seg->sects.nitems; ++i) {
567 		sect = get_sect_by_index(seg, i);
568 
569 		rval = kxld_sect_export_macho_to_file_buffer(sect, buf, header_offset,
570 		    header_size, data_offset, data_size, is_32_bit);
571 		require_noerr(rval, finish);
572 	}
573 
574 	/* Update the filesize */
575 
576 	if (is_32_bit) {
577 		hdr32->filesize = (uint32_t) (*data_offset - base_data_offset);
578 	} else {
579 		hdr64->filesize = (uint64_t) (*data_offset - base_data_offset);
580 	}
581 
582 	*data_offset = (u_long)kxld_round_page_cross_safe(*data_offset);
583 
584 	rval = KERN_SUCCESS;
585 
586 finish:
587 	return rval;
588 }
589 
590 
591 /*******************************************************************************
592 *******************************************************************************/
593 kern_return_t
kxld_seg_export_macho_to_vm(const KXLDSeg * seg,u_char * buf,u_long * header_offset,u_long header_size,u_long data_size,kxld_addr_t file_link_addr,boolean_t is_32_bit)594 kxld_seg_export_macho_to_vm(const KXLDSeg *seg,
595     u_char *buf,
596     u_long *header_offset,
597     u_long header_size,
598     u_long data_size,
599     kxld_addr_t file_link_addr,
600     boolean_t is_32_bit)
601 {
602 	kern_return_t   rval = KERN_FAILURE;
603 	KXLDSect *      sect = NULL;
604 
605 	// data_offset is used to set fileoff field in segment header
606 	u_long          data_offset;
607 	u_int           i = 0;
608 
609 	check(seg);
610 	check(buf);
611 	check(header_offset);
612 
613 	data_offset = (u_long) (seg->link_addr - file_link_addr);
614 
615 	/* Write out the header */
616 
617 	KXLD_3264_FUNC(is_32_bit, rval,
618 	    seg_export_macho_header_32, seg_export_macho_header_64,
619 	    seg,
620 	    buf,
621 	    header_offset, header_size, data_offset);
622 	require_noerr(rval, finish);
623 
624 	/* Write out each section */
625 
626 	for (i = 0; i < seg->sects.nitems; ++i) {
627 		sect = get_sect_by_index(seg, i);
628 
629 		rval = kxld_sect_export_macho_to_vm(sect, buf, header_offset,
630 		    header_size, file_link_addr, data_size, is_32_bit);
631 		require_noerr(rval, finish);
632 	}
633 
634 	rval = KERN_SUCCESS;
635 
636 finish:
637 	return rval;
638 }
639 
640 #if KXLD_USER_OR_ILP32
641 /*******************************************************************************
642 *******************************************************************************/
643 static kern_return_t
seg_export_macho_header_32(const KXLDSeg * seg,u_char * buf,u_long * header_offset,u_long header_size,u_long data_offset)644 seg_export_macho_header_32(const KXLDSeg *seg, u_char *buf,
645     u_long *header_offset, u_long header_size, u_long data_offset)
646 {
647 	kern_return_t rval = KERN_FAILURE;
648 	struct segment_command *seghdr = NULL;
649 
650 	check(seg);
651 	check(buf);
652 	check(header_offset);
653 
654 	require_action(sizeof(*seghdr) <= header_size - *header_offset, finish,
655 	    rval = KERN_FAILURE);
656 	seghdr = (struct segment_command *) ((void *) (buf + *header_offset));
657 	*header_offset += sizeof(*seghdr);
658 
659 	seghdr->cmd = LC_SEGMENT;
660 	seghdr->cmdsize = (uint32_t) sizeof(*seghdr);
661 	seghdr->cmdsize +=
662 	    (uint32_t) (seg->sects.nitems * kxld_sect_get_macho_header_size(TRUE));
663 	strlcpy(seghdr->segname, seg->segname, sizeof(seghdr->segname));
664 	seghdr->vmaddr = (uint32_t) seg->link_addr;
665 	seghdr->vmsize = (uint32_t) seg->vmsize;
666 	seghdr->fileoff = (uint32_t) data_offset;
667 	seghdr->filesize = (uint32_t) seg->vmsize;
668 	seghdr->maxprot = seg->maxprot;
669 	seghdr->initprot = seg->initprot;
670 	seghdr->nsects = seg->sects.nitems;
671 	seghdr->flags = 0;
672 
673 #if SPLIT_KEXTS_DEBUG
674 	{
675 		kxld_log(kKxldLogLinking, kKxldLogErr,
676 		    "segname %s seghdr %p vmaddr %p vmsize 0x%02X %u fileoff 0x%02X %u <%s>",
677 		    seg->segname[0] ? seg->segname : "none",
678 		    (void *) seghdr,
679 		    (void *) ((uint64_t)seghdr->vmaddr),
680 		    seghdr->vmsize,
681 		    seghdr->vmsize,
682 		    seghdr->fileoff,
683 		    seghdr->fileoff,
684 		    __func__);
685 	}
686 #endif
687 
688 	rval = KERN_SUCCESS;
689 
690 finish:
691 	return rval;
692 }
693 #endif /* KXLD_USER_OR_ILP32 */
694 
695 #if KXLD_USER_OR_LP64
696 /*******************************************************************************
697 *******************************************************************************/
698 static kern_return_t
seg_export_macho_header_64(const KXLDSeg * seg,u_char * buf,u_long * header_offset,u_long header_size,u_long data_offset)699 seg_export_macho_header_64(const KXLDSeg *seg, u_char *buf,
700     u_long *header_offset, u_long header_size, u_long data_offset)
701 {
702 	kern_return_t rval = KERN_FAILURE;
703 	struct segment_command_64 *seghdr = NULL;
704 
705 	check(seg);
706 	check(buf);
707 	check(header_offset);
708 
709 	require_action(sizeof(*seghdr) <= header_size - *header_offset, finish,
710 	    rval = KERN_FAILURE);
711 
712 #if SPLIT_KEXTS_DEBUG
713 	{
714 		struct mach_header_64 *mach;
715 
716 		mach = (struct mach_header_64 *) ((void *) buf);
717 
718 		if (mach->magic != MH_MAGIC_64) {
719 			kxld_log(kKxldLogLinking, kKxldLogErr,
720 			    "bad macho header at %p <%s>",
721 			    (void *) mach, __func__);
722 			goto finish;
723 		}
724 	}
725 #endif
726 
727 	seghdr = (struct segment_command_64 *) ((void *) (buf + *header_offset));
728 	*header_offset += sizeof(*seghdr);
729 
730 	seghdr->cmd = LC_SEGMENT_64;
731 	seghdr->cmdsize = (uint32_t) sizeof(*seghdr);
732 	seghdr->cmdsize +=
733 	    (uint32_t) (seg->sects.nitems * kxld_sect_get_macho_header_size(FALSE));
734 	strlcpy(seghdr->segname, seg->segname, sizeof(seghdr->segname));
735 	seghdr->vmaddr = (uint64_t) seg->link_addr;
736 	seghdr->vmsize = (uint64_t) seg->vmsize;
737 	seghdr->fileoff = (uint64_t) data_offset;
738 	seghdr->filesize = (uint64_t) seg->vmsize;
739 	seghdr->maxprot = seg->maxprot;
740 	seghdr->initprot = seg->initprot;
741 	seghdr->nsects = seg->sects.nitems;
742 	seghdr->flags = 0;
743 
744 #if SPLIT_KEXTS_DEBUG
745 	{
746 		kxld_log(kKxldLogLinking, kKxldLogErr,
747 		    "%p >>> Start of %s seghdr (size %lu) <%s>",
748 		    (void *) seghdr,
749 		    seg->segname[0] ? seg->segname : "none",
750 		    sizeof(*seghdr),
751 		    __func__);
752 		kxld_log(kKxldLogLinking, kKxldLogErr,
753 		    "%p <<< End of %s seghdr <%s>",
754 		    (void *) ((u_char *)seghdr + sizeof(*seghdr)),
755 		    seg->segname[0] ? seg->segname : "none",
756 		    __func__);
757 
758 		kxld_log(kKxldLogLinking, kKxldLogErr,
759 		    "%s seghdr, cmdsize %d vmaddr %p vmsize %p %llu fileoff %p %llu <%s>",
760 		    seg->segname[0] ? seg->segname : "none",
761 		    seghdr->cmdsize,
762 		    (void *) seghdr->vmaddr,
763 		    (void *) seghdr->vmsize,
764 		    seghdr->vmsize,
765 		    (void *) seghdr->fileoff,
766 		    seghdr->fileoff,
767 		    __func__);
768 	}
769 #endif
770 
771 	rval = KERN_SUCCESS;
772 
773 finish:
774 	return rval;
775 }
776 #endif /* KXLD_USER_OR_LP64 */
777 
778 /*******************************************************************************
779 *******************************************************************************/
780 kern_return_t
kxld_seg_add_section(KXLDSeg * seg,KXLDSect * sect)781 kxld_seg_add_section(KXLDSeg *seg, KXLDSect *sect)
782 {
783 	kern_return_t rval = KERN_FAILURE;
784 	KXLDSect **sectp = NULL;
785 	u_int i;
786 
787 	check(seg);
788 	check(sect);
789 	require_action(streq_safe(seg->segname, sect->segname, sizeof(seg->segname)),
790 	    finish, rval = KERN_FAILURE);
791 
792 	/* Add the section into the section index */
793 
794 	for (i = 0; i < seg->sects.nitems; ++i) {
795 		sectp = kxld_array_get_item(&seg->sects, i);
796 		if (NULL == *sectp) {
797 			*sectp = sect;
798 			break;
799 		}
800 	}
801 	require_action(i < seg->sects.nitems, finish, rval = KERN_FAILURE);
802 
803 	rval = KERN_SUCCESS;
804 
805 finish:
806 
807 	return rval;
808 }
809 
810 /*******************************************************************************
811 *******************************************************************************/
812 kern_return_t
kxld_seg_finish_init(KXLDSeg * seg)813 kxld_seg_finish_init(KXLDSeg *seg)
814 {
815 	kern_return_t rval = KERN_FAILURE;
816 	u_int i = 0;
817 	KXLDSect *sect = NULL;
818 	kxld_addr_t maxaddr = 0;
819 	kxld_size_t maxsize = 0;
820 
821 	/* If we already have a size for this segment (e.g. from the mach-o load
822 	 * command) then don't recalculate the segment size. This is safer since
823 	 * when we recalculate we are making assumptions about page alignment and
824 	 * padding that the kext mach-o file was built with. Better to trust the
825 	 * macho-o info, if we have it. If we don't (i.e. vmsize == 0) then add up
826 	 * the section sizes and take a best guess at page padding.
827 	 */
828 	if ((seg->vmsize == 0) && (seg->sects.nitems)) {
829 		for (i = 0; i < seg->sects.nitems; ++i) {
830 			sect = get_sect_by_index(seg, i);
831 			require_action(sect, finish, rval = KERN_FAILURE);
832 			if (sect->base_addr > maxaddr) {
833 				maxaddr = sect->base_addr;
834 				maxsize = sect->size;
835 			}
836 		}
837 		seg->vmsize = kxld_round_page_cross_safe(maxaddr +
838 		    maxsize - seg->base_addr);
839 	}
840 
841 	rval = KERN_SUCCESS;
842 
843 finish:
844 	return rval;
845 }
846 
847 /*******************************************************************************
848 *******************************************************************************/
849 void
kxld_seg_set_vm_protections(KXLDSeg * seg,boolean_t strict_protections)850 kxld_seg_set_vm_protections(KXLDSeg *seg, boolean_t strict_protections)
851 {
852 	if (strict_protections) {
853 		if (!strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname))) {
854 			seg->initprot = TEXT_SEG_PROT;
855 			seg->maxprot = TEXT_SEG_PROT;
856 		} else {
857 			seg->initprot = DATA_SEG_PROT;
858 			seg->maxprot = DATA_SEG_PROT;
859 		}
860 	} else {
861 		seg->initprot = VM_PROT_ALL;
862 		seg->maxprot = VM_PROT_ALL;
863 	}
864 }
865 
866 /*******************************************************************************
867 *******************************************************************************/
868 void
kxld_seg_relocate(KXLDSeg * seg,kxld_addr_t link_addr)869 kxld_seg_relocate(KXLDSeg *seg, kxld_addr_t link_addr)
870 {
871 	KXLDSect *sect = NULL;
872 	u_int i = 0;
873 	splitKextLinkInfo * link_info = (splitKextLinkInfo *) link_addr;
874 	kxld_addr_t         my_link_addr;
875 
876 	if (isOldInterface) {
877 		seg->link_addr += link_addr;
878 	} else {
879 		if (isSplitKext) {
880 			// we have a split kext
881 			if (kxld_seg_is_text_seg(seg)) {
882 				// assumes this is the beginning of the kext
883 				my_link_addr = link_info->vmaddr_TEXT;
884 				seg->link_addr = my_link_addr;
885 			} else if (kxld_seg_is_text_exec_seg(seg)) {
886 				my_link_addr = link_info->vmaddr_TEXT_EXEC;
887 				seg->link_addr = my_link_addr;
888 				// vmaddr_TEXT_EXEC is the actual vmaddr for this segment so we need
889 				// to adjust for kxld_sect_relocate assuming the link addr is
890 				// the address of the kext (macho header in __TEXT)
891 				my_link_addr -= seg->base_addr;
892 			} else if (kxld_seg_is_data_seg(seg)) {
893 				my_link_addr = link_info->vmaddr_DATA;
894 				seg->link_addr = my_link_addr;
895 				// vmaddr_DATA is the actual vmaddr for this segment so we need
896 				// to adjust for kxld_sect_relocate assuming the link addr is
897 				// the address of the kext (macho header in __TEXT)
898 				my_link_addr -= seg->base_addr;
899 			} else if (kxld_seg_is_data_const_seg(seg)) {
900 				my_link_addr = link_info->vmaddr_DATA_CONST;
901 				seg->link_addr = my_link_addr;
902 				// vmaddr_DATA_CONST is the actual vmaddr for this segment so we need
903 				// to adjust for kxld_sect_relocate assuming the link addr is
904 				// the address of the kext (macho header in __TEXT)
905 				my_link_addr -= seg->base_addr;
906 			} else if (kxld_seg_is_llvm_cov_seg(seg)) {
907 				my_link_addr = link_info->vmaddr_LLVM_COV;
908 				seg->link_addr = my_link_addr;
909 				// vmaddr_LLVM_COV is the actual vmaddr for this segment so we need
910 				// to adjust for kxld_sect_relocate assuming the link addr is
911 				// the address of the kext (macho header in __TEXT)
912 				my_link_addr -= seg->base_addr;
913 			} else if (kxld_seg_is_linkedit_seg(seg)) {
914 				my_link_addr = link_info->vmaddr_LINKEDIT;
915 				seg->link_addr = my_link_addr;
916 				// vmaddr_DATA is the actual vmaddr for this segment so we need
917 				// to adjust for kxld_sect_relocate assuming the link addr is
918 				// the address of the kext (macho header in __TEXT)
919 				my_link_addr -= seg->base_addr;
920 			} else {
921 				kxld_log(kKxldLogLinking, kKxldLogErr,
922 				    " not expecting this segment %s!!! <%s>",
923 				    seg->segname[0] ? seg->segname : "none",
924 				    __func__);
925 				my_link_addr = link_info->vmaddr_TEXT;
926 				seg->link_addr += my_link_addr;
927 			}
928 		} else {
929 			my_link_addr = link_info->vmaddr_TEXT;
930 			seg->link_addr += my_link_addr;
931 		}
932 	}
933 
934 #if SPLIT_KEXTS_DEBUG
935 	{
936 		kxld_log(kKxldLogLinking, kKxldLogErr,
937 		    "%p >>> Start of %s segment (vmsize %llu) <%s>)",
938 		    (void *) seg->link_addr,
939 		    seg->segname[0] ? seg->segname : "none",
940 		    seg->vmsize,
941 		    __func__);
942 		kxld_log(kKxldLogLinking, kKxldLogErr,
943 		    "%p <<< End of %s segment <%s>",
944 		    (void *) (seg->link_addr + seg->vmsize),
945 		    seg->segname[0] ? seg->segname : "none",
946 		    __func__);
947 	}
948 #endif
949 
950 	for (i = 0; i < seg->sects.nitems; ++i) {
951 		sect = get_sect_by_index(seg, i);
952 		if (isOldInterface) {
953 			kxld_sect_relocate(sect, link_addr);
954 		} else {
955 			kxld_sect_relocate(sect, my_link_addr);
956 		}
957 	}
958 }
959 
960 /*******************************************************************************
961 *******************************************************************************/
962 void
kxld_seg_populate_linkedit(KXLDSeg * seg,const KXLDSymtab * symtab,boolean_t is_32_bit,const KXLDArray * locrelocs,const KXLDArray * extrelocs,boolean_t target_supports_slideable_kexts,uint32_t splitinfolc_size)963 kxld_seg_populate_linkedit(KXLDSeg *seg, const KXLDSymtab *symtab, boolean_t is_32_bit
964 #if KXLD_PIC_KEXTS
965     , const KXLDArray *locrelocs
966     , const KXLDArray *extrelocs
967     , boolean_t target_supports_slideable_kexts
968 #endif  /* KXLD_PIC_KEXTS */
969     , uint32_t splitinfolc_size
970     )
971 {
972 	u_long size = 0;
973 
974 	size += kxld_symtab_get_macho_data_size(symtab, is_32_bit);
975 
976 #if KXLD_PIC_KEXTS
977 	if (target_supports_slideable_kexts) {
978 		size += kxld_reloc_get_macho_data_size(locrelocs, extrelocs);
979 	}
980 #endif  /* KXLD_PIC_KEXTS */
981 
982 	// 0 unless this is a split kext
983 	size += splitinfolc_size;
984 
985 	seg->vmsize = kxld_round_page_cross_safe(size);
986 }
987 
988 /*******************************************************************************
989 *******************************************************************************/
990 boolean_t
kxld_seg_is_split_seg(const KXLDSeg * seg)991 kxld_seg_is_split_seg(const KXLDSeg *seg)
992 {
993 	boolean_t       result = FALSE;
994 
995 	check(seg);
996 	if (isSplitKext) {
997 		if (kxld_seg_is_data_seg(seg) || kxld_seg_is_linkedit_seg(seg) ||
998 		    kxld_seg_is_text_exec_seg(seg) || kxld_seg_is_data_const_seg(seg) ||
999 		    kxld_seg_is_llvm_cov_seg(seg)) {
1000 			result = TRUE;
1001 		}
1002 	}
1003 
1004 	return result;
1005 }
1006 
1007 boolean_t
kxld_seg_is_text_seg(const KXLDSeg * seg)1008 kxld_seg_is_text_seg(const KXLDSeg *seg)
1009 {
1010 	boolean_t       result = FALSE;
1011 
1012 	check(seg);
1013 	result = !strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname));
1014 
1015 	return result;
1016 }
1017 
1018 boolean_t
kxld_seg_is_text_exec_seg(const KXLDSeg * seg)1019 kxld_seg_is_text_exec_seg(const KXLDSeg *seg)
1020 {
1021 	boolean_t       result = FALSE;
1022 
1023 	check(seg);
1024 	result = !strncmp(seg->segname, "__TEXT_EXEC", sizeof(seg->segname));
1025 
1026 	return result;
1027 }
1028 
1029 boolean_t
kxld_seg_is_data_seg(const KXLDSeg * seg)1030 kxld_seg_is_data_seg(const KXLDSeg *seg)
1031 {
1032 	boolean_t       result = FALSE;
1033 
1034 	check(seg);
1035 	result = !strncmp(seg->segname, SEG_DATA, sizeof(seg->segname));
1036 
1037 	return result;
1038 }
1039 
1040 boolean_t
kxld_seg_is_data_const_seg(const KXLDSeg * seg)1041 kxld_seg_is_data_const_seg(const KXLDSeg *seg)
1042 {
1043 	boolean_t       result = FALSE;
1044 
1045 	check(seg);
1046 	result = !strncmp(seg->segname, "__DATA_CONST", sizeof(seg->segname));
1047 
1048 	return result;
1049 }
1050 
1051 boolean_t
kxld_seg_is_linkedit_seg(const KXLDSeg * seg)1052 kxld_seg_is_linkedit_seg(const KXLDSeg *seg)
1053 {
1054 	boolean_t       result = FALSE;
1055 
1056 	check(seg);
1057 	result = !strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname));
1058 
1059 	return result;
1060 }
1061 
1062 boolean_t
kxld_seg_is_llvm_cov_seg(const KXLDSeg * seg)1063 kxld_seg_is_llvm_cov_seg(const KXLDSeg *seg)
1064 {
1065 	boolean_t       result = FALSE;
1066 
1067 	check(seg);
1068 	result = !strncmp(seg->segname, "__LLVM_COV", sizeof(seg->segname));
1069 
1070 	return result;
1071 }
1072