]>
git.saurik.com Git - apple/xnu.git/blob - tests/kernel_uuid_match.c
1 #include <darwintest.h>
8 #include <sys/sysctl.h>
9 #include <TargetConditionals.h>
14 #include <mach-o/loader.h>
15 #include <mach-o/dyld.h>
16 #include <mach-o/swap.h>
17 #include <libkern/OSByteOrder.h>
21 #if TARGET_OS_MAC && !TARGET_OS_EMBEDDED
23 #define KERNEL_SEARCH_DIR "/System/Library/Kernels/*"
25 //running on a different OS (e.g. iOS, watchOS, etc.)
26 #define KERNEL_SEARCH_DIR "/*"
29 #define SWAP32(v) v = OSSwapInt32(v)
32 /* opens and maps the file at [path] in memory,
33 * sets the length in [len] and returns a pointer
34 * to the beginning of the memory region or NULL
35 * if unable to open and map the file
37 static void *open_file(char *path
, size_t *len
) {
39 if ((fd
= open(path
, O_RDONLY
)) < 0) {
42 *len
= (size_t)lseek(fd
, (off_t
)0, SEEK_END
);
43 void *p
= mmap(NULL
, *len
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
45 if (p
== MAP_FAILED
) {
51 #pragma clang diagnostic push
52 #pragma clang diagnostic ignored "-Wsign-conversion"
53 static void __swap_mach_header(struct mach_header
*header
) {
54 SWAP32(header
->magic
);
55 SWAP32(header
->cputype
);
56 SWAP32(header
->cpusubtype
);
57 SWAP32(header
->filetype
);
58 SWAP32(header
->ncmds
);
59 SWAP32(header
->sizeofcmds
);
60 SWAP32(header
->flags
);
63 static void __swap_mach_header_64(struct mach_header_64
*header
) {
64 SWAP32(header
->magic
);
65 SWAP32(header
->cputype
);
66 SWAP32(header
->cpusubtype
);
67 SWAP32(header
->filetype
);
68 SWAP32(header
->ncmds
);
69 SWAP32(header
->sizeofcmds
);
70 SWAP32(header
->flags
);
72 #pragma clang diagnostic pop
74 /* parses the uuid from the file at [path] and sets the uuid in [uuid]
75 * returns true if successfully parses the file, returns false otherwise
76 * (e.g. the file is not a Mach-O binary)
78 static bool parse_binary_uuid(char *path
, uuid_t uuid
) {
80 bool should_swap
= false;
81 unsigned int ncmds
= 0;
82 struct load_command
*lc
= NULL
;
85 struct mach_header
*h
= open_file(path
, &len
);
89 if (h
->magic
== MH_MAGIC
|| h
->magic
== MH_CIGAM
) {
91 struct mach_header
*header
= h
;
92 if (header
->magic
== MH_CIGAM
) {
93 __swap_mach_header(header
);
96 ncmds
= header
->ncmds
;
97 //the first load command is after the header
98 lc
= (struct load_command
*)(header
+ 1);
99 } else if (h
->magic
== MH_MAGIC_64
|| h
->magic
== MH_CIGAM_64
) {
101 struct mach_header_64
*header
= (struct mach_header_64
*)h
;
102 if (header
->magic
== MH_CIGAM_64
) {
103 __swap_mach_header_64(header
);
106 ncmds
= header
->ncmds
;
107 lc
= (struct load_command
*)(header
+ 1);
109 //this is not a Mach-O binary, or it is a FAT binary
113 for (unsigned int i
= 0; i
< ncmds
; i
++) {
114 uint32_t cmd
= lc
->cmd
;
115 uint32_t cmdsize
= lc
->cmdsize
;
120 if (cmd
== LC_UUID
) {
121 struct uuid_command
*uuid_cmd
=
122 (struct uuid_command
*)lc
;
123 uuid_copy(uuid
, uuid_cmd
->uuid
);
124 uuid_string_t tuuid_str
;
125 uuid_unparse(uuid
, tuuid_str
);
126 T_LOG("Trying test UUID %s", tuuid_str
);
130 lc
= (struct load_command
*)((uintptr_t)lc
+ cmdsize
);
136 /* uses the sysctl command line tool to get the uuid
137 * of the currently running kernel
139 static void get_system_kernel_uuid(uuid_t kuuid
) {
140 char kuuid_line
[MAX_LEN
];
141 memset(kuuid_line
, 0, sizeof(kuuid_line
));
142 size_t len
= sizeof(kuuid_line
);
143 int ret
= sysctlbyname("kern.uuid", kuuid_line
, &len
, NULL
, 0);
144 T_ASSERT_POSIX_SUCCESS(ret
, "sysctl kern.uuid");
146 T_ASSERT_TRUE(uuid_parse(kuuid_line
, kuuid
) == 0,
147 "Parse running kernel uuid");
150 /* compares [kuuid] to the uuid in each of the kernel binaries on OS's
151 * other than macOS (there can be multiple kernel binaries if the mastering
152 * process doesn't remove all of the irrelevant binaries)
154 static void find_and_compare_test_uuids(char *search_path
, uuid_t kuuid
) {
156 int ret
= glob(search_path
, 0, NULL
, &g
);
157 T_WITH_ERRNO
; T_ASSERT_EQ(ret
, 0, "glob %s", search_path
);
160 for (int i
= 0; i
< g
.gl_matchc
; i
++) {
161 char *path
= g
.gl_pathv
[i
];
163 //check that [path] is the path for a file (not a directory, device, etc.)
165 int ret
= stat(path
, &s
);
166 T_ASSERT_POSIX_SUCCESS(ret
, "stat %s", path
);
167 if ((s
.st_mode
& S_IFREG
) == 0) {
171 T_LOG("Reading file at path: %s", path
);
173 if (parse_binary_uuid(path
, tuuid
) &&
174 uuid_compare(kuuid
, tuuid
) == 0) {
180 T_EXPECT_TRUE(pass
, "The sources match");
183 T_DECL(uuid_match
, "Compare the running kernel UUID to kernel binaries.")
187 get_system_kernel_uuid(kuuid
);
188 uuid_string_t kuuid_str
;
189 uuid_unparse(kuuid
, kuuid_str
);
190 T_LOG("Got running kernel UUID %s", kuuid_str
);
191 find_and_compare_test_uuids(KERNEL_SEARCH_DIR
, kuuid
);