]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/task_ident.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / kern / task_ident.c
1 /*
2 * Copyright (c) 2020 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 #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>
37
38 struct proc_ident {
39 uint64_t p_uniqueid;
40 pid_t p_pid;
41 int p_idversion;
42 };
43
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);
49
50 struct task_id_token {
51 struct proc_ident ident;
52 ipc_port_t port;
53 os_refcnt_t tidt_refs;
54 };
55
56 static ZONE_DECLARE(task_id_token_zone, "task_id_token",
57 sizeof(struct task_id_token), ZC_ZFREE_CLEARMEM);
58
59 static void
60 tidt_reference(task_id_token_t token)
61 {
62 if (token == TASK_ID_TOKEN_NULL) {
63 return;
64 }
65 os_ref_retain(&token->tidt_refs);
66 }
67
68 static void
69 tidt_release(task_id_token_t token)
70 {
71 ipc_port_t port;
72
73 if (token == TASK_ID_TOKEN_NULL) {
74 return;
75 }
76
77 if (os_ref_release(&token->tidt_refs) > 0) {
78 return;
79 }
80
81 /* last ref */
82 port = token->port;
83
84 require_ip_active(port);
85 assert(!port->ip_srights);
86 ipc_port_dealloc_kernel(port);
87
88 zfree(task_id_token_zone, token);
89 }
90
91 void
92 task_id_token_release(task_id_token_t token)
93 {
94 tidt_release(token);
95 }
96
97 void
98 task_id_token_notify(mach_msg_header_t *msg)
99 {
100 assert(msg->msgh_id == MACH_NOTIFY_NO_SENDERS);
101
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);
105
106 require_ip_active(port);
107 assert(IKOT_TASK_ID_TOKEN == ip_kotype(port));
108 assert(port->ip_srights == 0);
109
110 tidt_release(token); /* consumes ref given by notification */
111 }
112
113 kern_return_t
114 task_create_identity_token(
115 task_t task,
116 task_id_token_t *tokenp)
117 {
118 task_id_token_t token;
119
120 if (task == TASK_NULL || task == kernel_task) {
121 return KERN_INVALID_ARGUMENT;
122 }
123
124 token = zalloc_flags(task_id_token_zone, Z_ZERO | Z_WAITOK | Z_NOFAIL);
125
126 task_lock(task);
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);
132 } else {
133 task_unlock(task);
134 zfree(task_id_token_zone, token);
135 return KERN_INVALID_ARGUMENT;
136 }
137 task_unlock(task);
138
139 *tokenp = token;
140
141 return KERN_SUCCESS;
142 }
143
144 kern_return_t
145 task_identity_token_get_task_port(
146 task_id_token_t token,
147 task_flavor_t flavor,
148 ipc_port_t *portp)
149 {
150 int which;
151 task_t task;
152 kern_return_t kr;
153
154 if (token == TASK_ID_TOKEN_NULL) {
155 return KERN_INVALID_ARGUMENT;
156 }
157
158 switch (flavor) {
159 case TASK_FLAVOR_NAME:
160 which = TASK_NAME_PORT;
161 break;
162 case TASK_FLAVOR_INSPECT:
163 which = TASK_INSPECT_PORT;
164 break;
165 case TASK_FLAVOR_READ:
166 which = TASK_READ_PORT;
167 break;
168 case TASK_FLAVOR_CONTROL:
169 which = TASK_KERNEL_PORT;
170 break;
171 default:
172 return KERN_INVALID_ARGUMENT;
173 }
174
175 void* p = proc_find_ident(&token->ident);
176 if (p == NULL) {
177 return KERN_INVALID_ARGUMENT;
178 }
179 task = proc_task(p);
180 task_reference(task);
181 proc_rele(p);
182
183 if (task == TASK_NULL) {
184 return KERN_INVALID_ARGUMENT;
185 }
186
187 if (flavor == TASK_FLAVOR_CONTROL && task == current_task()) {
188 *portp = convert_task_to_port_pinned(task); /* consumes task ref */
189 return KERN_SUCCESS;
190 }
191 if (flavor <= TASK_FLAVOR_INSPECT && task_conversion_eval(current_task(), task)) {
192 task_deallocate(task);
193 return KERN_INVALID_ARGUMENT;
194 }
195
196 #if CONFIG_MACF
197 if (task != current_task()) {
198 if (mac_task_check_task_id_token_get_task(task, flavor)) {
199 task_deallocate(task);
200 return KERN_DENIED;
201 }
202 }
203 #endif
204
205 kr = task_get_special_port(task, which, portp);
206 task_deallocate(task);
207 return kr;
208 }
209
210 /* Produces token ref */
211 task_id_token_t
212 convert_port_to_task_id_token(
213 ipc_port_t port)
214 {
215 task_id_token_t token = TASK_ID_TOKEN_NULL;
216
217 if (IP_VALID(port)) {
218 ip_lock(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);
222
223 zone_require(task_id_token_zone, token);
224 tidt_reference(token);
225 }
226 }
227 ip_unlock(port);
228 }
229 return token;
230 }
231
232 /* Consumes token ref */
233 ipc_port_t
234 convert_task_id_token_to_port(
235 task_id_token_t token)
236 {
237 boolean_t kr;
238
239 if (token == TASK_ID_TOKEN_NULL) {
240 return IP_NULL;
241 }
242
243 zone_require(task_id_token_zone, token);
244
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 */
248
249 return token->port;
250 }