2 * Copyright (c) 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@
29 #include <os/refcnt.h>
30 #include <kern/ipc_kobject.h>
31 #include <mach/mach_types.h>
32 #include <mach/task.h>
33 #include <mach/notify.h>
34 #include <mach/kern_return.h>
35 #include <security/mac_mach_internal.h>
36 #include <kern/task_ident.h>
44 extern void* proc_find_ident(struct proc_ident
const *i
);
45 extern int proc_rele(void* p
);
46 extern task_t
proc_task(void* p
);
47 extern struct proc_ident
proc_ident(void* p
);
48 extern kern_return_t
task_conversion_eval(task_t caller
, task_t victim
);
50 struct task_id_token
{
51 struct proc_ident ident
;
53 os_refcnt_t tidt_refs
;
56 static ZONE_DECLARE(task_id_token_zone
, "task_id_token",
57 sizeof(struct task_id_token
), ZC_ZFREE_CLEARMEM
);
60 tidt_reference(task_id_token_t token
)
62 if (token
== TASK_ID_TOKEN_NULL
) {
65 os_ref_retain(&token
->tidt_refs
);
69 tidt_release(task_id_token_t token
)
73 if (token
== TASK_ID_TOKEN_NULL
) {
77 if (os_ref_release(&token
->tidt_refs
) > 0) {
84 require_ip_active(port
);
85 assert(!port
->ip_srights
);
86 ipc_port_dealloc_kernel(port
);
88 zfree(task_id_token_zone
, token
);
92 task_id_token_release(task_id_token_t token
)
98 task_id_token_notify(mach_msg_header_t
*msg
)
100 assert(msg
->msgh_id
== MACH_NOTIFY_NO_SENDERS
);
102 mach_no_senders_notification_t
*not = (mach_no_senders_notification_t
*)msg
;
103 ipc_port_t port
= not->not_header
.msgh_remote_port
;
104 task_id_token_t token
= ip_get_kobject(port
);
106 require_ip_active(port
);
107 assert(IKOT_TASK_ID_TOKEN
== ip_kotype(port
));
108 assert(port
->ip_srights
== 0);
110 tidt_release(token
); /* consumes ref given by notification */
114 task_create_identity_token(
116 task_id_token_t
*tokenp
)
118 task_id_token_t token
;
120 if (task
== TASK_NULL
|| task
== kernel_task
) {
121 return KERN_INVALID_ARGUMENT
;
124 token
= zalloc_flags(task_id_token_zone
, Z_ZERO
| Z_WAITOK
| Z_NOFAIL
);
127 if (task
->bsd_info
) {
128 token
->port
= IP_NULL
;
129 token
->ident
= proc_ident(task
->bsd_info
);
130 /* this reference will be donated to no-senders notification */
131 os_ref_init_count(&token
->tidt_refs
, NULL
, 1);
134 zfree(task_id_token_zone
, token
);
135 return KERN_INVALID_ARGUMENT
;
145 task_identity_token_get_task_port(
146 task_id_token_t token
,
147 task_flavor_t flavor
,
154 if (token
== TASK_ID_TOKEN_NULL
) {
155 return KERN_INVALID_ARGUMENT
;
159 case TASK_FLAVOR_NAME
:
160 which
= TASK_NAME_PORT
;
162 case TASK_FLAVOR_INSPECT
:
163 which
= TASK_INSPECT_PORT
;
165 case TASK_FLAVOR_READ
:
166 which
= TASK_READ_PORT
;
168 case TASK_FLAVOR_CONTROL
:
169 which
= TASK_KERNEL_PORT
;
172 return KERN_INVALID_ARGUMENT
;
175 void* p
= proc_find_ident(&token
->ident
);
177 return KERN_INVALID_ARGUMENT
;
180 task_reference(task
);
183 if (task
== TASK_NULL
) {
184 return KERN_INVALID_ARGUMENT
;
187 if (flavor
== TASK_FLAVOR_CONTROL
&& task
== current_task()) {
188 *portp
= convert_task_to_port_pinned(task
); /* consumes task ref */
191 if (flavor
<= TASK_FLAVOR_INSPECT
&& task_conversion_eval(current_task(), task
)) {
192 task_deallocate(task
);
193 return KERN_INVALID_ARGUMENT
;
197 if (task
!= current_task()) {
198 if (mac_task_check_task_id_token_get_task(task
, flavor
)) {
199 task_deallocate(task
);
205 kr
= task_get_special_port(task
, which
, portp
);
206 task_deallocate(task
);
210 /* Produces token ref */
212 convert_port_to_task_id_token(
215 task_id_token_t token
= TASK_ID_TOKEN_NULL
;
217 if (IP_VALID(port
)) {
219 if (ip_active(port
)) {
220 if (ip_kotype(port
) == IKOT_TASK_ID_TOKEN
) {
221 token
= (task_id_token_t
)ip_get_kobject(port
);
223 zone_require(task_id_token_zone
, token
);
224 tidt_reference(token
);
232 /* Consumes token ref */
234 convert_task_id_token_to_port(
235 task_id_token_t token
)
239 if (token
== TASK_ID_TOKEN_NULL
) {
243 zone_require(task_id_token_zone
, token
);
245 kr
= ipc_kobject_make_send_lazy_alloc_port(&token
->port
,
246 (ipc_kobject_t
) token
, IKOT_TASK_ID_TOKEN
, IPC_KOBJECT_ALLOC_NONE
, false, 0);
247 assert(kr
== TRUE
); /* no-senders notification is armed, consumes token ref */