xref: /xnu-10063.101.15/libkern/kxld/kxld_splitinfolc.c (revision 94d3b452840153a99b38a3a9659680b2a006908e)
1 /*
2  * Copyright (c) 2016 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-o/loader.h>
30 #include <sys/types.h>
31 
32 #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld"
33 #include <AssertMacros.h>
34 
35 #include "kxld_util.h"
36 #include "kxld_splitinfolc.h"
37 
38 /*******************************************************************************
39 *******************************************************************************/
40 void
kxld_splitinfolc_init_from_macho(KXLDsplitinfolc * splitinfolc,struct linkedit_data_command * src)41 kxld_splitinfolc_init_from_macho(KXLDsplitinfolc *splitinfolc, struct linkedit_data_command *src)
42 {
43 	check(splitinfolc);
44 	check(src);
45 
46 	splitinfolc->cmdsize = src->cmdsize;
47 	splitinfolc->dataoff = src->dataoff;
48 	splitinfolc->datasize = src->datasize;
49 	splitinfolc->has_splitinfolc = TRUE;
50 }
51 
52 /*******************************************************************************
53 *******************************************************************************/
54 void
kxld_splitinfolc_clear(KXLDsplitinfolc * splitinfolc)55 kxld_splitinfolc_clear(KXLDsplitinfolc *splitinfolc)
56 {
57 	bzero(splitinfolc, sizeof(*splitinfolc));
58 }
59 
60 /*******************************************************************************
61 *******************************************************************************/
62 u_long
kxld_splitinfolc_get_macho_header_size(void)63 kxld_splitinfolc_get_macho_header_size(void)
64 {
65 	return sizeof(struct linkedit_data_command);
66 }
67 
68 /*******************************************************************************
69 *******************************************************************************/
70 kern_return_t
kxld_splitinfolc_export_macho(const KXLDsplitinfolc * splitinfolc,splitKextLinkInfo * linked_object,u_long * header_offset,u_long header_size,u_long * data_offset,u_long size)71 kxld_splitinfolc_export_macho(const KXLDsplitinfolc *splitinfolc,
72     splitKextLinkInfo *linked_object,
73     u_long *header_offset,
74     u_long header_size,
75     u_long *data_offset,
76     u_long size)
77 {
78 	kern_return_t       rval = KERN_FAILURE;
79 	struct linkedit_data_command *splitinfolc_hdr = NULL;
80 	u_char *            buf;
81 
82 	check(splitinfolc);
83 	check(linked_object);
84 	check(header_offset);
85 	check(data_offset);
86 
87 	buf = (u_char *)(linked_object->linkedKext);
88 	require_action(sizeof(*splitinfolc_hdr) <= header_size - *header_offset,
89 	    finish,
90 	    rval = KERN_FAILURE);
91 	splitinfolc_hdr = (struct linkedit_data_command *)((void *)(buf + *header_offset));
92 	*header_offset += sizeof(*splitinfolc_hdr);
93 
94 	if (buf + *data_offset > buf + size) {
95 		kxld_log(kKxldLogLinking, kKxldLogErr,
96 		    "\n OVERFLOW! linkedKext %p to %p (%lu) copy %p to %p (%u) <%s>",
97 		    (void *) buf,
98 		    (void *) (buf + size),
99 		    size,
100 		    (void *) (buf + *data_offset),
101 		    (void *) (buf + *data_offset + splitinfolc->datasize),
102 		    splitinfolc->datasize,
103 		    __func__);
104 		goto finish;
105 	}
106 
107 	// copy in the split info reloc data from kextExecutable. For example dataoff
108 	// in LC_SEGMENT_SPLIT_INFO load command points to the reloc data in the
109 	// __LINKEDIT segment.  In this case 65768 into the kextExecutable file is
110 	// the split seg reloc info (for 920 bytes)
111 //    Load command 9
112 //    cmd LC_SEGMENT_SPLIT_INFO
113 //    cmdsize 16
114 //    dataoff 65768
115 //    datasize 920
116 
117 
118 	memcpy(buf + *data_offset, linked_object->kextExecutable + splitinfolc->dataoff, splitinfolc->datasize);
119 
120 #if SPLIT_KEXTS_DEBUG
121 	u_char *dataPtr = buf + *data_offset;
122 
123 	kxld_log(kKxldLogLinking, kKxldLogErr,
124 	    "\n\n linkedKext %p to %p (%lu) copy %p to %p (%u) <%s>",
125 	    (void *) buf,
126 	    (void *) (buf + size),
127 	    size,
128 	    (void *) (dataPtr),
129 	    (void *) (dataPtr + splitinfolc->datasize),
130 	    splitinfolc->datasize,
131 	    __func__);
132 
133 	if (*(dataPtr + 0) != 0x7F) {
134 		kxld_log(kKxldLogLinking, kKxldLogErr,
135 		    "\n\n bad LC_SEGMENT_SPLIT_INFO: 0x%02X %02X %02X %02X %02X %02X %02X %02X at %p (buf %p + %lu) <%s>",
136 		    *(dataPtr + 0),
137 		    *(dataPtr + 1),
138 		    *(dataPtr + 2),
139 		    *(dataPtr + 3),
140 		    *(dataPtr + 4),
141 		    *(dataPtr + 5),
142 		    *(dataPtr + 6),
143 		    *(dataPtr + 7),
144 		    (void *) dataPtr,
145 		    (void *) buf,
146 		    *data_offset, __func__);
147 	}
148 #endif
149 
150 	// update the load command header
151 	splitinfolc_hdr->cmd = LC_SEGMENT_SPLIT_INFO;
152 	splitinfolc_hdr->cmdsize = (uint32_t) sizeof(*splitinfolc_hdr);
153 	splitinfolc_hdr->dataoff = (uint32_t)(*data_offset);
154 	splitinfolc_hdr->datasize = splitinfolc->datasize;
155 
156 	*data_offset += splitinfolc->datasize;
157 
158 	rval = KERN_SUCCESS;
159 
160 finish:
161 	return rval;
162 }
163