]> git.saurik.com Git - apple/security.git/blob - RegressionTests/secseccodeapitest.c
Security-59754.41.1.tar.gz
[apple/security.git] / RegressionTests / secseccodeapitest.c
1 //
2 // secseccodeapitest.c
3 // secseccodeapitest
4 //
5
6 #include "authd_private.h"
7
8 #include <stdio.h>
9 #include <xpc/xpc.h>
10 #include <Security/SecCode.h>
11 #include <libkern/OSAtomic.h>
12 #include <AssertMacros.h>
13
14 #define BEGIN() \
15 ({ \
16 fprintf(stdout, "[BEGIN] %s\n", __FUNCTION__); \
17 })
18
19 #define INFO(fmt, ...) \
20 ({ \
21 fprintf(stdout, fmt "\n", ##__VA_ARGS__); \
22 })
23
24 #define PASS(fmt, ...) \
25 ({ \
26 fprintf(stdout, "[PASS] %s " fmt "\n", __FUNCTION__, ##__VA_ARGS__); \
27 })
28
29 #define FAIL(fmt, ...) \
30 ({ \
31 fprintf(stdout, "[FAIL] %s " fmt "\n", __FUNCTION__, ##__VA_ARGS__); \
32 })
33
34 #define SAFE_RELEASE(x) \
35 ({ \
36 if (x) { \
37 CFRelease(x); \
38 x = NULL; \
39 } \
40 })
41
42 enum xpcConnectionStates {
43 kXPCConnectionStateNotCancelled = 0,
44 kXPCConnectionStateCancelled,
45 kXPCConnectionStateOkayToExit,
46 kXPCConnectionStateServerNotAvailable,
47 };
48
49 static int
50 _validatePathFromSecCode(SecCodeRef processRef, const char *path)
51 {
52 int ret = -1;
53 OSStatus status;
54 SecStaticCodeRef staticProcessRef = NULL;
55 CFURLRef pathURL = NULL;
56 CFStringRef pathString = NULL;
57
58 /* Get the StaticCodeRef for this SecCodeRef */
59 status = SecCodeCopyStaticCode(processRef, kSecCSDefaultFlags, &staticProcessRef);
60 require_noerr_action(status, exit, ret = -1);
61
62 INFO("Successfully created a SecStaticCodeRef");
63
64 /* Copy the path of requested service */
65 status = SecCodeCopyPath(staticProcessRef, kSecCSDefaultFlags, &pathURL);
66 require_noerr_action(status, exit, ret = -1);
67
68 INFO("Successfully created a CFURLRef");
69
70 /* Get the CFStringRef from the CFURLRef */
71 pathString = CFURLGetString(pathURL);
72 require_action(pathString, exit, ret = -1);
73
74 INFO("Successfully created a CFStingRef");
75
76 if (!strncmp(path, CFStringGetCStringPtr(pathString, kCFStringEncodingUTF8), strlen(path))) {
77 INFO("Successfully confirmed the location of requested service");
78 ret = 0;
79 } else {
80 INFO("Location of service incorrect: %s", CFStringGetCStringPtr(pathString, kCFStringEncodingUTF8));
81 ret = -1;
82 }
83
84 exit:
85 SAFE_RELEASE(pathURL);
86 SAFE_RELEASE(staticProcessRef);
87
88 return ret;
89 }
90
91 static int
92 CheckCreateWithXPCMessage(void)
93 {
94 BEGIN();
95
96 int ret;
97 OSStatus status;
98 xpc_connection_t connection = NULL;
99 xpc_object_t message = NULL, reply = NULL;
100 SecCodeRef processRef = NULL;
101 volatile static int xpcState = kXPCConnectionStateNotCancelled;
102
103 connection = xpc_connection_create(SECURITY_AUTH_NAME, NULL);
104 if (NULL == connection) {
105 FAIL("Unable to create an XPC connection with %s", SECURITY_AUTH_NAME);
106 return -1;
107 }
108
109 INFO("XPC Connection with %s created", SECURITY_AUTH_NAME);
110
111 xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
112 if (xpc_get_type(event) == XPC_TYPE_ERROR && event == XPC_ERROR_CONNECTION_INVALID) {
113 if (OSAtomicCompareAndSwapInt(kXPCConnectionStateCancelled, kXPCConnectionStateOkayToExit, &xpcState)) {
114 INFO("XPC Connection Cancelled");
115 } else {
116 xpcState = kXPCConnectionStateServerNotAvailable;
117 FAIL("Authorization server not available");
118 }
119 }
120 });
121
122 xpc_connection_resume(connection);
123
124 INFO("XPC Connection resumed");
125
126 /* Create an empty dictionary */
127 message = xpc_dictionary_create(NULL, NULL, 0);
128
129 /*
130 * Set _type to something invalid. This is done because authd will simply
131 * return an "invalid type" for this case, which means no state changes in
132 * the authd daemon.
133 */
134 xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_RIGHT_PROPERTIES+512);
135
136 /* Send object and wait for response */
137 reply = xpc_connection_send_message_with_reply_sync(connection, message);
138 xpc_release(message);
139
140 INFO("XPC Message received");
141
142 /* Create a SecCode using the XPC Message */
143 status = SecCodeCreateWithXPCMessage(reply, kSecCSDefaultFlags, &processRef);
144 if (status) {
145 FAIL("Unable to create a SecCodeRef from message reply [%d]", status);
146 xpc_release(reply);
147 return -1;
148 }
149 xpc_release(reply);
150
151 INFO("Successfully created a SecCodeRef");
152
153 const char *authdLocation = "file:///System/Library/Frameworks/Security.framework/Versions/A/XPCServices/authd.xpc/";
154 if (_validatePathFromSecCode(processRef, authdLocation)) {
155 FAIL("Unable to verify authd location");
156 ret = -1;
157 } else {
158 PASS("authd location successfully verified");
159 ret = 0;
160 }
161
162 SAFE_RELEASE(processRef);
163
164 // Potential race condition in getting an actual XPC_TYPE_ERROR vs getting
165 // a connection cancelled. We are okay with this since this is extremely unlikely...
166 if (OSAtomicCompareAndSwapInt(kXPCConnectionStateNotCancelled, kXPCConnectionStateCancelled, &xpcState)) {
167 xpc_connection_cancel(connection);
168 }
169
170 while (xpcState != kXPCConnectionStateOkayToExit) {
171 if (xpcState == kXPCConnectionStateServerNotAvailable) {
172 break;
173 }
174 usleep(1000 * 1);
175 }
176
177 return ret;
178 }
179
180 static int
181 CheckCreateWithXPCMessage_invalidXPCObject(void)
182 {
183 BEGIN();
184
185 OSStatus status;
186 xpc_object_t invalidObject = NULL;
187 SecCodeRef processRef = NULL;
188
189 /* Create an NULL object */
190 invalidObject = xpc_null_create();
191
192 INFO("Created a NULL object");
193
194 /* Try and acquire a SecCodeRef through the NULL object -- should fail with errSecCSInvalidObjectRef */
195 status = SecCodeCreateWithXPCMessage(invalidObject, kSecCSDefaultFlags, &processRef);
196 if (status != errSecCSInvalidObjectRef) {
197 FAIL("Return code unexpected [%d]", status);
198 return -1;
199 }
200
201 PASS("Got expected return code");
202 return 0;
203 }
204
205 static int
206 CheckCreateWithXPCMessage_NULLConnectionInObject(void)
207 {
208 BEGIN();
209
210 OSStatus status;
211 xpc_object_t emptyDictionary = NULL;
212 SecCodeRef processRef = NULL;
213
214 /* Create an empty dictionary object */
215 emptyDictionary = xpc_dictionary_create_empty();
216
217 INFO("Created an empty dictionary object");
218
219 /* Try and acquire a SecCodeRef through the empty dictionary -- should fail with errSecCSInvalidObjectRef */
220 status = SecCodeCreateWithXPCMessage(emptyDictionary, kSecCSDefaultFlags, &processRef);
221 if (status != errSecCSInvalidObjectRef) {
222 FAIL("Return code unexpected [%d]", status);
223 return -1;
224 }
225
226 PASS("Got expected return code");
227 return 0;
228 }
229
230 int main(void)
231 {
232 fprintf(stdout, "[TEST] secseccodeapitest\n");
233
234 int i;
235 int (*testList[])(void) = {
236 CheckCreateWithXPCMessage,
237 CheckCreateWithXPCMessage_invalidXPCObject,
238 CheckCreateWithXPCMessage_NULLConnectionInObject
239 };
240 const int numberOfTests = sizeof(testList) / sizeof(*testList);
241 int testResults[numberOfTests] = {0};
242
243 for (i = 0; i < numberOfTests; i++) {
244 testResults[i] = testList[i]();
245 }
246
247 fprintf(stdout, "[SUMMARY]\n");
248 for (i = 0; i < numberOfTests; i++) {
249 fprintf(stdout, "%d. %s\n", i+1, testResults[i] == 0 ? "Passed" : "Failed");
250 }
251
252 return 0;
253 }