2 * Copyright (c) 2019-2020 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 #include <sys/types.h>
31 #include <sys/malloc.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>
41 * Entitlement required for using the port of the test entry
43 #define ENTITLEMENT_TEST_PORT "com.apple.private.network.restricted.port.test"
46 * Entitlement required for setting the test sysctl variables
48 #define ENTITLEMENT_TEST_CONTROL "com.apple.private.network.restricted.port.control"
51 * Use a single bitmap for quickly checking if a TCP or UDP port is restricted
53 bitmap_t
*restricted_port_bitmap
= NULL
;
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
62 * Possible values for the field rpe_flags
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
70 static struct restricted_port_entry restricted_port_list
[] = {
71 #if !XNU_TARGET_OS_OSX
77 .rpe_flags
= RPE_FLAG_ENTITLEMENT
| RPE_FLAG_TCP
| RPE_FLAG_UDP
,
78 .rpe_entitlement
= "com.apple.private.network.restricted.port.nr_proxy",
82 * Network relay control
86 .rpe_flags
= RPE_FLAG_ENTITLEMENT
| RPE_FLAG_UDP
,
87 .rpe_entitlement
= "com.apple.private.network.restricted.port.nr_control",
91 * Entries for identityservicesd
95 .rpe_flags
= RPE_FLAG_ENTITLEMENT
| RPE_FLAG_TCP
| RPE_FLAG_UDP
,
96 .rpe_entitlement
= "com.apple.private.network.restricted.port.ids_service_connector",
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",
103 #endif /* !XNU_TARGET_OS_OSX */
110 .rpe_flags
= RPE_FLAG_ENTITLEMENT
| RPE_FLAG_TCP
,
111 .rpe_entitlement
= "com.apple.private.network.restricted.port.lights_out_management",
114 #if (DEBUG || DEVELOPMENT)
116 * Entries reserved for unit testing
120 .rpe_flags
= RPE_FLAG_TCP
| RPE_FLAG_TEST
,
121 .rpe_entitlement
= ENTITLEMENT_TEST_PORT
,
125 .rpe_flags
= RPE_FLAG_UDP
| RPE_FLAG_TEST
,
126 .rpe_entitlement
= ENTITLEMENT_TEST_PORT
,
128 #endif /* (DEBUG || DEVELOPMENT) */
131 * Sentinel to mark the actual end of the list (rpe_entitlement == NULL)
136 .rpe_entitlement
= NULL
,
140 #define RPE_ENTRY_COUNT (sizeof(restricted_port_list) / sizeof(restricted_port_list[0]))
142 SYSCTL_NODE(_net
, OID_AUTO
, restricted_port
,
143 CTLFLAG_RW
| CTLFLAG_LOCKED
, 0, "restricted port");
145 static int sysctl_restricted_port_bitmap SYSCTL_HANDLER_ARGS
;
146 static int sysctl_restricted_port_enforced SYSCTL_HANDLER_ARGS
;
147 static int sysctl_restricted_port_verbose SYSCTL_HANDLER_ARGS
;
149 SYSCTL_PROC(_net_restricted_port
, OID_AUTO
, bitmap
,
150 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_LOCKED
,
151 0, 0, &sysctl_restricted_port_bitmap
, "", "");
154 * In order to set the following sysctl variables the process needs to run as superuser
155 * or have the entitlement ENTITLEMENT_TEST_CONTROL
157 #if (DEBUG || DEVELOPMENT)
158 static int restricted_port_enforced
= 1;
159 SYSCTL_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) */
163 const int restricted_port_enforced
= 1;
164 SYSCTL_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) */
169 static int restricted_port_verbose
= 0;
170 SYSCTL_PROC(_net_restricted_port
, OID_AUTO
, verbose
,
171 CTLTYPE_INT
| CTLFLAG_LOCKED
| CTLFLAG_RW
| CTLFLAG_ANYBODY
,
172 0, 0, &sysctl_restricted_port_verbose
, "I", "");
174 #if (DEBUG || DEVELOPMENT)
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.
181 static uint16_t restricted_port_test
= 0;
183 static int sysctl_restricted_port_test_entitlement SYSCTL_HANDLER_ARGS
;
184 static int sysctl_restricted_port_test_superuser SYSCTL_HANDLER_ARGS
;
186 SYSCTL_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", "");
190 SYSCTL_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) */
196 sysctl_restricted_port_bitmap SYSCTL_HANDLER_ARGS
198 #pragma unused(oidp, arg1, arg2)
203 int error
= SYSCTL_OUT(req
, restricted_port_bitmap
, BITMAP_SIZE(UINT16_MAX
));
209 sysctl_restricted_port_enforced SYSCTL_HANDLER_ARGS
211 #pragma unused(arg1, arg2)
212 int old_value
= restricted_port_enforced
;
213 int value
= old_value
;
215 int error
= sysctl_handle_int(oidp
, &value
, 0, req
);
216 if (error
!= 0 || !req
->newptr
) {
219 #if (DEBUG || DEVELOPMENT)
220 if (proc_suser(current_proc()) != 0 &&
221 !IOTaskHasEntitlement(current_task(), ENTITLEMENT_TEST_CONTROL
)) {
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
);
232 #endif /* (DEBUG || DEVELOPMENT) */
236 sysctl_restricted_port_verbose SYSCTL_HANDLER_ARGS
238 #pragma unused(arg1, arg2)
239 int old_value
= restricted_port_verbose
;
240 int value
= old_value
;
242 int error
= sysctl_handle_int(oidp
, &value
, 0, req
);
243 if (error
!= 0 || !req
->newptr
) {
246 if (proc_suser(current_proc()) != 0 &&
247 !IOTaskHasEntitlement(current_task(), ENTITLEMENT_TEST_CONTROL
)) {
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
);
259 #if (DEBUG || DEVELOPMENT)
262 sysctl_restricted_port_test_common(struct sysctl_oid
*oidp
,
263 struct sysctl_req
*req
, bool test_superuser
)
265 uint16_t old_value
= restricted_port_test
;
266 int value
= old_value
;
269 int error
= sysctl_handle_int(oidp
, &value
, 0, req
);
270 if (error
!= 0 || !req
->newptr
) {
273 if (proc_suser(current_proc()) != 0 &&
274 !IOTaskHasEntitlement(current_task(), ENTITLEMENT_TEST_CONTROL
)) {
277 if (value
< 0 || value
> UINT16_MAX
) {
282 * Clear the current test port entries
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
];
288 if (rpe
->rpe_entitlement
== NULL
) {
291 if (!(rpe
->rpe_flags
& RPE_FLAG_TEST
)) {
295 rpe
->rpe_flags
&= ~(RPE_FLAG_ENTITLEMENT
| RPE_FLAG_SUPERUSER
);
297 bitmap_clear(restricted_port_bitmap
, restricted_port_test
);
298 restricted_port_test
= 0;
301 for (i
= 0; i
< RPE_ENTRY_COUNT
; i
++) {
302 struct restricted_port_entry
*rpe
= &restricted_port_list
[i
];
304 if (rpe
->rpe_entitlement
== NULL
) {
307 if (!(rpe
->rpe_flags
& RPE_FLAG_TEST
)) {
310 rpe
->rpe_port
= (in_port_t
)value
;
311 if (test_superuser
) {
312 rpe
->rpe_flags
|= RPE_FLAG_SUPERUSER
;
313 rpe
->rpe_flags
&= ~RPE_FLAG_ENTITLEMENT
;
315 rpe
->rpe_flags
|= RPE_FLAG_ENTITLEMENT
;
316 rpe
->rpe_flags
&= ~RPE_FLAG_SUPERUSER
;
319 restricted_port_test
= (uint16_t)value
;
320 bitmap_set(restricted_port_bitmap
, restricted_port_test
);
327 sysctl_restricted_port_test_entitlement SYSCTL_HANDLER_ARGS
329 #pragma unused(arg1, arg2)
330 uint16_t old_value
= restricted_port_test
;
333 error
= sysctl_restricted_port_test_common(oidp
, req
, false);
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
);
344 sysctl_restricted_port_test_superuser SYSCTL_HANDLER_ARGS
346 #pragma unused(arg1, arg2)
347 uint16_t old_value
= restricted_port_test
;
350 error
= sysctl_restricted_port_test_common(oidp
, req
, true);
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
);
360 #endif /* (DEBUG || DEVELOPMENT) */
363 restricted_in_port_init(void)
368 restricted_port_bitmap
= bitmap_alloc(UINT16_MAX
);
370 if (restricted_port_bitmap
== NULL
) {
371 panic("restricted_port_init: bitmap allocation failed");
374 for (i
= 0; i
< RPE_ENTRY_COUNT
; i
++) {
375 struct restricted_port_entry
*rpe
= &restricted_port_list
[i
];
377 if (rpe
->rpe_entitlement
== NULL
) {
380 if (rpe
->rpe_port
== 0) {
383 bitmap_set(restricted_port_bitmap
, rpe
->rpe_port
);
388 port_flag_str(uint32_t port_flags
)
390 switch (port_flags
) {
391 case PORT_FLAGS_LISTENER
:
404 * The port is passed in network byte order
407 current_task_can_use_restricted_in_port(in_port_t port
, uint8_t protocol
, uint32_t port_flags
)
410 struct proc
*p
= current_proc();
411 pid_t pid
= proc_pid(p
);
414 * Quick check that does not take in account the protocol
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
);
425 for (i
= 0; i
< RPE_ENTRY_COUNT
; i
++) {
426 struct restricted_port_entry
*rpe
= &restricted_port_list
[i
];
428 if (rpe
->rpe_entitlement
== NULL
) {
431 if (rpe
->rpe_port
== 0) {
434 if ((protocol
== IPPROTO_TCP
&& !(rpe
->rpe_flags
& RPE_FLAG_TCP
)) ||
435 (protocol
== IPPROTO_UDP
&& !(rpe
->rpe_flags
& RPE_FLAG_UDP
))) {
438 if (rpe
->rpe_port
!= ntohs(port
)) {
442 * Found an entry in the list of restricted ports
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
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
);
458 if (rpe
->rpe_flags
& RPE_FLAG_ENTITLEMENT
) {
460 * Do not let the kernel use the port because there is
461 * no entitlement for kernel extensions
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
));
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
);
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
);
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
);
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
);