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