1 /*
2 * Copyright (c) 2014-2021 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
29 #include <string.h>
30 #include <sys/systm.h>
31 #include <sys/types.h>
32 #include <sys/syslog.h>
33 #include <sys/queue.h>
34 #include <sys/malloc.h>
35 #include <sys/kernel.h>
36 #include <sys/kern_control.h>
37 #include <sys/mbuf.h>
38 #include <sys/kpi_mbuf.h>
39 #include <sys/sysctl.h>
40 #include <sys/priv.h>
41 #include <sys/kern_event.h>
42 #include <sys/sysproto.h>
43 #include <net/network_agent.h>
44 #include <net/if_var.h>
45 #include <net/necp.h>
46 #include <os/log.h>
47
48 u_int32_t netagent_debug = LOG_NOTICE; // 0=None, 1=Basic
49
50 SYSCTL_NODE(_net, OID_AUTO, netagent, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NetworkAgent");
51 SYSCTL_INT(_net_netagent, OID_AUTO, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &netagent_debug, 0, "");
52
53 static int netagent_registered_count = 0;
54 SYSCTL_INT(_net_netagent, OID_AUTO, registered_count, CTLFLAG_RD | CTLFLAG_LOCKED,
55 &netagent_registered_count, 0, "");
56
57 static int netagent_active_count = 0;
58 SYSCTL_INT(_net_netagent, OID_AUTO, active_count, CTLFLAG_RD | CTLFLAG_LOCKED,
59 &netagent_active_count, 0, "");
60
61 #define NETAGENTLOG(level, format, ...) do { \
62 if (level <= netagent_debug) { \
63 if (level == LOG_ERR) { \
64 os_log_error(OS_LOG_DEFAULT, "%s: " format "\n", __FUNCTION__, __VA_ARGS__); \
65 } else { \
66 os_log(OS_LOG_DEFAULT, "%s: " format "\n", __FUNCTION__, __VA_ARGS__); \
67 } \
68 } \
69 } while (0)
70
71 #define NETAGENTLOG0(level, msg) do { \
72 if (level <= netagent_debug) { \
73 if (level == LOG_ERR) { \
74 os_log_error(OS_LOG_DEFAULT, "%s: %s\n", __FUNCTION__, msg); \
75 } else { \
76 os_log(OS_LOG_DEFAULT, "%s: %s\n", __FUNCTION__, msg); \
77 } \
78 } \
79 } while (0)
80
81 struct netagent_client {
82 LIST_ENTRY(netagent_client) client_chain;
83 uuid_t client_id;
84 uuid_t client_proc_uuid;
85 pid_t client_pid;
86 };
87
88 LIST_HEAD(netagent_client_list_s, netagent_client);
89
90 struct netagent_token {
91 TAILQ_ENTRY(netagent_token) token_chain;
92 u_int32_t token_length;
93 u_int8_t *token_bytes;
94 };
95
96 TAILQ_HEAD(netagent_token_list_s, netagent_token);
97
98 #define NETAGENT_MAX_CLIENT_ERROR_COUNT 32
99
100 struct netagent_wrapper {
101 LIST_ENTRY(netagent_wrapper) master_chain;
102 u_int32_t control_unit;
103 netagent_event_f event_handler;
104 void *event_context;
105 u_int32_t generation;
106 u_int64_t use_count;
107 u_int32_t token_count;
108 u_int32_t token_low_water;
109 int32_t last_client_error;
110 u_int32_t client_error_count;
111 u_int8_t __pad_bytes[3];
112 struct netagent_token_list_s token_list;
113 struct netagent_client_list_s pending_triggers_list;
114 struct netagent *netagent;
115 };
116
117 struct netagent_session {
118 u_int32_t control_unit; // A control unit of 0 indicates an agent owned by the kernel
119 struct netagent_wrapper *wrapper;
120 netagent_event_f event_handler;
121 void *event_context;
122 };
123
124 typedef enum {
125 kNetagentErrorDomainPOSIX = 0,
126 kNetagentErrorDomainUserDefined = 1,
127 } netagent_error_domain_t;
128
129 static LIST_HEAD(_netagent_list, netagent_wrapper) master_netagent_list =
130 LIST_HEAD_INITIALIZER(master_netagent_list);
131
132 // Protected by netagent_lock
133 static u_int32_t g_next_generation = 1;
134
135 static kern_ctl_ref netagent_kctlref;
136 static u_int32_t netagent_family;
137 static LCK_GRP_DECLARE(netagent_mtx_grp, NETAGENT_CONTROL_NAME);
138 static LCK_RW_DECLARE(netagent_lock, &netagent_mtx_grp);
139
140 static errno_t netagent_register_control(void);
141 static errno_t netagent_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac,
142 void **unitinfo);
143 static errno_t netagent_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo);
144 static errno_t netagent_ctl_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
145 mbuf_t m, int flags);
146 static void netagent_ctl_rcvd(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int flags);
147 static errno_t netagent_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
148 int opt, void *data, size_t *len);
149 static errno_t netagent_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo,
150 int opt, void *data, size_t len);
151
152 static int netagent_send_ctl_data(u_int32_t control_unit, u_int8_t *buffer, size_t buffer_size);
153
154 static struct netagent_session *netagent_create_session(u_int32_t control_unit);
155 static void netagent_delete_session(struct netagent_session *session);
156
157 // Register
158 static void netagent_handle_register_message(struct netagent_session *session, u_int32_t message_id,
159 size_t payload_length, mbuf_t packet, size_t offset);
160 static errno_t netagent_handle_register_setopt(struct netagent_session *session, u_int8_t *payload,
161 size_t payload_length);
162
163 // Unregister
164 static void netagent_handle_unregister_message(struct netagent_session *session, u_int32_t message_id,
165 size_t payload_length, mbuf_t packet, size_t offset);
166 static errno_t netagent_handle_unregister_setopt(struct netagent_session *session, u_int8_t *payload,
167 size_t payload_length);
168
169 // Update
170 static void netagent_handle_update_message(struct netagent_session *session, u_int32_t message_id,
171 size_t payload_length, mbuf_t packet, size_t offset);
172 static errno_t netagent_handle_update_setopt(struct netagent_session *session, u_int8_t *payload,
173 size_t payload_length);
174
175 // Assign nexus
176 static void netagent_handle_assign_nexus_message(struct netagent_session *session, u_int32_t message_id,
177 size_t payload_length, mbuf_t packet, size_t offset);
178 static errno_t netagent_handle_assign_nexus_setopt(struct netagent_session *session, u_int8_t *payload,
179 size_t payload_length);
180
181 // Assign group
182 static errno_t netagent_handle_assign_group_setopt(struct netagent_session *session, u_int8_t *payload,
183 size_t payload_length);
184
185 // Set/get assert count
186 static errno_t netagent_handle_use_count_setopt(struct netagent_session *session, u_int8_t *payload, size_t payload_length);
187 static errno_t netagent_handle_use_count_getopt(struct netagent_session *session, u_int8_t *buffer, size_t *buffer_length);
188
189 // Manage tokens
190 static errno_t netagent_handle_add_token_setopt(struct netagent_session *session, u_int8_t *payload, size_t payload_length);
191 static errno_t netagent_handle_flush_tokens_setopt(struct netagent_session *session, u_int8_t *payload, size_t payload_length);
192 static errno_t netagent_handle_token_count_getopt(struct netagent_session *session, u_int8_t *buffer, size_t *buffer_length);
193 static errno_t netagent_handle_token_low_water_setopt(struct netagent_session *session, u_int8_t *buffer, size_t buffer_length);
194 static errno_t netagent_handle_token_low_water_getopt(struct netagent_session *session, u_int8_t *buffer, size_t *buffer_length);
195
196 // Client error
197 static errno_t netagent_handle_reset_client_error_setopt(struct netagent_session *session, u_int8_t *payload, size_t payload_length);
198
199 static void netagent_handle_get(struct netagent_session *session, u_int32_t message_id,
200 size_t payload_length, mbuf_t packet, size_t offset);
201
202 static struct netagent_wrapper *netagent_find_agent_with_uuid(uuid_t uuid);
203
204 errno_t
netagent_init(void)205 netagent_init(void)
206 {
207 return netagent_register_control();
208 }
209
210 static errno_t
netagent_register_control(void)211 netagent_register_control(void)
212 {
213 struct kern_ctl_reg kern_ctl;
214 errno_t result = 0;
215
216 // Find a unique value for our interface family
217 result = mbuf_tag_id_find(NETAGENT_CONTROL_NAME, &netagent_family);
218 if (result != 0) {
219 NETAGENTLOG(LOG_ERR, "mbuf_tag_id_find_internal failed: %d", result);
220 return result;
221 }
222
223 bzero(&kern_ctl, sizeof(kern_ctl));
224 strlcpy(kern_ctl.ctl_name, NETAGENT_CONTROL_NAME, sizeof(kern_ctl.ctl_name));
225 kern_ctl.ctl_name[sizeof(kern_ctl.ctl_name) - 1] = 0;
226 kern_ctl.ctl_flags = CTL_FLAG_PRIVILEGED; // Require root
227 kern_ctl.ctl_sendsize = 64 * 1024;
228 kern_ctl.ctl_recvsize = 64 * 1024;
229 kern_ctl.ctl_connect = netagent_ctl_connect;
230 kern_ctl.ctl_disconnect = netagent_ctl_disconnect;
231 kern_ctl.ctl_send = netagent_ctl_send;
232 kern_ctl.ctl_rcvd = netagent_ctl_rcvd;
233 kern_ctl.ctl_setopt = netagent_ctl_setopt;
234 kern_ctl.ctl_getopt = netagent_ctl_getopt;
235
236 result = ctl_register(&kern_ctl, &netagent_kctlref);
237 if (result != 0) {
238 NETAGENTLOG(LOG_ERR, "ctl_register failed: %d", result);
239 return result;
240 }
241
242 return 0;
243 }
244
245 static errno_t
netagent_ctl_connect(kern_ctl_ref kctlref,struct sockaddr_ctl * sac,void ** unitinfo)246 netagent_ctl_connect(kern_ctl_ref kctlref, struct sockaddr_ctl *sac, void **unitinfo)
247 {
248 #pragma unused(kctlref)
249 *unitinfo = netagent_create_session(sac->sc_unit);
250 if (*unitinfo == NULL) {
251 // Could not allocate session
252 return ENOBUFS;
253 }
254
255 return 0;
256 }
257
258 static errno_t
netagent_ctl_disconnect(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo)259 netagent_ctl_disconnect(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo)
260 {
261 #pragma unused(kctlref, unit)
262 struct netagent_session *session = (struct netagent_session *)unitinfo;
263 if (session != NULL) {
264 netagent_delete_session(session);
265 }
266
267 return 0;
268 }
269
270 // Kernel events
271 static void
netagent_post_event(uuid_t agent_uuid,u_int32_t event_code,bool update_necp,bool should_update_immediately)272 netagent_post_event(uuid_t agent_uuid, u_int32_t event_code, bool update_necp, bool should_update_immediately)
273 {
274 if (update_necp) {
275 necp_update_all_clients_immediately_if_needed(should_update_immediately);
276 }
277
278 struct kev_msg ev_msg;
279 memset(&ev_msg, 0, sizeof(ev_msg));
280
281 struct kev_netagent_data event_data;
282
283 ev_msg.vendor_code = KEV_VENDOR_APPLE;
284 ev_msg.kev_class = KEV_NETWORK_CLASS;
285 ev_msg.kev_subclass = KEV_NETAGENT_SUBCLASS;
286 ev_msg.event_code = event_code;
287
288 uuid_copy(event_data.netagent_uuid, agent_uuid);
289 ev_msg.dv[0].data_ptr = &event_data;
290 ev_msg.dv[0].data_length = sizeof(event_data);
291
292 kev_post_msg(&ev_msg);
293 }
294
295 // Message handling
296 static u_int8_t *
netagent_buffer_write_message_header(u_int8_t * buffer,u_int8_t message_type,u_int8_t flags,u_int32_t message_id,u_int32_t error,size_t payload_length)297 netagent_buffer_write_message_header(u_int8_t *buffer, u_int8_t message_type, u_int8_t flags,
298 u_int32_t message_id, u_int32_t error, size_t payload_length)
299 {
300 memset(buffer, 0, sizeof(struct netagent_message_header));
301 ((struct netagent_message_header *)(void *)buffer)->message_type = message_type;
302 ((struct netagent_message_header *)(void *)buffer)->message_flags = flags;
303 ((struct netagent_message_header *)(void *)buffer)->message_id = message_id;
304 ((struct netagent_message_header *)(void *)buffer)->message_error = error;
305 ((struct netagent_message_header *)(void *)buffer)->message_payload_length = (u_int32_t)payload_length;
306 return buffer + sizeof(struct netagent_message_header);
307 }
308
309 static int
netagent_send_ctl_data(u_int32_t control_unit,u_int8_t * buffer,size_t buffer_size)310 netagent_send_ctl_data(u_int32_t control_unit, u_int8_t *buffer, size_t buffer_size)
311 {
312 if (netagent_kctlref == NULL || control_unit == 0 || buffer == NULL || buffer_size == 0) {
313 return EINVAL;
314 }
315
316 return ctl_enqueuedata(netagent_kctlref, control_unit, buffer, buffer_size, CTL_DATA_EOR);
317 }
318
319 static int
netagent_send_trigger(struct netagent_wrapper * wrapper,struct proc * p,u_int32_t flags,u_int8_t trigger_type)320 netagent_send_trigger(struct netagent_wrapper *wrapper, struct proc *p, u_int32_t flags, u_int8_t trigger_type)
321 {
322 int error = 0;
323 struct netagent_trigger_message *trigger_message = NULL;
324 u_int8_t *trigger = NULL;
325 size_t trigger_size = sizeof(struct netagent_message_header) + sizeof(struct netagent_trigger_message);
326
327 trigger = (u_int8_t *)kalloc_data(trigger_size, Z_WAITOK);
328 if (trigger == NULL) {
329 return ENOMEM;
330 }
331
332 (void)netagent_buffer_write_message_header(trigger, trigger_type, 0, 0, 0, sizeof(struct netagent_trigger_message));
333
334 trigger_message = (struct netagent_trigger_message *)(void *)(trigger + sizeof(struct netagent_message_header));
335 trigger_message->trigger_flags = flags;
336 if (p != NULL) {
337 trigger_message->trigger_pid = proc_pid(p);
338 proc_getexecutableuuid(p, trigger_message->trigger_proc_uuid, sizeof(trigger_message->trigger_proc_uuid));
339 } else {
340 trigger_message->trigger_pid = 0;
341 uuid_clear(trigger_message->trigger_proc_uuid);
342 }
343
344 if ((error = netagent_send_ctl_data(wrapper->control_unit, trigger, trigger_size))) {
345 NETAGENTLOG(LOG_ERR, "Failed to send trigger message on control unit %d", wrapper->control_unit);
346 }
347
348 kfree_data(trigger, trigger_size);
349 return error;
350 }
351
352 static int
netagent_send_client_message(struct netagent_wrapper * wrapper,uuid_t client_id,u_int8_t message_type)353 netagent_send_client_message(struct netagent_wrapper *wrapper, uuid_t client_id, u_int8_t message_type)
354 {
355 int error = 0;
356 struct netagent_client_message *client_message = NULL;
357 u_int8_t *message = NULL;
358 size_t message_size = sizeof(struct netagent_message_header) + sizeof(struct netagent_client_message);
359
360 message = (u_int8_t *)kalloc_data(message_size, Z_WAITOK);
361 if (message == NULL) {
362 return ENOMEM;
363 }
364
365 (void)netagent_buffer_write_message_header(message, message_type, 0, 0, 0, sizeof(struct netagent_client_message));
366
367 client_message = (struct netagent_client_message *)(void *)(message + sizeof(struct netagent_message_header));
368 uuid_copy(client_message->client_id, client_id);
369
370 if ((error = netagent_send_ctl_data(wrapper->control_unit, message, message_size))) {
371 NETAGENTLOG(LOG_ERR, "Failed to send client message %d on control unit %d", message_type, wrapper->control_unit);
372 }
373
374 kfree_data(message, message_size);
375 return error;
376 }
377
378 static int
netagent_send_error_message(struct netagent_wrapper * wrapper,uuid_t client_id,u_int8_t message_type,int32_t error_code)379 netagent_send_error_message(struct netagent_wrapper *wrapper, uuid_t client_id, u_int8_t message_type, int32_t error_code)
380 {
381 int error = 0;
382 struct netagent_client_error_message *client_message = NULL;
383 u_int8_t *message = NULL;
384 size_t message_size = sizeof(struct netagent_message_header) + sizeof(struct netagent_client_error_message);
385
386 message = (u_int8_t *)kalloc_data(message_size, Z_WAITOK);
387 if (message == NULL) {
388 return ENOMEM;
389 }
390
391 (void)netagent_buffer_write_message_header(message, message_type, 0, 0, 0, sizeof(struct netagent_client_error_message));
392
393 client_message = (struct netagent_client_error_message *)(void *)(message + sizeof(struct netagent_message_header));
394 uuid_copy(client_message->client_id, client_id);
395 client_message->error_code = error_code;
396
397 if ((error = netagent_send_ctl_data(wrapper->control_unit, message, message_size))) {
398 NETAGENTLOG(LOG_ERR, "Failed to send client message %d on control unit %d", message_type, wrapper->control_unit);
399 }
400
401 kfree_data(message, message_size);
402 return error;
403 }
404
405 static int
netagent_send_group_message(struct netagent_wrapper * wrapper,uuid_t client_id,u_int8_t message_type,struct necp_client_group_members * group_members)406 netagent_send_group_message(struct netagent_wrapper *wrapper, uuid_t client_id, u_int8_t message_type, struct necp_client_group_members *group_members)
407 {
408 int error = 0;
409 struct netagent_client_group_message *client_message = NULL;
410 u_int8_t *message = NULL;
411 size_t message_size = sizeof(struct netagent_message_header) + sizeof(struct netagent_client_group_message) + group_members->group_members_length;
412
413 message = (u_int8_t *)kalloc_data(message_size, Z_WAITOK);
414 if (message == NULL) {
415 return ENOMEM;
416 }
417
418 (void)netagent_buffer_write_message_header(message, message_type, 0, 0, 0, sizeof(struct netagent_client_group_message) + group_members->group_members_length);
419
420 client_message = (struct netagent_client_group_message *)(void *)(message + sizeof(struct netagent_message_header));
421 uuid_copy(client_message->client_id, client_id);
422 memcpy(client_message->group_members, group_members->group_members, group_members->group_members_length);
423
424 if ((error = netagent_send_ctl_data(wrapper->control_unit, message, message_size))) {
425 NETAGENTLOG(LOG_ERR, "Failed to send client group message %d on control unit %d", message_type, wrapper->control_unit);
426 }
427
428 kfree_data(message, message_size);
429 return error;
430 }
431
432 static int
netagent_send_tokens_needed(struct netagent_wrapper * wrapper)433 netagent_send_tokens_needed(struct netagent_wrapper *wrapper)
434 {
435 const u_int8_t message_type = NETAGENT_MESSAGE_TYPE_TOKENS_NEEDED;
436 int error = 0;
437 u_int8_t *message = NULL;
438 size_t message_size = sizeof(struct netagent_message_header);
439
440 message = (u_int8_t *)kalloc_data(message_size, Z_WAITOK);
441 if (message == NULL) {
442 return ENOMEM;
443 }
444
445 (void)netagent_buffer_write_message_header(message, message_type, 0, 0, 0, 0);
446
447 if ((error = netagent_send_ctl_data(wrapper->control_unit, message, message_size))) {
448 NETAGENTLOG(LOG_ERR, "Failed to send client tokens needed message on control unit %d", wrapper->control_unit);
449 }
450
451 kfree_data(message, message_size);
452 return error;
453 }
454
455 static int
netagent_send_success_response(struct netagent_session * session,u_int8_t message_type,u_int32_t message_id)456 netagent_send_success_response(struct netagent_session *session, u_int8_t message_type, u_int32_t message_id)
457 {
458 int error = 0;
459 u_int8_t *response = NULL;
460 size_t response_size = sizeof(struct netagent_message_header);
461 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK);
462 if (response == NULL) {
463 return ENOMEM;
464 }
465 (void)netagent_buffer_write_message_header(response, message_type, NETAGENT_MESSAGE_FLAGS_RESPONSE, message_id, 0, 0);
466
467 if ((error = netagent_send_ctl_data(session->control_unit, response, response_size))) {
468 NETAGENTLOG0(LOG_ERR, "Failed to send response");
469 }
470
471 kfree_data(response, response_size);
472 return error;
473 }
474
475 static errno_t
netagent_send_error_response(struct netagent_session * session,u_int8_t message_type,u_int32_t message_id,u_int32_t error_code)476 netagent_send_error_response(struct netagent_session *session, u_int8_t message_type,
477 u_int32_t message_id, u_int32_t error_code)
478 {
479 int error = 0;
480 u_int8_t *response = NULL;
481 size_t response_size = sizeof(struct netagent_message_header);
482
483 if (session == NULL) {
484 NETAGENTLOG0(LOG_ERR, "Got a NULL session");
485 return EINVAL;
486 }
487
488 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK);
489 if (response == NULL) {
490 return ENOMEM;
491 }
492 (void)netagent_buffer_write_message_header(response, message_type, NETAGENT_MESSAGE_FLAGS_RESPONSE,
493 message_id, error_code, 0);
494
495 if ((error = netagent_send_ctl_data(session->control_unit, response, response_size))) {
496 NETAGENTLOG0(LOG_ERR, "Failed to send response");
497 }
498
499 kfree_data(response, response_size);
500 return error;
501 }
502
503 static errno_t
netagent_ctl_send(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo,mbuf_t packet,int flags)504 netagent_ctl_send(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, mbuf_t packet, int flags)
505 {
506 #pragma unused(kctlref, unit, flags)
507 struct netagent_session *session = (struct netagent_session *)unitinfo;
508 struct netagent_message_header header;
509 int error = 0;
510
511 if (session == NULL) {
512 NETAGENTLOG0(LOG_ERR, "Got a NULL session");
513 error = EINVAL;
514 goto done;
515 }
516
517 if (mbuf_pkthdr_len(packet) < sizeof(header)) {
518 NETAGENTLOG(LOG_ERR, "Got a bad packet, length (%lu) < sizeof header (%lu)",
519 mbuf_pkthdr_len(packet), sizeof(header));
520 error = EINVAL;
521 goto done;
522 }
523
524 error = mbuf_copydata(packet, 0, sizeof(header), &header);
525 if (error) {
526 NETAGENTLOG(LOG_ERR, "mbuf_copydata failed for the header: %d", error);
527 error = ENOBUFS;
528 goto done;
529 }
530
531 switch (header.message_type) {
532 case NETAGENT_MESSAGE_TYPE_REGISTER: {
533 netagent_handle_register_message(session, header.message_id, header.message_payload_length,
534 packet, sizeof(header));
535 break;
536 }
537 case NETAGENT_MESSAGE_TYPE_UNREGISTER: {
538 netagent_handle_unregister_message(session, header.message_id, header.message_payload_length,
539 packet, sizeof(header));
540 break;
541 }
542 case NETAGENT_MESSAGE_TYPE_UPDATE: {
543 netagent_handle_update_message(session, header.message_id, header.message_payload_length,
544 packet, sizeof(header));
545 break;
546 }
547 case NETAGENT_MESSAGE_TYPE_GET: {
548 netagent_handle_get(session, header.message_id, header.message_payload_length,
549 packet, sizeof(header));
550 break;
551 }
552 case NETAGENT_MESSAGE_TYPE_ASSERT: {
553 NETAGENTLOG0(LOG_ERR, "NETAGENT_MESSAGE_TYPE_ASSERT no longer supported");
554 break;
555 }
556 case NETAGENT_MESSAGE_TYPE_UNASSERT: {
557 NETAGENTLOG0(LOG_ERR, "NETAGENT_MESSAGE_TYPE_UNASSERT no longer supported");
558 break;
559 }
560 case NETAGENT_MESSAGE_TYPE_ASSIGN_NEXUS: {
561 netagent_handle_assign_nexus_message(session, header.message_id, header.message_payload_length,
562 packet, sizeof(header));
563 break;
564 }
565 default: {
566 NETAGENTLOG(LOG_ERR, "Received unknown message type %d", header.message_type);
567 netagent_send_error_response(session, header.message_type, header.message_id,
568 NETAGENT_MESSAGE_ERROR_UNKNOWN_TYPE);
569 break;
570 }
571 }
572
573 done:
574 mbuf_freem(packet);
575 return error;
576 }
577
578 static void
netagent_ctl_rcvd(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo,int flags)579 netagent_ctl_rcvd(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int flags)
580 {
581 #pragma unused(kctlref, unit, unitinfo, flags)
582 return;
583 }
584
585 static errno_t
netagent_ctl_getopt(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo,int opt,void * data,size_t * len)586 netagent_ctl_getopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt,
587 void *data, size_t *len)
588 {
589 #pragma unused(kctlref, unit)
590 struct netagent_session *session = (struct netagent_session *)unitinfo;
591 errno_t error;
592
593 if (session == NULL) {
594 NETAGENTLOG0(LOG_ERR, "Received a NULL session");
595 error = EINVAL;
596 goto done;
597 }
598
599 switch (opt) {
600 case NETAGENT_OPTION_TYPE_USE_COUNT: {
601 NETAGENTLOG0(LOG_DEBUG, "Request to get use count");
602 error = netagent_handle_use_count_getopt(session, data, len);
603 break;
604 }
605 case NETAGENT_OPTION_TYPE_TOKEN_COUNT: {
606 NETAGENTLOG0(LOG_DEBUG, "Request to get token count");
607 error = netagent_handle_token_count_getopt(session, data, len);
608 break;
609 }
610 case NETAGENT_OPTION_TYPE_TOKEN_LOW_WATER: {
611 NETAGENTLOG0(LOG_DEBUG, "Request to get token low water mark");
612 error = netagent_handle_token_low_water_getopt(session, data, len);
613 break;
614 }
615 default:
616 NETAGENTLOG0(LOG_ERR, "Received unknown option");
617 error = ENOPROTOOPT;
618 break;
619 }
620
621 done:
622 return error;
623 }
624
625 static errno_t
netagent_ctl_setopt(kern_ctl_ref kctlref,u_int32_t unit,void * unitinfo,int opt,void * data,size_t len)626 netagent_ctl_setopt(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt,
627 void *data, size_t len)
628 {
629 #pragma unused(kctlref, unit)
630 struct netagent_session *session = (struct netagent_session *)unitinfo;
631 errno_t error;
632
633 if (session == NULL) {
634 NETAGENTLOG0(LOG_ERR, "Received a NULL session");
635 error = EINVAL;
636 goto done;
637 }
638
639 switch (opt) {
640 case NETAGENT_OPTION_TYPE_REGISTER: {
641 NETAGENTLOG0(LOG_DEBUG, "Request for registration");
642 error = netagent_handle_register_setopt(session, data, len);
643 break;
644 }
645 case NETAGENT_OPTION_TYPE_UPDATE: {
646 NETAGENTLOG0(LOG_DEBUG, "Request for update");
647 error = netagent_handle_update_setopt(session, data, len);
648 break;
649 }
650 case NETAGENT_OPTION_TYPE_UNREGISTER: {
651 NETAGENTLOG0(LOG_DEBUG, "Request for unregistration");
652 error = netagent_handle_unregister_setopt(session, data, len);
653 break;
654 }
655 case NETAGENT_OPTION_TYPE_ASSIGN_NEXUS: {
656 NETAGENTLOG0(LOG_DEBUG, "Request for assigning nexus");
657 error = netagent_handle_assign_nexus_setopt(session, data, len);
658 break;
659 }
660 case NETAGENT_MESSAGE_TYPE_ASSIGN_GROUP_MEMBERS: {
661 NETAGENTLOG0(LOG_DEBUG, "Request for assigning group members");
662 error = netagent_handle_assign_group_setopt(session, data, len);
663 break;
664 }
665 case NETAGENT_OPTION_TYPE_USE_COUNT: {
666 NETAGENTLOG0(LOG_DEBUG, "Request to set use count");
667 error = netagent_handle_use_count_setopt(session, data, len);
668 break;
669 }
670 case NETAGENT_OPTION_TYPE_ADD_TOKEN: {
671 NETAGENTLOG0(LOG_DEBUG, "Request to add a token");
672 error = netagent_handle_add_token_setopt(session, data, len);
673 break;
674 }
675 case NETAGENT_OPTION_TYPE_FLUSH_TOKENS: {
676 NETAGENTLOG0(LOG_DEBUG, "Request to flush tokens");
677 error = netagent_handle_flush_tokens_setopt(session, data, len);
678 break;
679 }
680 case NETAGENT_OPTION_TYPE_TOKEN_LOW_WATER: {
681 NETAGENTLOG0(LOG_DEBUG, "Request to set token low water mark");
682 error = netagent_handle_token_low_water_setopt(session, data, len);
683 break;
684 }
685 case NETAGENT_OPTION_TYPE_RESET_CLIENT_ERROR: {
686 NETAGENTLOG0(LOG_DEBUG, "Request to reset client error");
687 error = netagent_handle_reset_client_error_setopt(session, data, len);
688 break;
689 }
690 default:
691 NETAGENTLOG0(LOG_ERR, "Received unknown option");
692 error = ENOPROTOOPT;
693 break;
694 }
695
696 done:
697 return error;
698 }
699
700 // Session Management
701 static struct netagent_session *
netagent_create_session(u_int32_t control_unit)702 netagent_create_session(u_int32_t control_unit)
703 {
704 struct netagent_session *new_session = NULL;
705
706 new_session = kalloc_type(struct netagent_session,
707 Z_WAITOK | Z_ZERO | Z_NOFAIL);
708 NETAGENTLOG(LOG_DEBUG, "Create agent session, control unit %d", control_unit);
709 new_session->control_unit = control_unit;
710
711 return new_session;
712 }
713
714 netagent_session_t
netagent_create(netagent_event_f event_handler,void * context)715 netagent_create(netagent_event_f event_handler, void *context)
716 {
717 struct netagent_session *session = netagent_create_session(0);
718 if (session == NULL) {
719 return NULL;
720 }
721
722 session->event_handler = event_handler;
723 session->event_context = context;
724 return session;
725 }
726
727 static void
netagent_token_free(struct netagent_token * token)728 netagent_token_free(struct netagent_token *token)
729 {
730 kfree_data(token->token_bytes, token->token_length);
731 kfree_type(struct netagent_token, token);
732 }
733
734 static struct netagent_wrapper *
netagent_alloc_wrapper_memory(uint32_t data_size)735 netagent_alloc_wrapper_memory(uint32_t data_size)
736 {
737 struct netagent_wrapper *new_wrapper;
738
739 new_wrapper = kalloc_type(struct netagent_wrapper,
740 Z_WAITOK | Z_ZERO | Z_NOFAIL);
741 new_wrapper->netagent = kalloc_data(sizeof(struct netagent) + data_size,
742 Z_WAITOK | Z_NOFAIL);
743
744 return new_wrapper;
745 }
746
747 static void
netagent_free_wrapper_memory(struct netagent_wrapper * wrapper)748 netagent_free_wrapper_memory(struct netagent_wrapper *wrapper)
749 {
750 kfree_data(wrapper->netagent, sizeof(struct netagent) +
751 wrapper->netagent->netagent_data_size);
752 kfree_type(struct netagent_wrapper, wrapper);
753 }
754
755 static void
netagent_free_wrapper(struct netagent_wrapper * wrapper)756 netagent_free_wrapper(struct netagent_wrapper *wrapper)
757 {
758 // Free any leftover tokens
759 struct netagent_token *search_token = NULL;
760 struct netagent_token *temp_token = NULL;
761 TAILQ_FOREACH_SAFE(search_token, &wrapper->token_list, token_chain, temp_token) {
762 TAILQ_REMOVE(&wrapper->token_list, search_token, token_chain);
763 netagent_token_free(search_token);
764 }
765
766 // Free any pending client triggers
767 struct netagent_client *search_client = NULL;
768 struct netagent_client *temp_client = NULL;
769 LIST_FOREACH_SAFE(search_client, &wrapper->pending_triggers_list, client_chain, temp_client) {
770 LIST_REMOVE(search_client, client_chain);
771 kfree_type(struct netagent_client, search_client);
772 }
773
774 // Free wrapper itself
775 netagent_free_wrapper_memory(wrapper);
776 }
777
778 static void
netagent_unregister_session_wrapper(struct netagent_session * session)779 netagent_unregister_session_wrapper(struct netagent_session *session)
780 {
781 bool unregistered = FALSE;
782 uuid_t unregistered_uuid;
783 struct netagent_wrapper *wrapper = NULL;
784 lck_rw_lock_exclusive(&netagent_lock);
785 if (session != NULL) {
786 wrapper = session->wrapper;
787 if (wrapper != NULL) {
788 if (netagent_registered_count > 0) {
789 netagent_registered_count--;
790 }
791 if ((session->wrapper->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) &&
792 netagent_active_count > 0) {
793 netagent_active_count--;
794 }
795
796 LIST_REMOVE(wrapper, master_chain);
797
798 unregistered = TRUE;
799 uuid_copy(unregistered_uuid, session->wrapper->netagent->netagent_uuid);
800
801 netagent_free_wrapper(session->wrapper);
802 session->wrapper = NULL;
803 NETAGENTLOG0(LOG_DEBUG, "Unregistered agent");
804 }
805 }
806 lck_rw_done(&netagent_lock);
807
808 if (unregistered) {
809 ifnet_clear_netagent(unregistered_uuid);
810 netagent_post_event(unregistered_uuid, KEV_NETAGENT_UNREGISTERED, TRUE, false);
811 }
812 }
813
814 static void
netagent_delete_session(struct netagent_session * session)815 netagent_delete_session(struct netagent_session *session)
816 {
817 if (session != NULL) {
818 netagent_unregister_session_wrapper(session);
819 kfree_type(struct netagent_session, session);
820 }
821 }
822
823 void
netagent_destroy(netagent_session_t session)824 netagent_destroy(netagent_session_t session)
825 {
826 return netagent_delete_session((struct netagent_session *)session);
827 }
828
829 static size_t
netagent_packet_get_netagent_data_size(mbuf_t packet,size_t offset,int * err)830 netagent_packet_get_netagent_data_size(mbuf_t packet, size_t offset, int *err)
831 {
832 int error = 0;
833
834 struct netagent netagent_peek;
835 memset(&netagent_peek, 0, sizeof(netagent_peek));
836
837 *err = 0;
838
839 error = mbuf_copydata(packet, offset, sizeof(netagent_peek), &netagent_peek);
840 if (error) {
841 *err = ENOENT;
842 return 0;
843 }
844
845 return netagent_peek.netagent_data_size;
846 }
847
848 static errno_t
netagent_handle_register_inner(struct netagent_session * session,struct netagent_wrapper * new_wrapper)849 netagent_handle_register_inner(struct netagent_session *session, struct netagent_wrapper *new_wrapper)
850 {
851 lck_rw_lock_exclusive(&netagent_lock);
852
853 if (session->wrapper != NULL) {
854 lck_rw_done(&netagent_lock);
855 return EINVAL;
856 }
857
858 new_wrapper->control_unit = session->control_unit;
859 new_wrapper->event_handler = session->event_handler;
860 new_wrapper->event_context = session->event_context;
861 new_wrapper->generation = g_next_generation++;
862
863 session->wrapper = new_wrapper;
864 LIST_INSERT_HEAD(&master_netagent_list, new_wrapper, master_chain);
865 TAILQ_INIT(&new_wrapper->token_list);
866 LIST_INIT(&new_wrapper->pending_triggers_list);
867
868 new_wrapper->netagent->netagent_flags |= NETAGENT_FLAG_REGISTERED;
869 netagent_registered_count++;
870 if (new_wrapper->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) {
871 netagent_active_count++;
872 }
873
874 lck_rw_done(&netagent_lock);
875
876 return 0;
877 }
878
879 errno_t
netagent_register(netagent_session_t _session,struct netagent * agent)880 netagent_register(netagent_session_t _session, struct netagent *agent)
881 {
882 struct netagent_wrapper *new_wrapper = NULL;
883 uuid_t registered_uuid;
884
885 struct netagent_session *session = (struct netagent_session *)_session;
886 if (session == NULL) {
887 NETAGENTLOG0(LOG_ERR, "Cannot register agent on NULL session");
888 return EINVAL;
889 }
890
891 if (agent == NULL) {
892 NETAGENTLOG0(LOG_ERR, "Cannot register NULL agent");
893 return EINVAL;
894 }
895
896 if (session->wrapper != NULL) {
897 NETAGENTLOG0(LOG_ERR, "Session already has a registered agent");
898 return EINVAL;
899 }
900
901 size_t data_size = agent->netagent_data_size;
902 if (data_size > NETAGENT_MAX_DATA_SIZE) {
903 NETAGENTLOG(LOG_ERR, "Register message size could not be read, data_size %zu",
904 data_size);
905 return EINVAL;
906 }
907
908 new_wrapper = netagent_alloc_wrapper_memory(data_size);
909
910 __nochk_memcpy(new_wrapper->netagent, agent, sizeof(struct netagent) + data_size);
911
912 uuid_copy(registered_uuid, new_wrapper->netagent->netagent_uuid);
913
914 errno_t error = netagent_handle_register_inner(session, new_wrapper);
915 if (error != 0) {
916 netagent_free_wrapper_memory(new_wrapper);
917 return error;
918 }
919
920 NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
921 netagent_post_event(registered_uuid, KEV_NETAGENT_REGISTERED, TRUE, false);
922
923 return 0;
924 }
925
926 static errno_t
netagent_handle_register_setopt(struct netagent_session * session,u_int8_t * payload,size_t payload_length)927 netagent_handle_register_setopt(struct netagent_session *session, u_int8_t *payload,
928 size_t payload_length)
929 {
930 struct netagent_wrapper *new_wrapper = NULL;
931 errno_t response_error = 0;
932 struct netagent *register_netagent = (struct netagent *)(void *)payload;
933 uuid_t registered_uuid;
934
935 if (session == NULL) {
936 NETAGENTLOG0(LOG_ERR, "Failed to find session");
937 response_error = EINVAL;
938 goto done;
939 }
940
941 if (payload == NULL) {
942 NETAGENTLOG0(LOG_ERR, "No payload received");
943 response_error = EINVAL;
944 goto done;
945 }
946
947 if (session->wrapper != NULL) {
948 NETAGENTLOG0(LOG_ERR, "Session already has a registered agent");
949 response_error = EINVAL;
950 goto done;
951 }
952
953 if (payload_length < sizeof(struct netagent)) {
954 NETAGENTLOG(LOG_ERR, "Register message size too small for agent: (%zu < %zu)",
955 payload_length, sizeof(struct netagent));
956 response_error = EINVAL;
957 goto done;
958 }
959
960 size_t data_size = register_netagent->netagent_data_size;
961 if (data_size > NETAGENT_MAX_DATA_SIZE) {
962 NETAGENTLOG(LOG_ERR, "Register message size could not be read, data_size %zu", data_size);
963 response_error = EINVAL;
964 goto done;
965 }
966
967 if (payload_length != (sizeof(struct netagent) + data_size)) {
968 NETAGENTLOG(LOG_ERR, "Mismatch between data size and payload length (%lu != %zu)", (sizeof(struct netagent) + data_size), payload_length);
969 response_error = EINVAL;
970 goto done;
971 }
972
973 new_wrapper = netagent_alloc_wrapper_memory(data_size);
974
975 __nochk_memcpy(new_wrapper->netagent, register_netagent, sizeof(struct netagent) + data_size);
976
977 uuid_copy(registered_uuid, new_wrapper->netagent->netagent_uuid);
978
979 response_error = netagent_handle_register_inner(session, new_wrapper);
980 if (response_error != 0) {
981 netagent_free_wrapper_memory(new_wrapper);
982 goto done;
983 }
984
985 NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
986 netagent_post_event(registered_uuid, KEV_NETAGENT_REGISTERED, TRUE, false);
987
988 done:
989 return response_error;
990 }
991
992 static void
netagent_handle_register_message(struct netagent_session * session,u_int32_t message_id,size_t payload_length,mbuf_t packet,size_t offset)993 netagent_handle_register_message(struct netagent_session *session, u_int32_t message_id,
994 size_t payload_length, mbuf_t packet, size_t offset)
995 {
996 errno_t error;
997 struct netagent_wrapper *new_wrapper = NULL;
998 u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
999 uuid_t registered_uuid;
1000
1001 if (session == NULL) {
1002 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1003 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1004 goto fail;
1005 }
1006
1007 if (session->wrapper != NULL) {
1008 NETAGENTLOG0(LOG_ERR, "Session already has a registered agent");
1009 response_error = NETAGENT_MESSAGE_ERROR_ALREADY_REGISTERED;
1010 goto fail;
1011 }
1012
1013 if (payload_length < sizeof(struct netagent)) {
1014 NETAGENTLOG(LOG_ERR, "Register message size too small for agent: (%zu < %zu)",
1015 payload_length, sizeof(struct netagent));
1016 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1017 goto fail;
1018 }
1019
1020 size_t data_size = netagent_packet_get_netagent_data_size(packet, offset, &error);
1021 if (error || data_size > NETAGENT_MAX_DATA_SIZE) {
1022 NETAGENTLOG(LOG_ERR, "Register message size could not be read, error %d data_size %zu",
1023 error, data_size);
1024 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1025 goto fail;
1026 }
1027
1028 new_wrapper = netagent_alloc_wrapper_memory(data_size);
1029
1030 error = mbuf_copydata(packet, offset, sizeof(struct netagent) + data_size,
1031 new_wrapper->netagent);
1032 if (error) {
1033 NETAGENTLOG(LOG_ERR, "Failed to read data into agent structure: %d", error);
1034 netagent_free_wrapper_memory(new_wrapper);
1035 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1036 goto fail;
1037 }
1038
1039 uuid_copy(registered_uuid, new_wrapper->netagent->netagent_uuid);
1040
1041 error = netagent_handle_register_inner(session, new_wrapper);
1042 if (error) {
1043 NETAGENTLOG(LOG_ERR, "Failed to register agent: %d", error);
1044 netagent_free_wrapper_memory(new_wrapper);
1045 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1046 goto fail;
1047 }
1048
1049 NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
1050 netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_REGISTER, message_id);
1051 netagent_post_event(registered_uuid, KEV_NETAGENT_REGISTERED, TRUE, false);
1052 return;
1053 fail:
1054 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_REGISTER, message_id, response_error);
1055 }
1056
1057 errno_t
netagent_unregister(netagent_session_t _session)1058 netagent_unregister(netagent_session_t _session)
1059 {
1060 struct netagent_session *session = (struct netagent_session *)_session;
1061 if (session == NULL) {
1062 NETAGENTLOG0(LOG_ERR, "Cannot unregister NULL session");
1063 return EINVAL;
1064 }
1065
1066 netagent_unregister_session_wrapper(session);
1067 return 0;
1068 }
1069
1070 static errno_t
netagent_handle_unregister_setopt(struct netagent_session * session,u_int8_t * payload,size_t payload_length)1071 netagent_handle_unregister_setopt(struct netagent_session *session, u_int8_t *payload,
1072 size_t payload_length)
1073 {
1074 #pragma unused(payload, payload_length)
1075 errno_t response_error = 0;
1076
1077 if (session == NULL) {
1078 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1079 response_error = EINVAL;
1080 goto done;
1081 }
1082
1083 netagent_unregister_session_wrapper(session);
1084
1085 done:
1086 return response_error;
1087 }
1088
1089 static void
netagent_handle_unregister_message(struct netagent_session * session,u_int32_t message_id,size_t payload_length,mbuf_t packet,size_t offset)1090 netagent_handle_unregister_message(struct netagent_session *session, u_int32_t message_id,
1091 size_t payload_length, mbuf_t packet, size_t offset)
1092 {
1093 #pragma unused(payload_length, packet, offset)
1094 u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1095
1096 if (session == NULL) {
1097 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1098 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1099 goto fail;
1100 }
1101
1102 netagent_unregister_session_wrapper(session);
1103
1104 netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_UNREGISTER, message_id);
1105 return;
1106 fail:
1107 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_UNREGISTER, message_id, response_error);
1108 }
1109
1110 static void
netagent_send_cellular_failed_event(struct netagent_wrapper * wrapper,pid_t pid,uuid_t proc_uuid)1111 netagent_send_cellular_failed_event(struct netagent_wrapper *wrapper,
1112 pid_t pid, uuid_t proc_uuid)
1113 {
1114 if (strncmp(wrapper->netagent->netagent_domain, "Cellular", NETAGENT_DOMAINSIZE) != 0) {
1115 return;
1116 }
1117
1118 struct kev_netpolicy_ifdenied ev_ifdenied;
1119
1120 bzero(&ev_ifdenied, sizeof(ev_ifdenied));
1121
1122 ev_ifdenied.ev_data.epid = (u_int64_t)pid;
1123 uuid_copy(ev_ifdenied.ev_data.euuid, proc_uuid);
1124 ev_ifdenied.ev_if_functional_type = IFRTYPE_FUNCTIONAL_CELLULAR;
1125
1126 netpolicy_post_msg(KEV_NETPOLICY_IFFAILED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
1127 }
1128
1129 static errno_t
netagent_handle_update_inner(struct netagent_session * session,struct netagent_wrapper * new_wrapper,size_t data_size,u_int8_t * agent_changed,netagent_error_domain_t error_domain)1130 netagent_handle_update_inner(struct netagent_session *session, struct netagent_wrapper *new_wrapper, size_t data_size, u_int8_t *agent_changed, netagent_error_domain_t error_domain)
1131 {
1132 errno_t response_error = 0;
1133
1134 if (agent_changed == NULL) {
1135 NETAGENTLOG0(LOG_ERR, "Invalid argument: agent_changed");
1136 return EINVAL;
1137 }
1138
1139 lck_rw_lock_exclusive(&netagent_lock);
1140
1141 if (session->wrapper == NULL) {
1142 lck_rw_done(&netagent_lock);
1143 response_error = ENOENT;
1144 return response_error;
1145 }
1146
1147 if (uuid_compare(session->wrapper->netagent->netagent_uuid, new_wrapper->netagent->netagent_uuid) != 0 ||
1148 memcmp(&session->wrapper->netagent->netagent_domain, &new_wrapper->netagent->netagent_domain,
1149 sizeof(new_wrapper->netagent->netagent_domain)) != 0 ||
1150 memcmp(&session->wrapper->netagent->netagent_type, &new_wrapper->netagent->netagent_type,
1151 sizeof(new_wrapper->netagent->netagent_type)) != 0) {
1152 lck_rw_done(&netagent_lock);
1153 NETAGENTLOG0(LOG_ERR, "Basic agent parameters do not match, cannot update");
1154 if (error_domain == kNetagentErrorDomainPOSIX) {
1155 response_error = EINVAL;
1156 } else if (error_domain == kNetagentErrorDomainUserDefined) {
1157 response_error = NETAGENT_MESSAGE_ERROR_CANNOT_UPDATE;
1158 }
1159 return response_error;
1160 }
1161
1162 new_wrapper->netagent->netagent_flags |= NETAGENT_FLAG_REGISTERED;
1163 if (session->wrapper->netagent->netagent_data_size == new_wrapper->netagent->netagent_data_size &&
1164 memcmp(session->wrapper->netagent, new_wrapper->netagent, sizeof(struct netagent) + data_size) == 0) {
1165 // Agent is exactly identical, don't increment the generation count
1166
1167 // Make a copy of the list of pending clients, and clear the current list
1168 struct netagent_client_list_s pending_triggers_list_copy;
1169 LIST_INIT(&pending_triggers_list_copy);
1170 struct netagent_client *search_client = NULL;
1171 struct netagent_client *temp_client = NULL;
1172 LIST_FOREACH_SAFE(search_client, &session->wrapper->pending_triggers_list, client_chain, temp_client) {
1173 LIST_REMOVE(search_client, client_chain);
1174 LIST_INSERT_HEAD(&pending_triggers_list_copy, search_client, client_chain);
1175 }
1176 lck_rw_done(&netagent_lock);
1177
1178 // Update pending client triggers without holding a lock
1179 search_client = NULL;
1180 temp_client = NULL;
1181 LIST_FOREACH_SAFE(search_client, &pending_triggers_list_copy, client_chain, temp_client) {
1182 necp_force_update_client(search_client->client_id, session->wrapper->netagent->netagent_uuid, session->wrapper->generation);
1183 netagent_send_cellular_failed_event(new_wrapper, search_client->client_pid, search_client->client_proc_uuid);
1184 LIST_REMOVE(search_client, client_chain);
1185 kfree_type(struct netagent_client, search_client);
1186 }
1187 NETAGENTLOG0(LOG_DEBUG, "Updated agent (no changes)");
1188 *agent_changed = FALSE;
1189 return response_error;
1190 }
1191
1192 new_wrapper->generation = g_next_generation++;
1193 new_wrapper->use_count = session->wrapper->use_count;
1194
1195 TAILQ_INIT(&new_wrapper->token_list);
1196 TAILQ_CONCAT(&new_wrapper->token_list, &session->wrapper->token_list, token_chain);
1197 new_wrapper->token_count = session->wrapper->token_count;
1198 new_wrapper->token_low_water = session->wrapper->token_low_water;
1199 new_wrapper->last_client_error = session->wrapper->last_client_error;
1200 new_wrapper->client_error_count = session->wrapper->client_error_count;
1201
1202 if ((new_wrapper->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) &&
1203 !(session->wrapper->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE)) {
1204 netagent_active_count++;
1205 } else if (!(new_wrapper->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) &&
1206 (session->wrapper->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) &&
1207 netagent_active_count > 0) {
1208 netagent_active_count--;
1209 }
1210
1211 LIST_REMOVE(session->wrapper, master_chain);
1212 netagent_free_wrapper(session->wrapper);
1213 session->wrapper = new_wrapper;
1214 new_wrapper->control_unit = session->control_unit;
1215 new_wrapper->event_handler = session->event_handler;
1216 new_wrapper->event_context = session->event_context;
1217 LIST_INSERT_HEAD(&master_netagent_list, new_wrapper, master_chain);
1218 LIST_INIT(&new_wrapper->pending_triggers_list);
1219
1220 NETAGENTLOG0(LOG_DEBUG, "Updated agent");
1221 *agent_changed = TRUE;
1222
1223 lck_rw_done(&netagent_lock);
1224
1225 return response_error;
1226 }
1227
1228 errno_t
netagent_update(netagent_session_t _session,struct netagent * agent)1229 netagent_update(netagent_session_t _session, struct netagent *agent)
1230 {
1231 u_int8_t agent_changed;
1232 struct netagent_wrapper *new_wrapper = NULL;
1233 bool should_update_immediately;
1234 uuid_t updated_uuid;
1235
1236 struct netagent_session *session = (struct netagent_session *)_session;
1237 if (session == NULL) {
1238 NETAGENTLOG0(LOG_ERR, "Cannot update agent on NULL session");
1239 return EINVAL;
1240 }
1241
1242 if (agent == NULL) {
1243 NETAGENTLOG0(LOG_ERR, "Cannot register NULL agent");
1244 return EINVAL;
1245 }
1246
1247 if (session->wrapper == NULL) {
1248 NETAGENTLOG0(LOG_ERR, "Session has no agent to update");
1249 return EINVAL;
1250 }
1251
1252 size_t data_size = agent->netagent_data_size;
1253 if (data_size > NETAGENT_MAX_DATA_SIZE) {
1254 NETAGENTLOG(LOG_ERR, "Update message size (%zu > %u) too large", data_size, NETAGENT_MAX_DATA_SIZE);
1255 return EINVAL;
1256 }
1257
1258 new_wrapper = netagent_alloc_wrapper_memory(data_size);
1259
1260 __nochk_memcpy(new_wrapper->netagent, agent, sizeof(struct netagent) + data_size);
1261
1262 uuid_copy(updated_uuid, new_wrapper->netagent->netagent_uuid);
1263 should_update_immediately = (NETAGENT_FLAG_UPDATE_IMMEDIATELY == (new_wrapper->netagent->netagent_flags & NETAGENT_FLAG_UPDATE_IMMEDIATELY));
1264
1265 errno_t error = netagent_handle_update_inner(session, new_wrapper, data_size, &agent_changed, kNetagentErrorDomainPOSIX);
1266 if (error == 0) {
1267 netagent_post_event(updated_uuid, KEV_NETAGENT_UPDATED, agent_changed, should_update_immediately);
1268 if (agent_changed == FALSE) {
1269 // The session wrapper does not need the "new_wrapper" as nothing changed
1270 netagent_free_wrapper_memory(new_wrapper);
1271 }
1272 } else {
1273 netagent_free_wrapper_memory(new_wrapper);
1274 return error;
1275 }
1276
1277 return 0;
1278 }
1279
1280 static errno_t
netagent_handle_update_setopt(struct netagent_session * session,u_int8_t * payload,size_t payload_length)1281 netagent_handle_update_setopt(struct netagent_session *session, u_int8_t *payload, size_t payload_length)
1282 {
1283 struct netagent_wrapper *new_wrapper = NULL;
1284 errno_t response_error = 0;
1285 struct netagent *update_netagent = (struct netagent *)(void *)payload;
1286 u_int8_t agent_changed;
1287 bool should_update_immediately;
1288 uuid_t updated_uuid;
1289
1290 if (session == NULL) {
1291 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1292 response_error = EINVAL;
1293 goto done;
1294 }
1295
1296 if (payload == NULL) {
1297 NETAGENTLOG0(LOG_ERR, "No payload received");
1298 response_error = EINVAL;
1299 goto done;
1300 }
1301
1302 if (session->wrapper == NULL) {
1303 NETAGENTLOG0(LOG_ERR, "Session has no agent to update");
1304 response_error = ENOENT;
1305 goto done;
1306 }
1307
1308 if (payload_length < sizeof(struct netagent)) {
1309 NETAGENTLOG(LOG_ERR, "Update message size too small for agent: (%zu < %zu)",
1310 payload_length, sizeof(struct netagent));
1311 response_error = EINVAL;
1312 goto done;
1313 }
1314
1315 size_t data_size = update_netagent->netagent_data_size;
1316 if (data_size > NETAGENT_MAX_DATA_SIZE) {
1317 NETAGENTLOG(LOG_ERR, "Update message size (%zu > %u) too large", data_size, NETAGENT_MAX_DATA_SIZE);
1318 response_error = EINVAL;
1319 goto done;
1320 }
1321
1322 if (payload_length != (sizeof(struct netagent) + data_size)) {
1323 NETAGENTLOG(LOG_ERR, "Mismatch between data size and payload length (%lu != %zu)", (sizeof(struct netagent) + data_size), payload_length);
1324 response_error = EINVAL;
1325 goto done;
1326 }
1327
1328 new_wrapper = netagent_alloc_wrapper_memory(data_size);
1329
1330 __nochk_memcpy(new_wrapper->netagent, update_netagent, sizeof(struct netagent) + data_size);
1331
1332 uuid_copy(updated_uuid, new_wrapper->netagent->netagent_uuid);
1333 should_update_immediately = (NETAGENT_FLAG_UPDATE_IMMEDIATELY == (new_wrapper->netagent->netagent_flags & NETAGENT_FLAG_UPDATE_IMMEDIATELY));
1334
1335 response_error = netagent_handle_update_inner(session, new_wrapper, data_size, &agent_changed, kNetagentErrorDomainPOSIX);
1336 if (response_error == 0) {
1337 netagent_post_event(updated_uuid, KEV_NETAGENT_UPDATED, agent_changed, should_update_immediately);
1338 if (agent_changed == FALSE) {
1339 // The session wrapper does not need the "new_wrapper" as nothing changed
1340 netagent_free_wrapper_memory(new_wrapper);
1341 }
1342 } else {
1343 netagent_free_wrapper_memory(new_wrapper);
1344 }
1345
1346 done:
1347 return response_error;
1348 }
1349
1350 static void
netagent_handle_update_message(struct netagent_session * session,u_int32_t message_id,size_t payload_length,mbuf_t packet,size_t offset)1351 netagent_handle_update_message(struct netagent_session *session, u_int32_t message_id,
1352 size_t payload_length, mbuf_t packet, size_t offset)
1353 {
1354 int error;
1355 struct netagent_wrapper *new_wrapper = NULL;
1356 u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1357 u_int8_t agent_changed;
1358 uuid_t updated_uuid;
1359 bool should_update_immediately;
1360
1361 if (session == NULL) {
1362 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1363 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1364 goto fail;
1365 }
1366
1367 if (session->wrapper == NULL) {
1368 NETAGENTLOG0(LOG_ERR, "Session has no agent to update");
1369 response_error = NETAGENT_MESSAGE_ERROR_NOT_REGISTERED;
1370 goto fail;
1371 }
1372
1373 if (payload_length < sizeof(struct netagent)) {
1374 NETAGENTLOG(LOG_ERR, "Update message size too small for agent: (%zu < %zu)",
1375 payload_length, sizeof(struct netagent));
1376 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1377 goto fail;
1378 }
1379
1380 size_t data_size = netagent_packet_get_netagent_data_size(packet, offset, &error);
1381 if (error || data_size > NETAGENT_MAX_DATA_SIZE) {
1382 NETAGENTLOG(LOG_ERR, "Update message size could not be read, error %d data_size %zu",
1383 error, data_size);
1384 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1385 goto fail;
1386 }
1387
1388 new_wrapper = netagent_alloc_wrapper_memory(data_size);
1389
1390 error = mbuf_copydata(packet, offset, sizeof(struct netagent) + data_size, new_wrapper->netagent);
1391 if (error) {
1392 NETAGENTLOG(LOG_ERR, "Failed to read data into agent structure: %d", error);
1393 netagent_free_wrapper_memory(new_wrapper);
1394 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1395 goto fail;
1396 }
1397
1398 uuid_copy(updated_uuid, new_wrapper->netagent->netagent_uuid);
1399 should_update_immediately = (NETAGENT_FLAG_UPDATE_IMMEDIATELY == (new_wrapper->netagent->netagent_flags & NETAGENT_FLAG_UPDATE_IMMEDIATELY));
1400
1401 response_error = (u_int32_t)netagent_handle_update_inner(session, new_wrapper, data_size, &agent_changed, kNetagentErrorDomainUserDefined);
1402 if (response_error != 0) {
1403 netagent_free_wrapper_memory(new_wrapper);
1404 goto fail;
1405 }
1406
1407 netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_UPDATE, message_id);
1408 netagent_post_event(updated_uuid, KEV_NETAGENT_UPDATED, agent_changed, should_update_immediately);
1409
1410 if (agent_changed == FALSE) {
1411 // The session wrapper does not need the "new_wrapper" as nothing changed
1412 netagent_free_wrapper_memory(new_wrapper);
1413 }
1414
1415 return;
1416 fail:
1417 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_UPDATE, message_id, response_error);
1418 }
1419
1420 static void
netagent_handle_get(struct netagent_session * session,u_int32_t message_id,size_t payload_length,mbuf_t packet,size_t offset)1421 netagent_handle_get(struct netagent_session *session, u_int32_t message_id,
1422 size_t payload_length, mbuf_t packet, size_t offset)
1423 {
1424 #pragma unused(payload_length, packet, offset)
1425 u_int8_t *response = NULL;
1426 u_int8_t *cursor = NULL;
1427 u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1428
1429 if (session == NULL) {
1430 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1431 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1432 goto fail;
1433 }
1434
1435 lck_rw_lock_shared(&netagent_lock);
1436
1437 if (session->wrapper == NULL) {
1438 lck_rw_done(&netagent_lock);
1439 NETAGENTLOG0(LOG_ERR, "Session has no agent to get");
1440 response_error = NETAGENT_MESSAGE_ERROR_NOT_REGISTERED;
1441 goto fail;
1442 }
1443
1444 size_t response_size = sizeof(struct netagent_message_header)
1445 + sizeof(struct netagent)
1446 + session->wrapper->netagent->netagent_data_size;
1447 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK);
1448 if (response == NULL) {
1449 goto fail;
1450 }
1451
1452 cursor = response;
1453 cursor = netagent_buffer_write_message_header(cursor, NETAGENT_MESSAGE_TYPE_GET,
1454 NETAGENT_MESSAGE_FLAGS_RESPONSE, message_id, 0,
1455 response_size - sizeof(struct netagent_message_header));
1456 memcpy(cursor, session->wrapper->netagent, sizeof(struct netagent) +
1457 session->wrapper->netagent->netagent_data_size);
1458
1459 lck_rw_done(&netagent_lock);
1460
1461 if (!netagent_send_ctl_data(session->control_unit, response, response_size)) {
1462 NETAGENTLOG0(LOG_ERR, "Failed to send response");
1463 }
1464 kfree_data(response, response_size);
1465 return;
1466 fail:
1467 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_GET, message_id, response_error);
1468 }
1469
1470 errno_t
netagent_assign_nexus(netagent_session_t _session,uuid_t necp_client_uuid,void * assign_message,size_t assigned_results_length)1471 netagent_assign_nexus(netagent_session_t _session, uuid_t necp_client_uuid,
1472 void *assign_message, size_t assigned_results_length)
1473 {
1474 struct netagent_session *session = (struct netagent_session *)_session;
1475 uuid_t netagent_uuid;
1476 if (session == NULL) {
1477 NETAGENTLOG0(LOG_ERR, "Cannot assign nexus from NULL session");
1478 return EINVAL;
1479 }
1480
1481 lck_rw_lock_shared(&netagent_lock);
1482 if (session->wrapper == NULL) {
1483 lck_rw_done(&netagent_lock);
1484 NETAGENTLOG0(LOG_ERR, "Session has no agent");
1485 return ENOENT;
1486 }
1487 uuid_copy(netagent_uuid, session->wrapper->netagent->netagent_uuid);
1488 lck_rw_done(&netagent_lock);
1489
1490 // Note that if the error is 0, NECP has taken over our malloc'ed buffer
1491 int error = necp_assign_client_result(netagent_uuid, necp_client_uuid, assign_message, assigned_results_length);
1492 if (error) {
1493 // necp_assign_client_result returns POSIX errors; don't error for ENOENT
1494 NETAGENTLOG((error == ENOENT ? LOG_DEBUG : LOG_ERR), "Client assignment failed: %d", error);
1495 return error;
1496 }
1497
1498 NETAGENTLOG0(LOG_DEBUG, "Agent assigned nexus properties to client");
1499 return 0;
1500 }
1501
1502 errno_t
netagent_update_flow_protoctl_event(netagent_session_t _session,uuid_t client_id,uint32_t protoctl_event_code,uint32_t protoctl_event_val,uint32_t protoctl_event_tcp_seq_number)1503 netagent_update_flow_protoctl_event(netagent_session_t _session,
1504 uuid_t client_id, uint32_t protoctl_event_code,
1505 uint32_t protoctl_event_val, uint32_t protoctl_event_tcp_seq_number)
1506 {
1507 struct netagent_session *session = (struct netagent_session *)_session;
1508 uuid_t netagent_uuid;
1509 int error = 0;
1510
1511 if (session == NULL) {
1512 NETAGENTLOG0(LOG_ERR, "Cannot assign nexus from NULL session");
1513 return EINVAL;
1514 }
1515
1516 lck_rw_lock_shared(&netagent_lock);
1517 if (session->wrapper == NULL) {
1518 lck_rw_done(&netagent_lock);
1519 NETAGENTLOG0(LOG_ERR, "Session has no agent");
1520 return ENOENT;
1521 }
1522 uuid_copy(netagent_uuid, session->wrapper->netagent->netagent_uuid);
1523 lck_rw_done(&netagent_lock);
1524
1525 error = necp_update_flow_protoctl_event(netagent_uuid,
1526 client_id, protoctl_event_code, protoctl_event_val, protoctl_event_tcp_seq_number);
1527
1528 return error;
1529 }
1530
1531 static errno_t
netagent_handle_assign_nexus_setopt(struct netagent_session * session,u_int8_t * payload,size_t payload_length)1532 netagent_handle_assign_nexus_setopt(struct netagent_session *session, u_int8_t *payload,
1533 size_t payload_length)
1534 {
1535 errno_t response_error = 0;
1536 struct netagent_assign_nexus_message *assign_nexus_netagent = (struct netagent_assign_nexus_message *)(void *)payload;
1537 uuid_t client_id;
1538 uuid_t netagent_uuid;
1539 u_int8_t *assigned_results = NULL;
1540
1541 if (session == NULL) {
1542 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1543 response_error = ENOENT;
1544 goto done;
1545 }
1546
1547 if (payload == NULL) {
1548 NETAGENTLOG0(LOG_ERR, "No payload received");
1549 response_error = EINVAL;
1550 goto done;
1551 }
1552
1553 lck_rw_lock_shared(&netagent_lock);
1554 if (session->wrapper == NULL) {
1555 lck_rw_done(&netagent_lock);
1556 NETAGENTLOG0(LOG_ERR, "Session has no agent to get");
1557 response_error = ENOENT;
1558 goto done;
1559 }
1560
1561 uuid_copy(netagent_uuid, session->wrapper->netagent->netagent_uuid);
1562 lck_rw_done(&netagent_lock);
1563
1564 if (payload_length < sizeof(uuid_t)) {
1565 NETAGENTLOG0(LOG_ERR, "Assign message is too short");
1566 response_error = EINVAL;
1567 goto done;
1568 }
1569
1570 memcpy(client_id, assign_nexus_netagent->assign_client_id, sizeof(client_id));
1571 size_t assigned_results_length = (payload_length - sizeof(client_id));
1572
1573 if (assigned_results_length > 0) {
1574 assigned_results = kalloc_data(assigned_results_length, Z_WAITOK);
1575 if (assigned_results == NULL) {
1576 NETAGENTLOG(LOG_ERR, "Failed to allocate assign message (%lu bytes)", assigned_results_length);
1577 response_error = ENOMEM;
1578 goto done;
1579 }
1580 memcpy(assigned_results, assign_nexus_netagent->assign_necp_results, assigned_results_length);
1581 }
1582
1583 // Note that if the error is 0, NECP has taken over our malloc'ed buffer
1584 response_error = necp_assign_client_result(netagent_uuid, client_id, assigned_results, assigned_results_length);
1585 if (response_error) {
1586 // necp_assign_client_result returns POSIX errors
1587 kfree_data(assigned_results, assigned_results_length);
1588 NETAGENTLOG(LOG_ERR, "Client assignment failed: %d", response_error);
1589 goto done;
1590 }
1591
1592 NETAGENTLOG0(LOG_DEBUG, "Agent assigned nexus properties to client");
1593 done:
1594 return response_error;
1595 }
1596
1597
1598 static void
netagent_handle_assign_nexus_message(struct netagent_session * session,u_int32_t message_id,size_t payload_length,mbuf_t packet,size_t offset)1599 netagent_handle_assign_nexus_message(struct netagent_session *session, u_int32_t message_id,
1600 size_t payload_length, mbuf_t packet, size_t offset)
1601 {
1602 int error = 0;
1603 u_int32_t response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1604 uuid_t client_id;
1605 uuid_t netagent_uuid;
1606 u_int8_t *assigned_results = NULL;
1607
1608 if (session == NULL) {
1609 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1610 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1611 goto fail;
1612 }
1613
1614 lck_rw_lock_shared(&netagent_lock);
1615 if (session->wrapper == NULL) {
1616 lck_rw_done(&netagent_lock);
1617 NETAGENTLOG0(LOG_ERR, "Session has no agent to get");
1618 response_error = NETAGENT_MESSAGE_ERROR_NOT_REGISTERED;
1619 goto fail;
1620 }
1621 uuid_copy(netagent_uuid, session->wrapper->netagent->netagent_uuid);
1622 lck_rw_done(&netagent_lock);
1623
1624 if (payload_length < sizeof(uuid_t)) {
1625 NETAGENTLOG0(LOG_ERR, "Assign message is too short");
1626 response_error = NETAGENT_MESSAGE_ERROR_INVALID_DATA;
1627 goto fail;
1628 }
1629
1630 error = mbuf_copydata(packet, offset, sizeof(client_id), &client_id);
1631 if (error) {
1632 NETAGENTLOG(LOG_ERR, "Failed to read uuid for assign message: %d", error);
1633 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1634 goto fail;
1635 }
1636
1637 size_t assigned_results_length = (payload_length - sizeof(client_id));
1638 if (assigned_results_length > 0) {
1639 assigned_results = kalloc_data( assigned_results_length, Z_WAITOK);
1640 if (assigned_results == NULL) {
1641 NETAGENTLOG(LOG_ERR, "Failed to allocate assign message (%lu bytes)", assigned_results_length);
1642 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1643 goto fail;
1644 }
1645
1646 error = mbuf_copydata(packet, offset + sizeof(client_id), assigned_results_length, assigned_results);
1647 if (error) {
1648 kfree_data(assigned_results, assigned_results_length);
1649 NETAGENTLOG(LOG_ERR, "Failed to read assign message: %d", error);
1650 response_error = NETAGENT_MESSAGE_ERROR_INTERNAL;
1651 goto fail;
1652 }
1653 }
1654
1655 // Note that if the error is 0, NECP has taken over our malloc'ed buffer
1656 error = necp_assign_client_result(netagent_uuid, client_id, assigned_results, assigned_results_length);
1657 if (error) {
1658 kfree_data(assigned_results, assigned_results_length);
1659 NETAGENTLOG(LOG_ERR, "Client assignment failed: %d", error);
1660 response_error = NETAGENT_MESSAGE_ERROR_CANNOT_ASSIGN;
1661 goto fail;
1662 }
1663
1664 NETAGENTLOG0(LOG_DEBUG, "Agent assigned nexus properties to client");
1665 netagent_send_success_response(session, NETAGENT_MESSAGE_TYPE_ASSIGN_NEXUS, message_id);
1666 return;
1667 fail:
1668 netagent_send_error_response(session, NETAGENT_MESSAGE_TYPE_ASSIGN_NEXUS, message_id, response_error);
1669 }
1670
1671 static errno_t
netagent_handle_assign_group_setopt(struct netagent_session * session,u_int8_t * payload,size_t payload_length)1672 netagent_handle_assign_group_setopt(struct netagent_session *session, u_int8_t *payload,
1673 size_t payload_length)
1674 {
1675 errno_t response_error = 0;
1676 struct netagent_assign_nexus_message *assign_message = (struct netagent_assign_nexus_message *)(void *)payload;
1677 uuid_t client_id;
1678 uuid_t netagent_uuid;
1679 u_int8_t *assigned_group_members = NULL;
1680
1681 if (session == NULL) {
1682 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1683 response_error = ENOENT;
1684 goto done;
1685 }
1686
1687 if (payload == NULL) {
1688 NETAGENTLOG0(LOG_ERR, "No payload received");
1689 response_error = EINVAL;
1690 goto done;
1691 }
1692
1693 lck_rw_lock_shared(&netagent_lock);
1694 if (session->wrapper == NULL) {
1695 lck_rw_done(&netagent_lock);
1696 NETAGENTLOG0(LOG_ERR, "Session has no agent to get");
1697 response_error = ENOENT;
1698 goto done;
1699 }
1700
1701 uuid_copy(netagent_uuid, session->wrapper->netagent->netagent_uuid);
1702 lck_rw_done(&netagent_lock);
1703
1704 if (payload_length < sizeof(uuid_t)) {
1705 NETAGENTLOG0(LOG_ERR, "Group assign message is too short");
1706 response_error = EINVAL;
1707 goto done;
1708 }
1709
1710 memcpy(client_id, assign_message->assign_client_id, sizeof(client_id));
1711 size_t assigned_group_members_length = (payload_length - sizeof(client_id));
1712
1713 if (assigned_group_members_length > 0) {
1714 assigned_group_members = (u_int8_t *)kalloc_data(assigned_group_members_length, Z_WAITOK);
1715 if (assigned_group_members == NULL) {
1716 NETAGENTLOG(LOG_ERR, "Failed to allocate group assign message (%lu bytes)", assigned_group_members_length);
1717 response_error = ENOMEM;
1718 goto done;
1719 }
1720 memcpy(assigned_group_members, assign_message->assign_necp_results, assigned_group_members_length);
1721 }
1722
1723 // Note that if the error is 0, NECP has taken over our malloc'ed buffer
1724 response_error = necp_assign_client_group_members(netagent_uuid, client_id, assigned_group_members, assigned_group_members_length);
1725 if (response_error != 0) {
1726 // necp_assign_client_group_members returns POSIX errors
1727 if (assigned_group_members != NULL) {
1728 kfree_data(assigned_group_members, assigned_group_members_length);
1729 }
1730 NETAGENTLOG(LOG_ERR, "Client group assignment failed: %d", response_error);
1731 goto done;
1732 }
1733
1734 NETAGENTLOG0(LOG_DEBUG, "Agent assigned group members to client");
1735 done:
1736 return response_error;
1737 }
1738
1739
1740 errno_t
netagent_handle_use_count_setopt(struct netagent_session * session,u_int8_t * payload,size_t payload_length)1741 netagent_handle_use_count_setopt(struct netagent_session *session, u_int8_t *payload, size_t payload_length)
1742 {
1743 errno_t response_error = 0;
1744 uint64_t use_count = 0;
1745
1746 if (session == NULL) {
1747 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1748 response_error = ENOENT;
1749 goto done;
1750 }
1751
1752 if (payload == NULL) {
1753 NETAGENTLOG0(LOG_ERR, "No payload received");
1754 response_error = EINVAL;
1755 goto done;
1756 }
1757
1758 if (payload_length != sizeof(use_count)) {
1759 NETAGENTLOG(LOG_ERR, "Payload length is invalid (%lu)", payload_length);
1760 response_error = EINVAL;
1761 goto done;
1762 }
1763
1764 memcpy(&use_count, payload, sizeof(use_count));
1765
1766 lck_rw_lock_shared(&netagent_lock);
1767
1768 if (session->wrapper == NULL) {
1769 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
1770 response_error = ENOENT;
1771 lck_rw_done(&netagent_lock);
1772 goto done;
1773 }
1774
1775 session->wrapper->use_count = use_count;
1776
1777 lck_rw_done(&netagent_lock);
1778
1779 done:
1780 return response_error;
1781 }
1782
1783 errno_t
netagent_handle_use_count_getopt(struct netagent_session * session,u_int8_t * buffer,size_t * buffer_length)1784 netagent_handle_use_count_getopt(struct netagent_session *session, u_int8_t *buffer, size_t *buffer_length)
1785 {
1786 errno_t response_error = 0;
1787 uint64_t use_count = 0;
1788
1789 if (session == NULL) {
1790 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1791 response_error = ENOENT;
1792 goto done;
1793 }
1794
1795 if (buffer == NULL) {
1796 NETAGENTLOG0(LOG_ERR, "No payload received");
1797 response_error = EINVAL;
1798 goto done;
1799 }
1800
1801 if (*buffer_length != sizeof(use_count)) {
1802 NETAGENTLOG(LOG_ERR, "Buffer length is invalid (%lu)", *buffer_length);
1803 response_error = EINVAL;
1804 goto done;
1805 }
1806
1807 lck_rw_lock_shared(&netagent_lock);
1808
1809 if (session->wrapper == NULL) {
1810 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
1811 response_error = ENOENT;
1812 lck_rw_done(&netagent_lock);
1813 goto done;
1814 }
1815
1816 use_count = session->wrapper->use_count;
1817 lck_rw_done(&netagent_lock);
1818
1819 memcpy(buffer, &use_count, sizeof(use_count));
1820 *buffer_length = sizeof(use_count);
1821
1822 done:
1823 return response_error;
1824 }
1825
1826 static errno_t
netagent_handle_add_token_setopt(struct netagent_session * session,u_int8_t * token,size_t token_length)1827 netagent_handle_add_token_setopt(struct netagent_session *session, u_int8_t *token, size_t token_length)
1828 {
1829 errno_t response_error = 0;
1830
1831 if (session == NULL) {
1832 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1833 response_error = ENOENT;
1834 goto done;
1835 }
1836
1837 if (token == NULL) {
1838 NETAGENTLOG0(LOG_ERR, "No token received");
1839 response_error = EINVAL;
1840 goto done;
1841 }
1842
1843 if (token_length > NETAGENT_MAX_DATA_SIZE) {
1844 NETAGENTLOG(LOG_ERR, "Token length is invalid (%lu)", token_length);
1845 response_error = EINVAL;
1846 goto done;
1847 }
1848
1849 lck_rw_lock_exclusive(&netagent_lock);
1850
1851 if (session->wrapper == NULL) {
1852 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
1853 response_error = ENOENT;
1854 lck_rw_done(&netagent_lock);
1855 goto done;
1856 }
1857
1858 if (session->wrapper->token_count >= NETAGENT_MAX_TOKEN_COUNT) {
1859 NETAGENTLOG0(LOG_ERR, "Session cannot add more tokens");
1860 response_error = EINVAL;
1861 lck_rw_done(&netagent_lock);
1862 goto done;
1863 }
1864
1865 struct netagent_token *token_struct = NULL;
1866
1867 token_struct = kalloc_type(struct netagent_token, Z_WAITOK | Z_ZERO | Z_NOFAIL);
1868 token_struct->token_bytes = kalloc_data(token_length, Z_WAITOK | Z_NOFAIL);
1869 token_struct->token_length = (u_int32_t)token_length;
1870 memcpy(token_struct->token_bytes, token, token_length);
1871
1872 TAILQ_INSERT_TAIL(&session->wrapper->token_list, token_struct, token_chain);
1873
1874 session->wrapper->token_count++;
1875
1876 lck_rw_done(&netagent_lock);
1877 done:
1878 return response_error;
1879 }
1880
1881 static errno_t
netagent_handle_flush_tokens_setopt(struct netagent_session * session,__unused u_int8_t * buffer,__unused size_t buffer_length)1882 netagent_handle_flush_tokens_setopt(struct netagent_session *session, __unused u_int8_t *buffer, __unused size_t buffer_length)
1883 {
1884 errno_t response_error = 0;
1885
1886 if (session == NULL) {
1887 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1888 response_error = ENOENT;
1889 goto done;
1890 }
1891
1892 lck_rw_lock_exclusive(&netagent_lock);
1893
1894 if (session->wrapper == NULL) {
1895 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
1896 response_error = ENOENT;
1897 lck_rw_done(&netagent_lock);
1898 goto done;
1899 }
1900
1901 struct netagent_token *search_token = NULL;
1902 struct netagent_token *temp_token = NULL;
1903 TAILQ_FOREACH_SAFE(search_token, &session->wrapper->token_list, token_chain, temp_token) {
1904 TAILQ_REMOVE(&session->wrapper->token_list, search_token, token_chain);
1905 netagent_token_free(search_token);
1906 }
1907 session->wrapper->token_count = 0;
1908
1909 lck_rw_done(&netagent_lock);
1910 done:
1911 return response_error;
1912 }
1913
1914 static errno_t
netagent_handle_token_count_getopt(struct netagent_session * session,u_int8_t * buffer,size_t * buffer_length)1915 netagent_handle_token_count_getopt(struct netagent_session *session, u_int8_t *buffer, size_t *buffer_length)
1916 {
1917 errno_t response_error = 0;
1918 uint32_t token_count = 0;
1919
1920 if (session == NULL) {
1921 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1922 response_error = ENOENT;
1923 goto done;
1924 }
1925
1926 if (buffer == NULL) {
1927 NETAGENTLOG0(LOG_ERR, "No payload received");
1928 response_error = EINVAL;
1929 goto done;
1930 }
1931
1932 if (*buffer_length != sizeof(token_count)) {
1933 NETAGENTLOG(LOG_ERR, "Buffer length is invalid (%lu)", *buffer_length);
1934 response_error = EINVAL;
1935 goto done;
1936 }
1937
1938 lck_rw_lock_shared(&netagent_lock);
1939
1940 if (session->wrapper == NULL) {
1941 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
1942 response_error = ENOENT;
1943 lck_rw_done(&netagent_lock);
1944 goto done;
1945 }
1946
1947 token_count = session->wrapper->token_count;
1948 lck_rw_done(&netagent_lock);
1949
1950 memcpy(buffer, &token_count, sizeof(token_count));
1951 *buffer_length = sizeof(token_count);
1952
1953 done:
1954 return response_error;
1955 }
1956
1957 static errno_t
netagent_handle_token_low_water_setopt(struct netagent_session * session,u_int8_t * buffer,size_t buffer_length)1958 netagent_handle_token_low_water_setopt(struct netagent_session *session, u_int8_t *buffer, size_t buffer_length)
1959 {
1960 errno_t response_error = 0;
1961 uint32_t token_low_water = 0;
1962
1963 if (session == NULL) {
1964 NETAGENTLOG0(LOG_ERR, "Failed to find session");
1965 response_error = ENOENT;
1966 goto done;
1967 }
1968
1969 if (buffer == NULL) {
1970 NETAGENTLOG0(LOG_ERR, "No payload received");
1971 response_error = EINVAL;
1972 goto done;
1973 }
1974
1975 if (buffer_length != sizeof(token_low_water)) {
1976 NETAGENTLOG(LOG_ERR, "Buffer length is invalid (%lu)", buffer_length);
1977 response_error = EINVAL;
1978 goto done;
1979 }
1980
1981 memcpy(&token_low_water, buffer, sizeof(token_low_water));
1982
1983 lck_rw_lock_exclusive(&netagent_lock);
1984
1985 if (session->wrapper == NULL) {
1986 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
1987 response_error = ENOENT;
1988 lck_rw_done(&netagent_lock);
1989 goto done;
1990 }
1991
1992 session->wrapper->token_low_water = token_low_water;
1993 lck_rw_done(&netagent_lock);
1994
1995 done:
1996 return response_error;
1997 }
1998
1999 static errno_t
netagent_handle_token_low_water_getopt(struct netagent_session * session,u_int8_t * buffer,size_t * buffer_length)2000 netagent_handle_token_low_water_getopt(struct netagent_session *session, u_int8_t *buffer, size_t *buffer_length)
2001 {
2002 errno_t response_error = 0;
2003 uint32_t token_low_water = 0;
2004
2005 if (session == NULL) {
2006 NETAGENTLOG0(LOG_ERR, "Failed to find session");
2007 response_error = ENOENT;
2008 goto done;
2009 }
2010
2011 if (buffer == NULL) {
2012 NETAGENTLOG0(LOG_ERR, "No payload received");
2013 response_error = EINVAL;
2014 goto done;
2015 }
2016
2017 if (*buffer_length != sizeof(token_low_water)) {
2018 NETAGENTLOG(LOG_ERR, "Buffer length is invalid (%lu)", *buffer_length);
2019 response_error = EINVAL;
2020 goto done;
2021 }
2022
2023 lck_rw_lock_shared(&netagent_lock);
2024
2025 if (session->wrapper == NULL) {
2026 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2027 response_error = ENOENT;
2028 lck_rw_done(&netagent_lock);
2029 goto done;
2030 }
2031
2032 token_low_water = session->wrapper->token_low_water;
2033 lck_rw_done(&netagent_lock);
2034
2035 memcpy(buffer, &token_low_water, sizeof(token_low_water));
2036 *buffer_length = sizeof(token_low_water);
2037
2038 done:
2039 return response_error;
2040 }
2041
2042 static errno_t
netagent_handle_reset_client_error_setopt(struct netagent_session * session,__unused u_int8_t * payload,__unused size_t payload_length)2043 netagent_handle_reset_client_error_setopt(struct netagent_session *session, __unused u_int8_t *payload, __unused size_t payload_length)
2044 {
2045 errno_t response_error = 0;
2046
2047 if (session == NULL) {
2048 NETAGENTLOG0(LOG_ERR, "Failed to find session");
2049 response_error = ENOENT;
2050 goto done;
2051 }
2052
2053 lck_rw_lock_exclusive(&netagent_lock);
2054
2055 if (session->wrapper == NULL) {
2056 NETAGENTLOG0(LOG_ERR, "Session has no agent registered");
2057 response_error = ENOENT;
2058 lck_rw_done(&netagent_lock);
2059 goto done;
2060 }
2061
2062 struct netagent_token *search_token = NULL;
2063 struct netagent_token *temp_token = NULL;
2064 TAILQ_FOREACH_SAFE(search_token, &session->wrapper->token_list, token_chain, temp_token) {
2065 TAILQ_REMOVE(&session->wrapper->token_list, search_token, token_chain);
2066 netagent_token_free(search_token);
2067 }
2068 session->wrapper->last_client_error = 0;
2069 session->wrapper->client_error_count = 0;
2070
2071 lck_rw_done(&netagent_lock);
2072 done:
2073 return response_error;
2074 }
2075
2076 static struct netagent_wrapper *
netagent_find_agent_with_uuid(uuid_t uuid)2077 netagent_find_agent_with_uuid(uuid_t uuid)
2078 {
2079 struct netagent_wrapper *search_netagent = NULL;
2080
2081 LIST_FOREACH(search_netagent, &master_netagent_list, master_chain) {
2082 if (uuid_compare(search_netagent->netagent->netagent_uuid, uuid) == 0) {
2083 return search_netagent;
2084 }
2085 }
2086
2087 return NULL;
2088 }
2089
2090 void
netagent_post_updated_interfaces(uuid_t uuid)2091 netagent_post_updated_interfaces(uuid_t uuid)
2092 {
2093 struct netagent_wrapper *wrapper = NULL;
2094 lck_rw_lock_shared(&netagent_lock);
2095 wrapper = netagent_find_agent_with_uuid(uuid);
2096 lck_rw_done(&netagent_lock);
2097
2098 if (wrapper != NULL) {
2099 netagent_post_event(uuid, KEV_NETAGENT_UPDATED_INTERFACES, TRUE, false);
2100 } else {
2101 NETAGENTLOG0(LOG_DEBUG, "Interface event with no associated agent");
2102 }
2103
2104 return;
2105 }
2106
2107 static u_int32_t
netagent_dump_get_data_size_locked()2108 netagent_dump_get_data_size_locked()
2109 {
2110 struct netagent_wrapper *search_netagent = NULL;
2111 u_int32_t total_netagent_data_size = 0;
2112 // Traverse the master list to know how much data the client needs to allocate to get the list of agent UUIDs
2113 LIST_FOREACH(search_netagent, &master_netagent_list, master_chain) {
2114 total_netagent_data_size += sizeof(search_netagent->netagent->netagent_uuid);
2115 }
2116 return total_netagent_data_size;
2117 }
2118
2119 static void
netagent_dump_copy_data_locked(u_int8_t * buffer,u_int32_t buffer_length)2120 netagent_dump_copy_data_locked(u_int8_t *buffer, u_int32_t buffer_length)
2121 {
2122 size_t response_size = 0;
2123 u_int8_t *cursor = NULL;
2124 struct netagent_wrapper *search_netagent = NULL;
2125
2126 response_size = buffer_length; // We already know that buffer_length is the same as total_netagent_data_size.
2127 cursor = buffer;
2128 LIST_FOREACH(search_netagent, &master_netagent_list, master_chain) {
2129 memcpy(cursor, search_netagent->netagent->netagent_uuid, sizeof(search_netagent->netagent->netagent_uuid));
2130 cursor += sizeof(search_netagent->netagent->netagent_uuid);
2131 }
2132 }
2133
2134 int
netagent_ioctl(u_long cmd,caddr_t data)2135 netagent_ioctl(u_long cmd, caddr_t data)
2136 {
2137 int error = 0;
2138
2139 switch (cmd) {
2140 case SIOCGIFAGENTLIST32:
2141 case SIOCGIFAGENTLIST64: {
2142 /* Check entitlement if the client requests agent dump */
2143 errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
2144 if (cred_result != 0) {
2145 NETAGENTLOG0(LOG_ERR, "Client does not hold the necessary entitlement to get netagent information");
2146 return EINVAL;
2147 }
2148 break;
2149 }
2150 default:
2151 break;
2152 }
2153
2154 lck_rw_lock_shared(&netagent_lock);
2155 switch (cmd) {
2156 case SIOCGIFAGENTDATA32: {
2157 struct netagent_req32 *ifsir32 = (struct netagent_req32 *)(void *)data;
2158 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(ifsir32->netagent_uuid);
2159 if (wrapper == NULL) {
2160 error = ENOENT;
2161 break;
2162 }
2163 uuid_copy(ifsir32->netagent_uuid, wrapper->netagent->netagent_uuid);
2164 memcpy(ifsir32->netagent_domain, wrapper->netagent->netagent_domain, sizeof(ifsir32->netagent_domain));
2165 memcpy(ifsir32->netagent_type, wrapper->netagent->netagent_type, sizeof(ifsir32->netagent_type));
2166 memcpy(ifsir32->netagent_desc, wrapper->netagent->netagent_desc, sizeof(ifsir32->netagent_desc));
2167 ifsir32->netagent_flags = wrapper->netagent->netagent_flags;
2168 if (ifsir32->netagent_data_size == 0) {
2169 // First pass, client wants data size
2170 ifsir32->netagent_data_size = wrapper->netagent->netagent_data_size;
2171 } else if (ifsir32->netagent_data != USER_ADDR_NULL &&
2172 ifsir32->netagent_data_size == wrapper->netagent->netagent_data_size) {
2173 // Second pass, client wants data buffer filled out
2174 error = copyout(wrapper->netagent->netagent_data, ifsir32->netagent_data, wrapper->netagent->netagent_data_size);
2175 } else {
2176 error = EINVAL;
2177 }
2178 break;
2179 }
2180 case SIOCGIFAGENTDATA64: {
2181 struct netagent_req64 *ifsir64 = (struct netagent_req64 *)(void *)data;
2182 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(ifsir64->netagent_uuid);
2183 if (wrapper == NULL) {
2184 error = ENOENT;
2185 break;
2186 }
2187 uuid_copy(ifsir64->netagent_uuid, wrapper->netagent->netagent_uuid);
2188 memcpy(ifsir64->netagent_domain, wrapper->netagent->netagent_domain, sizeof(ifsir64->netagent_domain));
2189 memcpy(ifsir64->netagent_type, wrapper->netagent->netagent_type, sizeof(ifsir64->netagent_type));
2190 memcpy(ifsir64->netagent_desc, wrapper->netagent->netagent_desc, sizeof(ifsir64->netagent_desc));
2191 ifsir64->netagent_flags = wrapper->netagent->netagent_flags;
2192 if (ifsir64->netagent_data_size == 0) {
2193 // First pass, client wants data size
2194 ifsir64->netagent_data_size = wrapper->netagent->netagent_data_size;
2195 } else if (ifsir64->netagent_data != USER_ADDR_NULL &&
2196 ifsir64->netagent_data_size == wrapper->netagent->netagent_data_size) {
2197 // Second pass, client wants data buffer filled out
2198 error = copyout(wrapper->netagent->netagent_data, ifsir64->netagent_data, wrapper->netagent->netagent_data_size);
2199 } else {
2200 error = EINVAL;
2201 }
2202 break;
2203 }
2204 case SIOCGIFAGENTLIST32: {
2205 struct netagentlist_req32 *ifsir32 = (struct netagentlist_req32 *)(void *)data;
2206 if (ifsir32->data_size == 0) {
2207 // First pass, client wants data size
2208 ifsir32->data_size = netagent_dump_get_data_size_locked();
2209 } else if (ifsir32->data != USER_ADDR_NULL &&
2210 ifsir32->data_size > 0 &&
2211 ifsir32->data_size == netagent_dump_get_data_size_locked()) {
2212 // Second pass, client wants data buffer filled out
2213 u_int8_t *response = NULL;
2214 response = (u_int8_t *)kalloc_data(ifsir32->data_size, Z_NOWAIT | Z_ZERO);
2215 if (response == NULL) {
2216 error = ENOMEM;
2217 break;
2218 }
2219
2220 netagent_dump_copy_data_locked(response, ifsir32->data_size);
2221 error = copyout(response, ifsir32->data, ifsir32->data_size);
2222 kfree_data(response, ifsir32->data_size);
2223 } else {
2224 error = EINVAL;
2225 }
2226 break;
2227 }
2228 case SIOCGIFAGENTLIST64: {
2229 struct netagentlist_req64 *ifsir64 = (struct netagentlist_req64 *)(void *)data;
2230 if (ifsir64->data_size == 0) {
2231 // First pass, client wants data size
2232 ifsir64->data_size = netagent_dump_get_data_size_locked();
2233 } else if (ifsir64->data != USER_ADDR_NULL &&
2234 ifsir64->data_size > 0 &&
2235 ifsir64->data_size == netagent_dump_get_data_size_locked()) {
2236 // Second pass, client wants data buffer filled out
2237 u_int8_t *response = NULL;
2238 response = (u_int8_t *)kalloc_data(ifsir64->data_size, Z_NOWAIT | Z_ZERO);
2239 if (response == NULL) {
2240 error = ENOMEM;
2241 break;
2242 }
2243
2244 netagent_dump_copy_data_locked(response, ifsir64->data_size);
2245 error = copyout(response, ifsir64->data, ifsir64->data_size);
2246 kfree_data(response, ifsir64->data_size);
2247 } else {
2248 error = EINVAL;
2249 }
2250 break;
2251 }
2252 default: {
2253 error = EINVAL;
2254 break;
2255 }
2256 }
2257 lck_rw_done(&netagent_lock);
2258 return error;
2259 }
2260
2261 u_int32_t
netagent_get_flags(uuid_t uuid)2262 netagent_get_flags(uuid_t uuid)
2263 {
2264 u_int32_t flags = 0;
2265 lck_rw_lock_shared(&netagent_lock);
2266 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(uuid);
2267 if (wrapper != NULL) {
2268 flags = wrapper->netagent->netagent_flags;
2269 } else {
2270 NETAGENTLOG0(LOG_DEBUG, "Flags requested for invalid netagent");
2271 }
2272 lck_rw_done(&netagent_lock);
2273
2274 return flags;
2275 }
2276
2277 errno_t
netagent_set_flags(uuid_t uuid,u_int32_t flags)2278 netagent_set_flags(uuid_t uuid, u_int32_t flags)
2279 {
2280 errno_t error = 0;
2281 bool updated = false;
2282
2283 lck_rw_lock_exclusive(&netagent_lock);
2284 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(uuid);
2285 if (wrapper != NULL) {
2286 // Don't allow the clients to clear
2287 // NETAGENT_FLAG_REGISTERED.
2288 uint32_t registered =
2289 wrapper->netagent->netagent_flags & NETAGENT_FLAG_REGISTERED;
2290 flags |= registered;
2291 if (wrapper->netagent->netagent_flags != flags) {
2292 wrapper->netagent->netagent_flags = flags;
2293 wrapper->generation = g_next_generation++;
2294 updated = true;
2295 }
2296 } else {
2297 NETAGENTLOG0(LOG_DEBUG,
2298 "Attempt to set flags for invalid netagent");
2299 error = ENOENT;
2300 }
2301 lck_rw_done(&netagent_lock);
2302 if (updated) {
2303 netagent_post_event(uuid, KEV_NETAGENT_UPDATED, true, false);
2304 }
2305
2306 return error;
2307 }
2308
2309 u_int32_t
netagent_get_generation(uuid_t uuid)2310 netagent_get_generation(uuid_t uuid)
2311 {
2312 u_int32_t generation = 0;
2313 lck_rw_lock_shared(&netagent_lock);
2314 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(uuid);
2315 if (wrapper != NULL) {
2316 generation = wrapper->generation;
2317 } else {
2318 NETAGENTLOG0(LOG_DEBUG, "Generation requested for invalid netagent");
2319 }
2320 lck_rw_done(&netagent_lock);
2321
2322 return generation;
2323 }
2324
2325 bool
netagent_get_agent_domain_and_type(uuid_t uuid,char * domain,char * type)2326 netagent_get_agent_domain_and_type(uuid_t uuid, char *domain, char *type)
2327 {
2328 bool found = FALSE;
2329 if (domain == NULL || type == NULL) {
2330 NETAGENTLOG(LOG_ERR, "Invalid arguments for netagent_get_agent_domain_and_type %p %p", domain, type);
2331 return FALSE;
2332 }
2333
2334 lck_rw_lock_shared(&netagent_lock);
2335 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(uuid);
2336 if (wrapper != NULL) {
2337 found = TRUE;
2338 memcpy(domain, wrapper->netagent->netagent_domain, NETAGENT_DOMAINSIZE);
2339 memcpy(type, wrapper->netagent->netagent_type, NETAGENT_TYPESIZE);
2340 } else {
2341 NETAGENTLOG0(LOG_ERR, "Type requested for invalid netagent");
2342 }
2343 lck_rw_done(&netagent_lock);
2344
2345 return found;
2346 }
2347
2348 int
netagent_kernel_trigger(uuid_t uuid)2349 netagent_kernel_trigger(uuid_t uuid)
2350 {
2351 int error = 0;
2352
2353 lck_rw_lock_shared(&netagent_lock);
2354 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(uuid);
2355 if (wrapper == NULL) {
2356 NETAGENTLOG0(LOG_ERR, "Requested netagent for kernel trigger could not be found");
2357 error = ENOENT;
2358 goto done;
2359 }
2360
2361 if ((wrapper->netagent->netagent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) == 0) {
2362 NETAGENTLOG0(LOG_ERR, "Requested netagent for kernel trigger is not kernel activated");
2363 // Agent does not accept kernel triggers
2364 error = EINVAL;
2365 goto done;
2366 }
2367
2368 if ((wrapper->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE)) {
2369 // Agent already active
2370 NETAGENTLOG0(LOG_INFO, "Requested netagent for kernel trigger is already active");
2371 error = 0;
2372 goto done;
2373 }
2374
2375 error = netagent_send_trigger(wrapper, current_proc(), NETAGENT_TRIGGER_FLAG_KERNEL, NETAGENT_MESSAGE_TYPE_TRIGGER);
2376 NETAGENTLOG((error ? LOG_ERR : LOG_INFO), "Triggered netagent from kernel (error %d)", error);
2377 done:
2378 lck_rw_done(&netagent_lock);
2379 return error;
2380 }
2381
2382 int
netagent_client_message_with_params(uuid_t agent_uuid,uuid_t necp_client_uuid,pid_t pid,void * handle,u_int8_t message_type,struct necp_client_agent_parameters * parameters,void ** assigned_results,size_t * assigned_results_length)2383 netagent_client_message_with_params(uuid_t agent_uuid,
2384 uuid_t necp_client_uuid,
2385 pid_t pid,
2386 void *handle,
2387 u_int8_t message_type,
2388 struct necp_client_agent_parameters *parameters,
2389 void **assigned_results,
2390 size_t *assigned_results_length)
2391 {
2392 int error = 0;
2393
2394 if (message_type != NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER &&
2395 message_type != NETAGENT_MESSAGE_TYPE_CLIENT_ASSERT &&
2396 message_type != NETAGENT_MESSAGE_TYPE_CLIENT_UNASSERT &&
2397 message_type != NETAGENT_MESSAGE_TYPE_CLIENT_ERROR &&
2398 message_type != NETAGENT_MESSAGE_TYPE_REQUEST_NEXUS &&
2399 message_type != NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS &&
2400 message_type != NETAGENT_MESSAGE_TYPE_ABORT_NEXUS &&
2401 message_type != NETAGENT_MESSAGE_TYPE_ADD_GROUP_MEMBERS &&
2402 message_type != NETAGENT_MESSAGE_TYPE_REMOVE_GROUP_MEMBERS) {
2403 NETAGENTLOG(LOG_ERR, "Client netagent message type (%d) is invalid", message_type);
2404 return EINVAL;
2405 }
2406
2407 lck_rw_lock_shared(&netagent_lock);
2408 bool should_unlock = TRUE;
2409 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(agent_uuid);
2410 if (wrapper == NULL) {
2411 NETAGENTLOG0(LOG_DEBUG, "Requested netagent for nexus instance could not be found");
2412 error = ENOENT;
2413 goto done;
2414 }
2415
2416 if (message_type == NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER) {
2417 if ((wrapper->netagent->netagent_flags & NETAGENT_FLAG_USER_ACTIVATED) == 0) {
2418 // Agent does not accept user triggers
2419 // Don't log, since this is a common case used to trigger events that cellular data is blocked, etc.
2420 error = ENOTSUP;
2421
2422
2423 pid_t report_pid = 0;
2424 uuid_t report_proc_uuid = {};
2425 if (parameters != NULL) {
2426 report_pid = parameters->u.nexus_request.epid;
2427 uuid_copy(report_proc_uuid, parameters->u.nexus_request.euuid);
2428 } else {
2429 struct proc *p = current_proc();
2430 if (p != NULL) {
2431 report_pid = proc_pid(p);
2432 proc_getexecutableuuid(p, report_proc_uuid, sizeof(report_proc_uuid));
2433 }
2434 }
2435 netagent_send_cellular_failed_event(wrapper, report_pid, report_proc_uuid);
2436 goto done;
2437 }
2438 } else if (message_type == NETAGENT_MESSAGE_TYPE_REQUEST_NEXUS ||
2439 message_type == NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS ||
2440 message_type == NETAGENT_MESSAGE_TYPE_ABORT_NEXUS) {
2441 bool is_nexus_agent = ((wrapper->netagent->netagent_flags &
2442 (NETAGENT_FLAG_NEXUS_PROVIDER |
2443 NETAGENT_FLAG_NEXUS_LISTENER |
2444 NETAGENT_FLAG_CUSTOM_IP_NEXUS |
2445 NETAGENT_FLAG_CUSTOM_ETHER_NEXUS |
2446 NETAGENT_FLAG_INTERPOSE_NEXUS)) != 0);
2447 if (!is_nexus_agent) {
2448 NETAGENTLOG0(LOG_ERR, "Requested netagent for nexus instance is not a nexus provider");
2449 // Agent is not a nexus provider
2450 error = EINVAL;
2451 goto done;
2452 }
2453
2454 if ((wrapper->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) == 0) {
2455 // Agent not active
2456 NETAGENTLOG0(LOG_INFO, "Requested netagent for nexus instance is not active");
2457 error = EINVAL;
2458 goto done;
2459 }
2460 } else if (message_type == NETAGENT_MESSAGE_TYPE_ADD_GROUP_MEMBERS ||
2461 message_type == NETAGENT_MESSAGE_TYPE_REMOVE_GROUP_MEMBERS) {
2462 bool is_group_agent = ((wrapper->netagent->netagent_flags & (NETAGENT_FLAG_SUPPORTS_GROUPS)) != 0);
2463 if (!is_group_agent) {
2464 NETAGENTLOG0(LOG_ERR, "Requested netagent for group operation is not a group provider");
2465 error = EINVAL;
2466 goto done;
2467 }
2468
2469 if ((wrapper->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE) == 0) {
2470 // Agent not active
2471 NETAGENTLOG0(LOG_INFO, "Requested netagent for group operation is not active");
2472 error = EINVAL;
2473 goto done;
2474 }
2475 }
2476
2477 if (wrapper->control_unit == 0) {
2478 if (wrapper->event_handler == NULL) {
2479 // No event handler registered for kernel agent
2480 error = EINVAL;
2481 } else {
2482 // We hold the shared lock during the event handler callout, so it is expected
2483 // that the event handler will not lead to any registrations or unregistrations
2484 // of network agents.
2485 error = wrapper->event_handler(message_type, necp_client_uuid, pid, handle,
2486 wrapper->event_context, parameters,
2487 assigned_results, assigned_results_length);
2488 if (error != 0) {
2489 VERIFY(assigned_results == NULL || *assigned_results == NULL);
2490 VERIFY(assigned_results_length == NULL || *assigned_results_length == 0);
2491 }
2492 }
2493 } else {
2494 // ABORT_NEXUS is kernel-private, so translate it for userspace nexus
2495 if (message_type == NETAGENT_MESSAGE_TYPE_ABORT_NEXUS) {
2496 message_type = NETAGENT_MESSAGE_TYPE_CLOSE_NEXUS;
2497 }
2498
2499 if (message_type == NETAGENT_MESSAGE_TYPE_CLIENT_ERROR) {
2500 const int32_t client_error = parameters->u.error;
2501 if (wrapper->last_client_error != client_error || // Always notify for an error change
2502 (client_error == 0 && wrapper->client_error_count == 0) || // Only notify once for no-error
2503 (client_error != 0 && wrapper->client_error_count < NETAGENT_MAX_CLIENT_ERROR_COUNT)) {
2504 if (lck_rw_lock_shared_to_exclusive(&netagent_lock)) {
2505 if (wrapper->last_client_error != client_error) {
2506 wrapper->last_client_error = client_error;
2507 wrapper->client_error_count = 1;
2508 } else {
2509 wrapper->client_error_count++;
2510 }
2511 error = netagent_send_error_message(wrapper, necp_client_uuid, message_type, client_error);
2512 } else {
2513 // If lck_rw_lock_shared_to_exclusive fails, it unlocks automatically
2514 should_unlock = FALSE;
2515 }
2516 }
2517 } else if (message_type == NETAGENT_MESSAGE_TYPE_ADD_GROUP_MEMBERS ||
2518 message_type == NETAGENT_MESSAGE_TYPE_REMOVE_GROUP_MEMBERS) {
2519 error = netagent_send_group_message(wrapper, necp_client_uuid, message_type, ¶meters->u.group_members);
2520 } else {
2521 error = netagent_send_client_message(wrapper, necp_client_uuid, message_type);
2522 }
2523 if (error == 0 && message_type == NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER) {
2524 if (lck_rw_lock_shared_to_exclusive(&netagent_lock)) {
2525 // Grab the lock exclusively to add a pending client to the list
2526 struct netagent_client *new_pending_client = NULL;
2527 new_pending_client = kalloc_type(struct netagent_client, Z_WAITOK);
2528 if (new_pending_client == NULL) {
2529 NETAGENTLOG0(LOG_ERR, "Failed to allocate client for trigger");
2530 } else {
2531 uuid_copy(new_pending_client->client_id, necp_client_uuid);
2532 if (parameters != NULL) {
2533 new_pending_client->client_pid = parameters->u.nexus_request.epid;
2534 uuid_copy(new_pending_client->client_proc_uuid, parameters->u.nexus_request.euuid);
2535 } else {
2536 struct proc *p = current_proc();
2537 if (p != NULL) {
2538 new_pending_client->client_pid = proc_pid(p);
2539 proc_getexecutableuuid(p, new_pending_client->client_proc_uuid, sizeof(new_pending_client->client_proc_uuid));
2540 }
2541 }
2542 LIST_INSERT_HEAD(&wrapper->pending_triggers_list, new_pending_client, client_chain);
2543 }
2544 } else {
2545 // If lck_rw_lock_shared_to_exclusive fails, it unlocks automatically
2546 should_unlock = FALSE;
2547 }
2548 }
2549 }
2550 NETAGENTLOG(((error && error != ENOENT) ? LOG_ERR : LOG_INFO), "Send message %d for client (error %d)", message_type, error);
2551 if (message_type == NETAGENT_MESSAGE_TYPE_CLIENT_TRIGGER) {
2552 uuid_string_t uuid_str;
2553 uuid_unparse(agent_uuid, uuid_str);
2554 NETAGENTLOG(LOG_NOTICE, "Triggered network agent %s, error = %d", uuid_str, error);
2555 }
2556 done:
2557 if (should_unlock) {
2558 lck_rw_done(&netagent_lock);
2559 }
2560 return error;
2561 }
2562
2563 int
netagent_client_message(uuid_t agent_uuid,uuid_t necp_client_uuid,pid_t pid,void * handle,u_int8_t message_type)2564 netagent_client_message(uuid_t agent_uuid, uuid_t necp_client_uuid, pid_t pid, void *handle, u_int8_t message_type)
2565 {
2566 return netagent_client_message_with_params(agent_uuid, necp_client_uuid, pid, handle, message_type, NULL, NULL, NULL);
2567 }
2568
2569 int
netagent_use(uuid_t agent_uuid,uint64_t * out_use_count)2570 netagent_use(uuid_t agent_uuid, uint64_t *out_use_count)
2571 {
2572 int error = 0;
2573
2574 lck_rw_lock_exclusive(&netagent_lock);
2575 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(agent_uuid);
2576 if (wrapper == NULL) {
2577 NETAGENTLOG0(LOG_ERR, "netagent_assert: Requested netagent UUID is not registered");
2578 error = ENOENT;
2579 goto done;
2580 }
2581
2582 uint64_t current_count = wrapper->use_count;
2583 wrapper->use_count++;
2584
2585 if (out_use_count != NULL) {
2586 *out_use_count = current_count;
2587 }
2588
2589 done:
2590 lck_rw_done(&netagent_lock);
2591 return error;
2592 }
2593
2594 int
netagent_copyout(uuid_t agent_uuid,user_addr_t user_addr,u_int32_t user_size)2595 netagent_copyout(uuid_t agent_uuid, user_addr_t user_addr, u_int32_t user_size)
2596 {
2597 int error = 0;
2598
2599 lck_rw_lock_shared(&netagent_lock);
2600 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(agent_uuid);
2601 if (wrapper == NULL) {
2602 NETAGENTLOG0(LOG_DEBUG, "Requested netagent for nexus instance could not be found");
2603 error = ENOENT;
2604 goto done;
2605 }
2606
2607 u_int32_t total_size = (sizeof(struct netagent) + wrapper->netagent->netagent_data_size);
2608 if (user_size < total_size) {
2609 NETAGENTLOG(LOG_ERR, "Provided user buffer is too small (%u < %u)", user_size, total_size);
2610 error = EINVAL;
2611 goto done;
2612 }
2613
2614 error = copyout(wrapper->netagent, user_addr, total_size);
2615
2616 NETAGENTLOG((error ? LOG_ERR : LOG_DEBUG), "Copied agent content (error %d)", error);
2617 done:
2618 lck_rw_done(&netagent_lock);
2619 return error;
2620 }
2621
2622 int
netagent_acquire_token(uuid_t agent_uuid,user_addr_t user_addr,u_int32_t user_size,int * retval)2623 netagent_acquire_token(uuid_t agent_uuid, user_addr_t user_addr, u_int32_t user_size, int *retval)
2624 {
2625 int error = 0;
2626
2627 lck_rw_lock_exclusive(&netagent_lock);
2628 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(agent_uuid);
2629 if (wrapper == NULL) {
2630 NETAGENTLOG0(LOG_DEBUG, "Network agent for request UUID could not be found");
2631 error = ENOENT;
2632 goto done;
2633 }
2634
2635 struct netagent_token *token = TAILQ_FIRST(&wrapper->token_list);
2636 if (token == NULL) {
2637 NETAGENTLOG0(LOG_DEBUG, "Network agent does not have any tokens");
2638 if (wrapper->token_low_water != 0) {
2639 (void)netagent_send_tokens_needed(wrapper);
2640 }
2641 error = ENODATA;
2642 goto done;
2643 }
2644
2645 if (user_size < token->token_length) {
2646 NETAGENTLOG(LOG_ERR, "Provided user buffer is too small (%u < %u)", user_size, token->token_length);
2647 error = EMSGSIZE;
2648 goto done;
2649 }
2650
2651 error = copyout(token->token_bytes, user_addr, token->token_length);
2652 if (error == 0) {
2653 *retval = (int)token->token_length;
2654 }
2655
2656 NETAGENTLOG((error ? LOG_ERR : LOG_DEBUG), "Copied token content (error %d)", error);
2657
2658 TAILQ_REMOVE(&wrapper->token_list, token, token_chain);
2659 netagent_token_free(token);
2660 if (wrapper->token_count > 0) {
2661 wrapper->token_count--;
2662 }
2663 if (wrapper->token_count < wrapper->token_low_water) {
2664 (void)netagent_send_tokens_needed(wrapper);
2665 }
2666 done:
2667 lck_rw_done(&netagent_lock);
2668 return error;
2669 }
2670
2671 int
netagent_trigger(struct proc * p,struct netagent_trigger_args * uap,int32_t * retval)2672 netagent_trigger(struct proc *p, struct netagent_trigger_args *uap, int32_t *retval)
2673 {
2674 #pragma unused(p, retval)
2675 uuid_t agent_uuid = {};
2676 int error = 0;
2677
2678 if (uap == NULL) {
2679 NETAGENTLOG0(LOG_ERR, "uap == NULL");
2680 return EINVAL;
2681 }
2682
2683 if (uap->agent_uuid) {
2684 if (uap->agent_uuidlen != sizeof(uuid_t)) {
2685 NETAGENTLOG(LOG_ERR, "Incorrect length (got %zu, expected %lu)",
2686 (size_t)uap->agent_uuidlen, sizeof(uuid_t));
2687 return ERANGE;
2688 }
2689
2690 error = copyin(uap->agent_uuid, agent_uuid, sizeof(uuid_t));
2691 if (error) {
2692 NETAGENTLOG(LOG_ERR, "copyin error (%d)", error);
2693 return error;
2694 }
2695 }
2696
2697 if (uuid_is_null(agent_uuid)) {
2698 NETAGENTLOG0(LOG_ERR, "Requested netagent UUID is empty");
2699 return EINVAL;
2700 }
2701
2702 lck_rw_lock_shared(&netagent_lock);
2703 struct netagent_wrapper *wrapper = netagent_find_agent_with_uuid(agent_uuid);
2704 if (wrapper == NULL) {
2705 NETAGENTLOG0(LOG_ERR, "Requested netagent UUID is not registered");
2706 error = ENOENT;
2707 goto done;
2708 }
2709
2710 if ((wrapper->netagent->netagent_flags & NETAGENT_FLAG_USER_ACTIVATED) == 0) {
2711 // Agent does not accept triggers
2712 NETAGENTLOG0(LOG_ERR, "Requested netagent UUID is not eligible for triggering");
2713 error = ENOTSUP;
2714 goto done;
2715 }
2716
2717 if ((wrapper->netagent->netagent_flags & NETAGENT_FLAG_ACTIVE)) {
2718 // Agent already active
2719 NETAGENTLOG0(LOG_INFO, "Requested netagent UUID is already active");
2720 error = 0;
2721 goto done;
2722 }
2723
2724 error = netagent_send_trigger(wrapper, p, NETAGENT_TRIGGER_FLAG_USER, NETAGENT_MESSAGE_TYPE_TRIGGER);
2725 NETAGENTLOG((error ? LOG_ERR : LOG_INFO), "Triggered netagent (error %d)", error);
2726 done:
2727 lck_rw_done(&netagent_lock);
2728 return error;
2729 }
2730