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