]> git.saurik.com Git - apple/system_cmds.git/blob - proc_uuid_policy.tproj/proc_uuid_policy.c
0078cb976420254091acf8c1fd1a2f8b094002a7
[apple/system_cmds.git] / proc_uuid_policy.tproj / proc_uuid_policy.c
1 /*
2 * Copyright (c) 2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /* Header Declarations */
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <libkern/OSByteOrder.h>
28 #include <libproc.h>
29 #include <mach-o/fat.h>
30 #include <mach-o/loader.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/mman.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <uuid/uuid.h>
38 #include <System/sys/proc_uuid_policy.h>
39
40 /* Constant Declarations */
41 #define SUCCESS 0
42 #define FAILURE -1
43 #define MAX_CHUNK_SIZE 1024 * 1024 * 16
44
45 #ifndef PROC_UUID_ALT_DYLD_POLICY
46 #define PROC_UUID_ALT_DYLD_POLICY 0x00000004
47 #endif
48
49 /* UUID bucket */
50 struct uuid_bucket
51 {
52 unsigned int num_uuids;
53 uuid_t *binary_uuids;
54 };
55
56 /* Static Function Definitions */
57 static
58 void
59 usage();
60
61 static
62 int
63 parse_macho_uuids(
64 const char *path,
65 struct uuid_bucket *uuid_bucket);
66
67 static
68 int
69 parse_macho_slice(
70 const void *mapped,
71 const unsigned int offset,
72 const unsigned int slice_index,
73 struct uuid_bucket *uuid_bucket);
74
75 /* Function Definitions */
76 int
77 main(
78 int argc,
79 char **argv)
80 {
81 int exit_status = EXIT_FAILURE;
82 const char *verb_string;
83 const char *policy_string;
84 const char *uuid_path_string;
85 int operation = 0;
86 const char *operation_string = NULL;
87 int policy = 0;
88 uuid_t uuid;
89 struct stat sb;
90 struct uuid_bucket uuid_bucket = {0, NULL};
91 unsigned int i;
92 uuid_string_t uuid_string = "";
93
94 /*
95 * Parse the arguments.
96 */
97
98 if (argc != 4) {
99
100 usage();
101 goto BAIL;
102 }
103
104 verb_string = argv[1];
105 policy_string = argv[2];
106 uuid_path_string = argv[3];
107
108 if (strcmp(verb_string, "clear") == 0) {
109
110 operation = PROC_UUID_POLICY_OPERATION_CLEAR;
111 operation_string = "Clearing";
112 } else if (strcmp(verb_string, "add") == 0) {
113
114 operation = PROC_UUID_POLICY_OPERATION_ADD;
115 operation_string = "Adding";
116 } else if (strcmp(verb_string, "remove") == 0) {
117
118 operation = PROC_UUID_POLICY_OPERATION_REMOVE;
119 operation_string = "Removing";
120 } else {
121
122 fprintf(stderr, "Unknown verb: %s\n", verb_string);
123 usage();
124 goto BAIL;
125 }
126
127 if (strcmp(policy_string, "none") == 0) {
128
129 policy = PROC_UUID_POLICY_FLAGS_NONE;
130 } else if (strcmp(policy_string, "no_cellular") == 0) {
131
132 policy = PROC_UUID_NO_CELLULAR;
133 } else if (strcmp(policy_string, "necp") == 0) {
134
135 policy = PROC_UUID_NECP_APP_POLICY;
136 } else if (strcmp(policy_string, "alt-dyld") == 0) {
137
138 policy = PROC_UUID_ALT_DYLD_POLICY;
139 } else {
140
141 fprintf(stderr, "Unknown policy: %s\n", policy_string);
142 usage();
143 goto BAIL;
144 }
145
146 if (uuid_parse(uuid_path_string, uuid) == -1) {
147
148 /* Is this a path to a macho file? */
149 if (stat(uuid_path_string, &sb) == -1) {
150
151 fprintf(stderr, "%s is not a UUID nor path: %s\n", uuid_path_string, strerror(errno));
152 goto BAIL;
153 } else {
154
155 /* Parse the UUID from the macho file. */
156 if (parse_macho_uuids(uuid_path_string, &uuid_bucket)) {
157
158 fprintf(stderr, "Could not parse %s for its UUID\n", uuid_path_string);
159 goto BAIL;
160 }
161 }
162 } else {
163
164 uuid_bucket.num_uuids = 1;
165 uuid_bucket.binary_uuids = calloc(1, sizeof(uuid_t));
166 if (uuid_bucket.binary_uuids == NULL) {
167
168 fprintf(stderr, "Could not allocate single UUID bucket\n");
169 goto BAIL;
170 }
171
172 memcpy(uuid_bucket.binary_uuids[0], uuid, sizeof(uuid_t));
173 }
174
175 for (i = 0; i < uuid_bucket.num_uuids; i++) {
176
177 uuid_unparse(uuid_bucket.binary_uuids[i], uuid_string);
178 printf("%s the %s policy for %s\n", operation_string, policy_string, uuid_string);
179
180 if (proc_uuid_policy(operation, uuid_bucket.binary_uuids[i], sizeof(uuid_t), policy) == -1) {
181
182 fprintf(stderr, "Could not enable the UUID policy: %s\n", strerror(errno));
183 goto BAIL;
184 }
185 }
186
187 /* Set the exit status to success. */
188 exit_status = EXIT_SUCCESS;
189
190 BAIL:
191
192 /*
193 * Clean up.
194 */
195
196 if (uuid_bucket.binary_uuids != NULL) {
197
198 free(uuid_bucket.binary_uuids);
199 }
200
201 return exit_status;
202 }
203
204 /* Static Function Definitions */
205 static
206 void
207 usage(void)
208 {
209 fprintf(stderr, "usage: %s <verb> <policy> <uuid | path>\n", getprogname());
210 fprintf(stderr, "Verbs:\n");
211 fprintf(stderr, "\tclear\tClear all policies for a given UUID\n");
212 fprintf(stderr, "\tadd\tAdd a specific policy\n");
213 fprintf(stderr, "\tremove\tRemove a specific policy\n");
214 fprintf(stderr, "\n");
215 fprintf(stderr, "Policies:\n");
216 fprintf(stderr, "\tnone\t\tPROC_UUID_POLICY_FLAGS_NONE\n");
217 fprintf(stderr, "\tno_cellular\tPROC_UUID_NO_CELLULAR\n");
218 fprintf(stderr, "\tnecp\t\tPROC_UUID_NECP_APP_POLICY\n");
219 fprintf(stderr, "\talt-dyld\tPROC_UUID_ALT_DYLD_POLICY\n");
220 }
221
222 static
223 int
224 parse_macho_uuids(
225 const char *path,
226 struct uuid_bucket *uuid_bucket)
227 {
228 int result = FAILURE;
229 int fd = -1;
230 struct stat sb;
231 void *mapped = MAP_FAILED;
232
233 struct fat_header *fat_header_pointer;
234 struct fat_arch *fat_arch_pointer;
235 bool swapped = false;
236
237 uint32_t nfat_arch = 0;
238 unsigned int i;
239 uint32_t arch_offset;
240 uint32_t arch_size;
241
242 /* Open the file and determine its size. */
243 fd = open(path, O_RDONLY);
244 if (fd == -1) {
245
246 fprintf(stderr, "Could not open %s: %s\n", path, strerror(errno));
247 goto BAIL;
248 }
249
250 if (fstat(fd, &sb) == -1) {
251
252 fprintf(stderr, "Could not fstat %s: %s\n", path, strerror(errno));
253 goto BAIL;
254 }
255
256 /* Memory map the file. */
257 mapped = mmap (0, (size_t)sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
258 if (mapped == MAP_FAILED) {
259
260 fprintf(stderr, "Could not memory map %s: %s\n", path, strerror(errno));
261 goto BAIL;
262 }
263
264 /*
265 * Determine the file type.
266 */
267
268 fat_header_pointer = (struct fat_header *) mapped;
269
270 switch (fat_header_pointer->magic) {
271
272 case FAT_MAGIC: {
273
274 nfat_arch = fat_header_pointer->nfat_arch;
275 }break;
276
277 case FAT_CIGAM: {
278
279 swapped = true;
280 nfat_arch = OSSwapInt32(fat_header_pointer->nfat_arch);
281 }break;
282
283 case MH_MAGIC:
284 case MH_CIGAM:
285 case MH_MAGIC_64:
286 case MH_CIGAM_64: {
287
288 uuid_bucket->num_uuids = 1;
289
290 uuid_bucket->binary_uuids = calloc(1, sizeof(uuid_t));
291 if (uuid_bucket->binary_uuids == NULL) {
292
293 fprintf(stderr, "Could not allocate a UUID\n");
294 goto BAIL;
295 }
296
297 if (parse_macho_slice(mapped, 0, 0, uuid_bucket)) {
298
299 fprintf(stderr, "Could not parse slice\n");
300 goto BAIL;
301 }
302 }break;
303
304 default: {
305
306 fprintf(stderr, "Unknown magic: %d\n", fat_header_pointer->magic);
307 goto BAIL;
308 }
309 }
310
311 if (nfat_arch > 0) {
312
313 uuid_bucket->num_uuids = nfat_arch;
314
315 uuid_bucket->binary_uuids = calloc(nfat_arch, sizeof(uuid_t));
316 if (uuid_bucket->binary_uuids == NULL) {
317
318 fprintf(stderr, "Could not allocate %d UUIDs\n", nfat_arch);
319 goto BAIL;
320 }
321
322 for (i = 0; i < nfat_arch; i++) {
323
324 fat_arch_pointer = (struct fat_arch *)(mapped + sizeof(struct fat_header) + (sizeof(struct fat_arch) * i));
325
326 if (swapped) {
327
328 arch_offset = OSSwapInt32(fat_arch_pointer->offset);
329 arch_size = OSSwapInt32(fat_arch_pointer->size);
330 } else {
331
332 arch_offset = fat_arch_pointer->offset;
333 arch_size = fat_arch_pointer->size;
334 }
335
336 if (parse_macho_slice(mapped, arch_offset, i, uuid_bucket)) {
337
338 fprintf(stderr, "Could not parse slice %d of %d\n", i, nfat_arch);
339 goto BAIL;
340 }
341 }
342 }
343
344 /* Set the result to success. */
345 result = SUCCESS;
346
347 BAIL:
348
349 /*
350 * Clean up.
351 */
352
353 if (mapped != MAP_FAILED) {
354
355 (void) munmap(mapped, (size_t)sb.st_size);
356 mapped = MAP_FAILED;
357 }
358
359 if (fd != -1) {
360
361 (void) close(fd);
362 fd = -1;
363 }
364
365 return result;
366 }
367
368 static
369 int
370 parse_macho_slice(
371 const void *mapped,
372 const unsigned int offset,
373 const unsigned int slice_index,
374 struct uuid_bucket *uuid_bucket)
375 {
376 int result = FAILURE;
377
378 struct mach_header *mach_header_pointer;
379 struct mach_header_64 *mach_header_64_pointer;
380 struct load_command *load_command_pointer;
381
382 bool swapped = false;
383
384 unsigned int number_load_commands = 0;
385 unsigned int i;
386
387 bool found_uuid_load_command = false;
388 struct uuid_command *uuid_load_command_pointer = NULL;
389
390 mach_header_pointer = (struct mach_header *)(mapped + offset);
391
392 switch (mach_header_pointer->magic) {
393
394 case FAT_MAGIC: {
395
396 fprintf(stderr, "FAT_MAGIC\n");
397 goto BAIL;
398 }break;
399
400 case FAT_CIGAM: {
401
402 fprintf(stderr, "FAT_CIGAM\n");
403 goto BAIL;
404 }break;
405
406 case MH_MAGIC: {
407
408 number_load_commands = mach_header_pointer->ncmds;
409 load_command_pointer = (struct load_command *)(void *)(mach_header_pointer + 1);
410 }break;
411
412 case MH_CIGAM: {
413
414 swapped = true;
415
416 number_load_commands = OSSwapInt32(mach_header_pointer->ncmds);
417 load_command_pointer = (struct load_command *)(void *)(mach_header_pointer + 1);
418 }break;
419
420 case MH_MAGIC_64: {
421
422 mach_header_64_pointer = (struct mach_header_64 *)(mapped + offset);
423 number_load_commands = mach_header_64_pointer->ncmds;
424
425 load_command_pointer = (struct load_command *)(void *)(mach_header_64_pointer + 1);
426 }break;
427
428 case MH_CIGAM_64: {
429
430 swapped = true;
431
432 mach_header_64_pointer = (struct mach_header_64 *)(mapped + offset);
433 number_load_commands = OSSwapInt32(mach_header_64_pointer->ncmds);
434
435 load_command_pointer = (struct load_command *)(void *)(mach_header_64_pointer + 1);
436 }break;
437
438 default: {
439
440 fprintf(stderr, "Unknown magic: %d\n", mach_header_pointer->magic);
441 goto BAIL;
442 }
443 }
444
445 /* Walk the load commands looking for LC_UUID. */
446 for (i = 0; i < number_load_commands; i++) {
447
448 if (load_command_pointer->cmd == LC_UUID) {
449
450 found_uuid_load_command = true;
451 uuid_load_command_pointer = (struct uuid_command *)load_command_pointer;
452 memcpy(uuid_bucket->binary_uuids[slice_index], uuid_load_command_pointer->uuid, sizeof(uuid_t));
453 }
454
455 load_command_pointer = (struct load_command *)((uintptr_t)load_command_pointer + load_command_pointer->cmdsize);
456 }
457
458 if (found_uuid_load_command == false) {
459
460 fprintf(stderr, "Could not find LC_UUID\n");
461 goto BAIL;
462 }
463
464 /* Set the result to success. */
465 result = SUCCESS;
466
467 BAIL:
468
469 return result;
470 }