2 * Copyright (c) 2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 /* Header Declarations */
27 #include <libkern/OSByteOrder.h>
29 #include <mach-o/fat.h>
30 #include <mach-o/loader.h>
37 #include <uuid/uuid.h>
38 #include <System/sys/proc_uuid_policy.h>
40 /* Constant Declarations */
43 #define MAX_CHUNK_SIZE 1024 * 1024 * 16
45 #ifndef PROC_UUID_ALT_DYLD_POLICY
46 #define PROC_UUID_ALT_DYLD_POLICY 0x00000004
52 unsigned int num_uuids
;
56 /* Static Function Definitions */
65 struct uuid_bucket
*uuid_bucket
);
71 const unsigned int offset
,
72 const unsigned int slice_index
,
73 struct uuid_bucket
*uuid_bucket
);
75 /* Function Definitions */
81 int exit_status
= EXIT_FAILURE
;
82 const char *verb_string
;
83 const char *policy_string
;
84 const char *uuid_path_string
;
86 const char *operation_string
= NULL
;
90 struct uuid_bucket uuid_bucket
= {0, NULL
};
92 uuid_string_t uuid_string
= "";
95 * Parse the arguments.
104 verb_string
= argv
[1];
105 policy_string
= argv
[2];
106 uuid_path_string
= argv
[3];
108 if (strcmp(verb_string
, "clear") == 0) {
110 operation
= PROC_UUID_POLICY_OPERATION_CLEAR
;
111 operation_string
= "Clearing";
112 } else if (strcmp(verb_string
, "add") == 0) {
114 operation
= PROC_UUID_POLICY_OPERATION_ADD
;
115 operation_string
= "Adding";
116 } else if (strcmp(verb_string
, "remove") == 0) {
118 operation
= PROC_UUID_POLICY_OPERATION_REMOVE
;
119 operation_string
= "Removing";
122 fprintf(stderr
, "Unknown verb: %s\n", verb_string
);
127 if (strcmp(policy_string
, "none") == 0) {
129 policy
= PROC_UUID_POLICY_FLAGS_NONE
;
130 } else if (strcmp(policy_string
, "no_cellular") == 0) {
132 policy
= PROC_UUID_NO_CELLULAR
;
133 } else if (strcmp(policy_string
, "necp") == 0) {
135 policy
= PROC_UUID_NECP_APP_POLICY
;
136 } else if (strcmp(policy_string
, "alt-dyld") == 0) {
138 policy
= PROC_UUID_ALT_DYLD_POLICY
;
141 fprintf(stderr
, "Unknown policy: %s\n", policy_string
);
146 if (uuid_parse(uuid_path_string
, uuid
) == -1) {
148 /* Is this a path to a macho file? */
149 if (stat(uuid_path_string
, &sb
) == -1) {
151 fprintf(stderr
, "%s is not a UUID nor path: %s\n", uuid_path_string
, strerror(errno
));
155 /* Parse the UUID from the macho file. */
156 if (parse_macho_uuids(uuid_path_string
, &uuid_bucket
)) {
158 fprintf(stderr
, "Could not parse %s for its UUID\n", uuid_path_string
);
164 uuid_bucket
.num_uuids
= 1;
165 uuid_bucket
.binary_uuids
= calloc(1, sizeof(uuid_t
));
166 if (uuid_bucket
.binary_uuids
== NULL
) {
168 fprintf(stderr
, "Could not allocate single UUID bucket\n");
172 memcpy(uuid_bucket
.binary_uuids
[0], uuid
, sizeof(uuid_t
));
175 for (i
= 0; i
< uuid_bucket
.num_uuids
; i
++) {
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
);
180 if (proc_uuid_policy(operation
, uuid_bucket
.binary_uuids
[i
], sizeof(uuid_t
), policy
) == -1) {
182 fprintf(stderr
, "Could not enable the UUID policy: %s\n", strerror(errno
));
187 /* Set the exit status to success. */
188 exit_status
= EXIT_SUCCESS
;
196 if (uuid_bucket
.binary_uuids
!= NULL
) {
198 free(uuid_bucket
.binary_uuids
);
204 /* Static Function Definitions */
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");
226 struct uuid_bucket
*uuid_bucket
)
228 int result
= FAILURE
;
231 void *mapped
= MAP_FAILED
;
233 struct fat_header
*fat_header_pointer
;
234 struct fat_arch
*fat_arch_pointer
;
235 bool swapped
= false;
237 uint32_t nfat_arch
= 0;
239 uint32_t arch_offset
;
242 /* Open the file and determine its size. */
243 fd
= open(path
, O_RDONLY
);
246 fprintf(stderr
, "Could not open %s: %s\n", path
, strerror(errno
));
250 if (fstat(fd
, &sb
) == -1) {
252 fprintf(stderr
, "Could not fstat %s: %s\n", path
, strerror(errno
));
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
) {
260 fprintf(stderr
, "Could not memory map %s: %s\n", path
, strerror(errno
));
265 * Determine the file type.
268 fat_header_pointer
= (struct fat_header
*) mapped
;
270 switch (fat_header_pointer
->magic
) {
274 nfat_arch
= fat_header_pointer
->nfat_arch
;
280 nfat_arch
= OSSwapInt32(fat_header_pointer
->nfat_arch
);
288 uuid_bucket
->num_uuids
= 1;
290 uuid_bucket
->binary_uuids
= calloc(1, sizeof(uuid_t
));
291 if (uuid_bucket
->binary_uuids
== NULL
) {
293 fprintf(stderr
, "Could not allocate a UUID\n");
297 if (parse_macho_slice(mapped
, 0, 0, uuid_bucket
)) {
299 fprintf(stderr
, "Could not parse slice\n");
306 fprintf(stderr
, "Unknown magic: %d\n", fat_header_pointer
->magic
);
313 uuid_bucket
->num_uuids
= nfat_arch
;
315 uuid_bucket
->binary_uuids
= calloc(nfat_arch
, sizeof(uuid_t
));
316 if (uuid_bucket
->binary_uuids
== NULL
) {
318 fprintf(stderr
, "Could not allocate %d UUIDs\n", nfat_arch
);
322 for (i
= 0; i
< nfat_arch
; i
++) {
324 fat_arch_pointer
= (struct fat_arch
*)(mapped
+ sizeof(struct fat_header
) + (sizeof(struct fat_arch
) * i
));
328 arch_offset
= OSSwapInt32(fat_arch_pointer
->offset
);
329 arch_size
= OSSwapInt32(fat_arch_pointer
->size
);
332 arch_offset
= fat_arch_pointer
->offset
;
333 arch_size
= fat_arch_pointer
->size
;
336 if (parse_macho_slice(mapped
, arch_offset
, i
, uuid_bucket
)) {
338 fprintf(stderr
, "Could not parse slice %d of %d\n", i
, nfat_arch
);
344 /* Set the result to success. */
353 if (mapped
!= MAP_FAILED
) {
355 (void) munmap(mapped
, (size_t)sb
.st_size
);
372 const unsigned int offset
,
373 const unsigned int slice_index
,
374 struct uuid_bucket
*uuid_bucket
)
376 int result
= FAILURE
;
378 struct mach_header
*mach_header_pointer
;
379 struct mach_header_64
*mach_header_64_pointer
;
380 struct load_command
*load_command_pointer
;
382 bool swapped
= false;
384 unsigned int number_load_commands
= 0;
387 bool found_uuid_load_command
= false;
388 struct uuid_command
*uuid_load_command_pointer
= NULL
;
390 mach_header_pointer
= (struct mach_header
*)(mapped
+ offset
);
392 switch (mach_header_pointer
->magic
) {
396 fprintf(stderr
, "FAT_MAGIC\n");
402 fprintf(stderr
, "FAT_CIGAM\n");
408 number_load_commands
= mach_header_pointer
->ncmds
;
409 load_command_pointer
= (struct load_command
*)(void *)(mach_header_pointer
+ 1);
416 number_load_commands
= OSSwapInt32(mach_header_pointer
->ncmds
);
417 load_command_pointer
= (struct load_command
*)(void *)(mach_header_pointer
+ 1);
422 mach_header_64_pointer
= (struct mach_header_64
*)(mapped
+ offset
);
423 number_load_commands
= mach_header_64_pointer
->ncmds
;
425 load_command_pointer
= (struct load_command
*)(void *)(mach_header_64_pointer
+ 1);
432 mach_header_64_pointer
= (struct mach_header_64
*)(mapped
+ offset
);
433 number_load_commands
= OSSwapInt32(mach_header_64_pointer
->ncmds
);
435 load_command_pointer
= (struct load_command
*)(void *)(mach_header_64_pointer
+ 1);
440 fprintf(stderr
, "Unknown magic: %d\n", mach_header_pointer
->magic
);
445 /* Walk the load commands looking for LC_UUID. */
446 for (i
= 0; i
< number_load_commands
; i
++) {
448 if (load_command_pointer
->cmd
== LC_UUID
) {
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
));
455 load_command_pointer
= (struct load_command
*)((uintptr_t)load_command_pointer
+ load_command_pointer
->cmdsize
);
458 if (found_uuid_load_command
== false) {
460 fprintf(stderr
, "Could not find LC_UUID\n");
464 /* Set the result to success. */