]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/restricted_in_port.c
xnu-6153.61.1.tar.gz
[apple/xnu.git] / bsd / net / restricted_in_port.c
1 /*
2 * Copyright (c) 2019 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
30 #include <sys/types.h>
31 #include <sys/malloc.h>
32 #include <sys/proc.h>
33 #include <sys/sysctl.h>
34 #include <kern/task.h>
35 #include <IOKit/IOBSD.h>
36 #include <net/restricted_in_port.h>
37 #include <netinet/in.h>
38 #include <os/log.h>
39
40 /*
41 * Entitlement required for using the port of the test entry
42 */
43 #define ENTITLEMENT_TEST_PORT "com.apple.private.network.restricted.port.test"
44
45 /*
46 * Entitlement required for setting the test sysctl variables
47 */
48 #define ENTITLEMENT_TEST_CONTROL "com.apple.private.network.restricted.port.control"
49
50 /*
51 * Use a single bitmap for quickly checking if a TCP or UDP port is restricted
52 */
53 bitmap_t *restricted_port_bitmap = NULL;
54
55 struct restricted_port_entry {
56 const char *rpe_entitlement; // entitlement to check for this port
57 in_port_t rpe_port; // restricted port number (host byte order)
58 uint16_t rpe_flags; // RPE_FLAG_xxx
59 };
60
61 /*
62 * Possible values for the field rpe_flags
63 */
64 #define RPE_FLAG_SUPERUSER 0x01 // superuser can use the port
65 #define RPE_FLAG_ENTITLEMENT 0x02 // can use the port with the required entitlement
66 #define RPE_FLAG_TCP 0x04 // require entitlement for TCP
67 #define RPE_FLAG_UDP 0x08 // require entitlement for TCP
68 #define RPE_FLAG_TEST 0x10 // entry for testing
69
70 static struct restricted_port_entry restricted_port_list[] = {
71 #if CONFIG_EMBEDDED
72 /*
73 * Network relay proxy
74 */
75 {
76 .rpe_port = 62742,
77 .rpe_flags = RPE_FLAG_ENTITLEMENT | RPE_FLAG_TCP | RPE_FLAG_UDP,
78 .rpe_entitlement = "com.apple.private.network.restricted.port.nr_proxy",
79 },
80
81 /*
82 * Network relay control
83 */
84 {
85 .rpe_port = 62743,
86 .rpe_flags = RPE_FLAG_ENTITLEMENT | RPE_FLAG_UDP,
87 .rpe_entitlement = "com.apple.private.network.restricted.port.nr_control",
88 },
89
90 /*
91 * Entries for identityservicesd
92 */
93 {
94 .rpe_port = 61314,
95 .rpe_flags = RPE_FLAG_ENTITLEMENT | RPE_FLAG_TCP | RPE_FLAG_UDP,
96 .rpe_entitlement = "com.apple.private.network.restricted.port.ids_service_connector",
97 },
98 {
99 .rpe_port = 61315,
100 .rpe_flags = RPE_FLAG_ENTITLEMENT | RPE_FLAG_TCP | RPE_FLAG_UDP,
101 .rpe_entitlement = "com.apple.private.network.restricted.port.ids_cloud_service_connector",
102 },
103 #endif /* CONFIG_EMBEDDED */
104
105 #if (DEBUG || DEVELOPMENT)
106 /*
107 * Entries reserved for unit testing
108 */
109 {
110 .rpe_port = 0,
111 .rpe_flags = RPE_FLAG_TCP | RPE_FLAG_TEST,
112 .rpe_entitlement = ENTITLEMENT_TEST_PORT,
113 },
114 {
115 .rpe_port = 0,
116 .rpe_flags = RPE_FLAG_UDP | RPE_FLAG_TEST,
117 .rpe_entitlement = ENTITLEMENT_TEST_PORT,
118 },
119 #endif /* (DEBUG || DEVELOPMENT) */
120
121 /*
122 * Sentinel to mark the actual end of the list (rpe_entitlement == NULL)
123 */
124 {
125 .rpe_port = 0,
126 .rpe_flags = 0,
127 .rpe_entitlement = NULL,
128 }
129 };
130
131 #define RPE_ENTRY_COUNT (sizeof(restricted_port_list) / sizeof(restricted_port_list[0]))
132
133 SYSCTL_NODE(_net, OID_AUTO, restricted_port,
134 CTLFLAG_RW | CTLFLAG_LOCKED, 0, "restricted port");
135
136 static int sysctl_restricted_port_bitmap SYSCTL_HANDLER_ARGS;
137 static int sysctl_restricted_port_enforced SYSCTL_HANDLER_ARGS;
138 static int sysctl_restricted_port_verbose SYSCTL_HANDLER_ARGS;
139
140 SYSCTL_PROC(_net_restricted_port, OID_AUTO, bitmap,
141 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED,
142 0, 0, &sysctl_restricted_port_bitmap, "", "");
143
144 /*
145 * In order to set the following sysctl variables the process needs to run as superuser
146 * or have the entitlement ENTITLEMENT_TEST_CONTROL
147 */
148 #if (DEBUG || DEVELOPMENT)
149 static int restricted_port_enforced = 1;
150 SYSCTL_PROC(_net_restricted_port, OID_AUTO, enforced,
151 CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW | CTLFLAG_ANYBODY,
152 0, 0, &sysctl_restricted_port_enforced, "I", "");
153 #else /* (DEBUG || DEVELOPMENT) */
154 const int restricted_port_enforced = 1;
155 SYSCTL_PROC(_net_restricted_port, OID_AUTO, enforced,
156 CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RD,
157 0, 0, &sysctl_restricted_port_enforced, "I", "");
158 #endif /* (DEBUG || DEVELOPMENT) */
159
160 static int restricted_port_verbose = 0;
161 SYSCTL_PROC(_net_restricted_port, OID_AUTO, verbose,
162 CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW | CTLFLAG_ANYBODY,
163 0, 0, &sysctl_restricted_port_verbose, "I", "");
164
165 #if (DEBUG || DEVELOPMENT)
166
167 /*
168 * Register dynamically a test port set by the unit test program to avoid conflict with
169 * a restricted port currently used by its legetimate process.
170 * The value must be passed is in host byte order.
171 */
172 static uint16_t restricted_port_test = 0;
173
174 static int sysctl_restricted_port_test_entitlement SYSCTL_HANDLER_ARGS;
175 static int sysctl_restricted_port_test_superuser SYSCTL_HANDLER_ARGS;
176
177 SYSCTL_PROC(_net_restricted_port, OID_AUTO, test_entitlement,
178 CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW | CTLFLAG_ANYBODY,
179 0, 0, &sysctl_restricted_port_test_entitlement, "UI", "");
180
181 SYSCTL_PROC(_net_restricted_port, OID_AUTO, test_superuser,
182 CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW | CTLFLAG_ANYBODY,
183 0, 0, &sysctl_restricted_port_test_superuser, "UI", "");
184 #endif /* (DEBUG || DEVELOPMENT) */
185
186 static int
187 sysctl_restricted_port_bitmap SYSCTL_HANDLER_ARGS
188 {
189 #pragma unused(oidp, arg1, arg2)
190
191 if (req->newptr) {
192 return EPERM;
193 }
194 int error = SYSCTL_OUT(req, restricted_port_bitmap, BITMAP_SIZE(UINT16_MAX));
195
196 return error;
197 }
198
199 static int
200 sysctl_restricted_port_enforced SYSCTL_HANDLER_ARGS
201 {
202 #pragma unused(arg1, arg2)
203 int old_value = restricted_port_enforced;
204 int value = old_value;
205
206 int error = sysctl_handle_int(oidp, &value, 0, req);
207 if (error != 0 || !req->newptr) {
208 return error;
209 }
210 #if (DEBUG || DEVELOPMENT)
211 if (proc_suser(current_proc()) != 0 &&
212 !IOTaskHasEntitlement(current_task(), ENTITLEMENT_TEST_CONTROL)) {
213 return EPERM;
214 }
215 restricted_port_enforced = value;
216 os_log(OS_LOG_DEFAULT,
217 "%s:%u sysctl net.restricted_port.enforced: %d -> %d",
218 proc_best_name(current_proc()), proc_selfpid(),
219 old_value, restricted_port_enforced);
220 return error;
221 #else
222 return EPERM;
223 #endif /* (DEBUG || DEVELOPMENT) */
224 }
225
226 static int
227 sysctl_restricted_port_verbose SYSCTL_HANDLER_ARGS
228 {
229 #pragma unused(arg1, arg2)
230 int old_value = restricted_port_verbose;
231 int value = old_value;
232
233 int error = sysctl_handle_int(oidp, &value, 0, req);
234 if (error != 0 || !req->newptr) {
235 return error;
236 }
237 if (proc_suser(current_proc()) != 0 &&
238 !IOTaskHasEntitlement(current_task(), ENTITLEMENT_TEST_CONTROL)) {
239 return EPERM;
240 }
241 restricted_port_verbose = value;
242 os_log(OS_LOG_DEFAULT,
243 "%s:%u sysctl net.restricted_port.verbose: %d -> %d)",
244 proc_best_name(current_proc()), proc_selfpid(),
245 old_value, restricted_port_verbose);
246
247 return error;
248 }
249
250 #if (DEBUG || DEVELOPMENT)
251
252 static int
253 sysctl_restricted_port_test_common(struct sysctl_oid *oidp,
254 struct sysctl_req *req, bool test_superuser)
255 {
256 uint16_t old_value = restricted_port_test;
257 int value = old_value;
258 unsigned int i;
259
260 int error = sysctl_handle_int(oidp, &value, 0, req);
261 if (error != 0 || !req->newptr) {
262 return error;
263 }
264 if (proc_suser(current_proc()) != 0 &&
265 !IOTaskHasEntitlement(current_task(), ENTITLEMENT_TEST_CONTROL)) {
266 return EPERM;
267 }
268 if (value < 0 || value > UINT16_MAX) {
269 return EINVAL;
270 }
271 if (value == 0) {
272 /*
273 * Clear the current test port entries
274 */
275 if (restricted_port_test != 0) {
276 for (i = 0; i < RPE_ENTRY_COUNT; i++) {
277 struct restricted_port_entry *rpe = &restricted_port_list[i];
278
279 if (rpe->rpe_entitlement == NULL) {
280 break;
281 }
282 if (!(rpe->rpe_flags & RPE_FLAG_TEST)) {
283 continue;
284 }
285 rpe->rpe_port = 0;
286 rpe->rpe_flags &= ~(RPE_FLAG_ENTITLEMENT | RPE_FLAG_SUPERUSER);
287 }
288 bitmap_clear(restricted_port_bitmap, restricted_port_test);
289 restricted_port_test = 0;
290 }
291 } else {
292 for (i = 0; i < RPE_ENTRY_COUNT; i++) {
293 struct restricted_port_entry *rpe = &restricted_port_list[i];
294
295 if (rpe->rpe_entitlement == NULL) {
296 break;
297 }
298 if (!(rpe->rpe_flags & RPE_FLAG_TEST)) {
299 continue;
300 }
301 rpe->rpe_port = value;
302 if (test_superuser) {
303 rpe->rpe_flags |= RPE_FLAG_SUPERUSER;
304 rpe->rpe_flags &= ~RPE_FLAG_ENTITLEMENT;
305 } else {
306 rpe->rpe_flags |= RPE_FLAG_ENTITLEMENT;
307 rpe->rpe_flags &= ~RPE_FLAG_SUPERUSER;
308 }
309 }
310 restricted_port_test = (uint16_t)value;
311 bitmap_set(restricted_port_bitmap, restricted_port_test);
312 }
313
314 return 0;
315 }
316
317 static int
318 sysctl_restricted_port_test_entitlement SYSCTL_HANDLER_ARGS
319 {
320 #pragma unused(arg1, arg2)
321 uint16_t old_value = restricted_port_test;
322 int error;
323
324 error = sysctl_restricted_port_test_common(oidp, req, false);
325 if (error == 0) {
326 os_log(OS_LOG_DEFAULT,
327 "%s:%u sysctl net.restricted_port.test_entitlement: %u -> %u)",
328 proc_best_name(current_proc()), proc_selfpid(),
329 old_value, restricted_port_test);
330 }
331 return error;
332 }
333
334 static int
335 sysctl_restricted_port_test_superuser SYSCTL_HANDLER_ARGS
336 {
337 #pragma unused(arg1, arg2)
338 uint16_t old_value = restricted_port_test;
339 int error;
340
341 error = sysctl_restricted_port_test_common(oidp, req, true);
342 if (error == 0) {
343 os_log(OS_LOG_DEFAULT,
344 "%s:%u sysctl net.restricted_port.test_superuser: %u -> %u)",
345 proc_best_name(current_proc()), proc_selfpid(),
346 old_value, restricted_port_test);
347 }
348 return error;
349 }
350
351 #endif /* (DEBUG || DEVELOPMENT) */
352
353 void
354 restricted_in_port_init(void)
355 {
356 unsigned int i;
357
358
359 restricted_port_bitmap = bitmap_alloc(UINT16_MAX);
360
361 if (restricted_port_bitmap == NULL) {
362 panic("restricted_port_init: bitmap allocation failed");
363 }
364
365 for (i = 0; i < RPE_ENTRY_COUNT; i++) {
366 struct restricted_port_entry *rpe = &restricted_port_list[i];
367
368 if (rpe->rpe_entitlement == NULL) {
369 break;
370 }
371 if (rpe->rpe_port == 0) {
372 continue;
373 }
374 bitmap_set(restricted_port_bitmap, rpe->rpe_port);
375 }
376 }
377
378 static const char *
379 port_flag_str(uint32_t port_flags)
380 {
381 switch (port_flags) {
382 case PORT_FLAGS_LISTENER:
383 return "listener";
384 case PORT_FLAGS_BSD:
385 return "bsd";
386 case PORT_FLAGS_PF:
387 return "pf";
388 default:
389 break;
390 }
391 return "?";
392 }
393
394 /*
395 * The port is passed in network byte order
396 */
397 bool
398 current_task_can_use_restricted_in_port(in_port_t port, uint8_t protocol, uint32_t port_flags)
399 {
400 unsigned int i;
401 struct proc *p = current_proc();
402 pid_t pid = proc_pid(p);
403
404 /*
405 * Quick check that does not take in account the protocol
406 */
407 if (!IS_RESTRICTED_IN_PORT(port) || restricted_port_enforced == 0) {
408 if (restricted_port_verbose > 1) {
409 os_log(OS_LOG_DEFAULT,
410 "port %u for protocol %u via %s can be used by process %s:%u",
411 ntohs(port), protocol, port_flag_str(port_flags), proc_best_name(p), pid);
412 }
413 return true;
414 }
415
416 for (i = 0; i < RPE_ENTRY_COUNT; i++) {
417 struct restricted_port_entry *rpe = &restricted_port_list[i];
418
419 if (rpe->rpe_entitlement == NULL) {
420 break;
421 }
422 if (rpe->rpe_port == 0) {
423 continue;
424 }
425 if ((protocol == IPPROTO_TCP && !(rpe->rpe_flags & RPE_FLAG_TCP)) ||
426 (protocol == IPPROTO_UDP && !(rpe->rpe_flags & RPE_FLAG_UDP))) {
427 continue;
428 }
429 if (rpe->rpe_port != ntohs(port)) {
430 continue;
431 }
432 /*
433 * Found an entry in the list of restricted ports
434 *
435 * A process can use a restricted port if it meets at least one of
436 * the following conditions:
437 * - The process has the required entitlement
438 * - The port is marked as usable by root
439 */
440 task_t task = current_task();
441 if (rpe->rpe_flags & RPE_FLAG_SUPERUSER) {
442 if (task == kernel_task || proc_suser(current_proc()) == 0) {
443 os_log(OS_LOG_DEFAULT,
444 "root restricted port %u for protocol %u via %s can be used by superuser process %s:%u",
445 ntohs(port), protocol, port_flag_str(port_flags), proc_best_name(p), pid);
446 return true;
447 }
448 }
449 if (rpe->rpe_flags & RPE_FLAG_ENTITLEMENT) {
450 /*
451 * Do not let the kernel use the port because there is
452 * no entitlement for kernel extensions
453 */
454 if (task == kernel_task) {
455 os_log(OS_LOG_DEFAULT,
456 "entitlement restricted port %u for protocol %u via %s cannot be used by kernel",
457 ntohs(port), protocol, port_flag_str(port_flags));
458 return false;
459 }
460 if (!IOTaskHasEntitlement(current_task(), rpe->rpe_entitlement)) {
461 os_log(OS_LOG_DEFAULT,
462 "entitlement restricted port %u for protocol %u via %s cannot be used by process %s:%u -- IOTaskHasEntitlement(%s) failed",
463 ntohs(port), protocol, port_flag_str(port_flags), proc_best_name(p), pid, rpe->rpe_entitlement);
464 return false;
465 }
466 os_log(OS_LOG_DEFAULT,
467 "entitlement restricted port %u for protocol %u via %s can be used by process %s:%u",
468 ntohs(port), protocol, port_flag_str(port_flags), proc_best_name(p), pid);
469 return true;
470 }
471 os_log(OS_LOG_DEFAULT,
472 "root restricted port %u for protocol %u via %s cannot be used by process %s:%u",
473 ntohs(port), protocol, port_flag_str(port_flags), proc_best_name(p), pid);
474 return false;
475 }
476 if (restricted_port_verbose > 1) {
477 os_log(OS_LOG_DEFAULT,
478 "port %u for protocol %u via %s can be used by process %s:%u",
479 ntohs(port), protocol, port_flag_str(port_flags), proc_best_name(p), pid);
480 }
481 return true;
482 }