2 * Copyright (c) 2019 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
[] = {
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 /* CONFIG_EMBEDDED */
105 #if (DEBUG || DEVELOPMENT)
107 * Entries reserved for unit testing
111 .rpe_flags
= RPE_FLAG_TCP
| RPE_FLAG_TEST
,
112 .rpe_entitlement
= ENTITLEMENT_TEST_PORT
,
116 .rpe_flags
= RPE_FLAG_UDP
| RPE_FLAG_TEST
,
117 .rpe_entitlement
= ENTITLEMENT_TEST_PORT
,
119 #endif /* (DEBUG || DEVELOPMENT) */
122 * Sentinel to mark the actual end of the list (rpe_entitlement == NULL)
127 .rpe_entitlement
= NULL
,
131 #define RPE_ENTRY_COUNT (sizeof(restricted_port_list) / sizeof(restricted_port_list[0]))
133 SYSCTL_NODE(_net
, OID_AUTO
, restricted_port
,
134 CTLFLAG_RW
| CTLFLAG_LOCKED
, 0, "restricted port");
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
;
140 SYSCTL_PROC(_net_restricted_port
, OID_AUTO
, bitmap
,
141 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_LOCKED
,
142 0, 0, &sysctl_restricted_port_bitmap
, "", "");
145 * In order to set the following sysctl variables the process needs to run as superuser
146 * or have the entitlement ENTITLEMENT_TEST_CONTROL
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) */
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", "");
165 #if (DEBUG || DEVELOPMENT)
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.
172 static uint16_t restricted_port_test
= 0;
174 static int sysctl_restricted_port_test_entitlement SYSCTL_HANDLER_ARGS
;
175 static int sysctl_restricted_port_test_superuser SYSCTL_HANDLER_ARGS
;
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", "");
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) */
187 sysctl_restricted_port_bitmap SYSCTL_HANDLER_ARGS
189 #pragma unused(oidp, arg1, arg2)
194 int error
= SYSCTL_OUT(req
, restricted_port_bitmap
, BITMAP_SIZE(UINT16_MAX
));
200 sysctl_restricted_port_enforced SYSCTL_HANDLER_ARGS
202 #pragma unused(arg1, arg2)
203 int old_value
= restricted_port_enforced
;
204 int value
= old_value
;
206 int error
= sysctl_handle_int(oidp
, &value
, 0, req
);
207 if (error
!= 0 || !req
->newptr
) {
210 #if (DEBUG || DEVELOPMENT)
211 if (proc_suser(current_proc()) != 0 &&
212 !IOTaskHasEntitlement(current_task(), ENTITLEMENT_TEST_CONTROL
)) {
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
);
223 #endif /* (DEBUG || DEVELOPMENT) */
227 sysctl_restricted_port_verbose SYSCTL_HANDLER_ARGS
229 #pragma unused(arg1, arg2)
230 int old_value
= restricted_port_verbose
;
231 int value
= old_value
;
233 int error
= sysctl_handle_int(oidp
, &value
, 0, req
);
234 if (error
!= 0 || !req
->newptr
) {
237 if (proc_suser(current_proc()) != 0 &&
238 !IOTaskHasEntitlement(current_task(), ENTITLEMENT_TEST_CONTROL
)) {
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
);
250 #if (DEBUG || DEVELOPMENT)
253 sysctl_restricted_port_test_common(struct sysctl_oid
*oidp
,
254 struct sysctl_req
*req
, bool test_superuser
)
256 uint16_t old_value
= restricted_port_test
;
257 int value
= old_value
;
260 int error
= sysctl_handle_int(oidp
, &value
, 0, req
);
261 if (error
!= 0 || !req
->newptr
) {
264 if (proc_suser(current_proc()) != 0 &&
265 !IOTaskHasEntitlement(current_task(), ENTITLEMENT_TEST_CONTROL
)) {
268 if (value
< 0 || value
> UINT16_MAX
) {
273 * Clear the current test port entries
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
];
279 if (rpe
->rpe_entitlement
== NULL
) {
282 if (!(rpe
->rpe_flags
& RPE_FLAG_TEST
)) {
286 rpe
->rpe_flags
&= ~(RPE_FLAG_ENTITLEMENT
| RPE_FLAG_SUPERUSER
);
288 bitmap_clear(restricted_port_bitmap
, restricted_port_test
);
289 restricted_port_test
= 0;
292 for (i
= 0; i
< RPE_ENTRY_COUNT
; i
++) {
293 struct restricted_port_entry
*rpe
= &restricted_port_list
[i
];
295 if (rpe
->rpe_entitlement
== NULL
) {
298 if (!(rpe
->rpe_flags
& RPE_FLAG_TEST
)) {
301 rpe
->rpe_port
= value
;
302 if (test_superuser
) {
303 rpe
->rpe_flags
|= RPE_FLAG_SUPERUSER
;
304 rpe
->rpe_flags
&= ~RPE_FLAG_ENTITLEMENT
;
306 rpe
->rpe_flags
|= RPE_FLAG_ENTITLEMENT
;
307 rpe
->rpe_flags
&= ~RPE_FLAG_SUPERUSER
;
310 restricted_port_test
= (uint16_t)value
;
311 bitmap_set(restricted_port_bitmap
, restricted_port_test
);
318 sysctl_restricted_port_test_entitlement SYSCTL_HANDLER_ARGS
320 #pragma unused(arg1, arg2)
321 uint16_t old_value
= restricted_port_test
;
324 error
= sysctl_restricted_port_test_common(oidp
, req
, false);
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
);
335 sysctl_restricted_port_test_superuser SYSCTL_HANDLER_ARGS
337 #pragma unused(arg1, arg2)
338 uint16_t old_value
= restricted_port_test
;
341 error
= sysctl_restricted_port_test_common(oidp
, req
, true);
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
);
351 #endif /* (DEBUG || DEVELOPMENT) */
354 restricted_in_port_init(void)
359 restricted_port_bitmap
= bitmap_alloc(UINT16_MAX
);
361 if (restricted_port_bitmap
== NULL
) {
362 panic("restricted_port_init: bitmap allocation failed");
365 for (i
= 0; i
< RPE_ENTRY_COUNT
; i
++) {
366 struct restricted_port_entry
*rpe
= &restricted_port_list
[i
];
368 if (rpe
->rpe_entitlement
== NULL
) {
371 if (rpe
->rpe_port
== 0) {
374 bitmap_set(restricted_port_bitmap
, rpe
->rpe_port
);
379 port_flag_str(uint32_t port_flags
)
381 switch (port_flags
) {
382 case PORT_FLAGS_LISTENER
:
395 * The port is passed in network byte order
398 current_task_can_use_restricted_in_port(in_port_t port
, uint8_t protocol
, uint32_t port_flags
)
401 struct proc
*p
= current_proc();
402 pid_t pid
= proc_pid(p
);
405 * Quick check that does not take in account the protocol
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
);
416 for (i
= 0; i
< RPE_ENTRY_COUNT
; i
++) {
417 struct restricted_port_entry
*rpe
= &restricted_port_list
[i
];
419 if (rpe
->rpe_entitlement
== NULL
) {
422 if (rpe
->rpe_port
== 0) {
425 if ((protocol
== IPPROTO_TCP
&& !(rpe
->rpe_flags
& RPE_FLAG_TCP
)) ||
426 (protocol
== IPPROTO_UDP
&& !(rpe
->rpe_flags
& RPE_FLAG_UDP
))) {
429 if (rpe
->rpe_port
!= ntohs(port
)) {
433 * Found an entry in the list of restricted ports
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
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
);
449 if (rpe
->rpe_flags
& RPE_FLAG_ENTITLEMENT
) {
451 * Do not let the kernel use the port because there is
452 * no entitlement for kernel extensions
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
));
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
);
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
);
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
);
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
);