1*1031c584SApple OSS Distributions #include <kern/kern_types.h>
2*1031c584SApple OSS Distributions #include <kern/thread_group.h>
3*1031c584SApple OSS Distributions #include <mach/mach_types.h>
4*1031c584SApple OSS Distributions #include <mach/boolean.h>
5*1031c584SApple OSS Distributions
6*1031c584SApple OSS Distributions #include <kern/coalition.h>
7*1031c584SApple OSS Distributions
8*1031c584SApple OSS Distributions #include <sys/coalition.h>
9*1031c584SApple OSS Distributions #include <sys/errno.h>
10*1031c584SApple OSS Distributions #include <sys/kauth.h>
11*1031c584SApple OSS Distributions #include <sys/kernel.h>
12*1031c584SApple OSS Distributions #include <sys/sysproto.h>
13*1031c584SApple OSS Distributions #include <sys/systm.h>
14*1031c584SApple OSS Distributions #include <sys/ubc.h> /* mach_to_bsd_errno */
15*1031c584SApple OSS Distributions
16*1031c584SApple OSS Distributions /* Coalitions syscalls */
17*1031c584SApple OSS Distributions
18*1031c584SApple OSS Distributions /*
19*1031c584SApple OSS Distributions * Create a new, empty coalition and return its ID.
20*1031c584SApple OSS Distributions *
21*1031c584SApple OSS Distributions * Returns:
22*1031c584SApple OSS Distributions * EINVAL Flags parameter was invalid
23*1031c584SApple OSS Distributions * ENOMEM Unable to allocate kernel resources for a new coalition
24*1031c584SApple OSS Distributions * EFAULT cidp parameter pointed to invalid memory.
25*1031c584SApple OSS Distributions *
26*1031c584SApple OSS Distributions * Returns with reference held for userspace caller.
27*1031c584SApple OSS Distributions */
28*1031c584SApple OSS Distributions static
29*1031c584SApple OSS Distributions int
coalition_create_syscall(user_addr_t cidp,uint32_t flags)30*1031c584SApple OSS Distributions coalition_create_syscall(user_addr_t cidp, uint32_t flags)
31*1031c584SApple OSS Distributions {
32*1031c584SApple OSS Distributions int error = 0;
33*1031c584SApple OSS Distributions kern_return_t kr;
34*1031c584SApple OSS Distributions uint64_t cid;
35*1031c584SApple OSS Distributions coalition_t coal;
36*1031c584SApple OSS Distributions int type = COALITION_CREATE_FLAGS_GET_TYPE(flags);
37*1031c584SApple OSS Distributions int role = COALITION_CREATE_FLAGS_GET_ROLE(flags);
38*1031c584SApple OSS Distributions boolean_t privileged = !!(flags & COALITION_CREATE_FLAGS_PRIVILEGED);
39*1031c584SApple OSS Distributions boolean_t efficient = !!(flags & COALITION_CREATE_FLAGS_EFFICIENT);
40*1031c584SApple OSS Distributions
41*1031c584SApple OSS Distributions if ((flags & (~COALITION_CREATE_FLAGS_MASK)) != 0) {
42*1031c584SApple OSS Distributions return EINVAL;
43*1031c584SApple OSS Distributions }
44*1031c584SApple OSS Distributions if (type < 0 || type > COALITION_TYPE_MAX) {
45*1031c584SApple OSS Distributions return EINVAL;
46*1031c584SApple OSS Distributions }
47*1031c584SApple OSS Distributions
48*1031c584SApple OSS Distributions kr = coalition_create_internal(type, role, privileged, efficient, &coal, &cid);
49*1031c584SApple OSS Distributions if (kr != KERN_SUCCESS) {
50*1031c584SApple OSS Distributions /* for now, the only kr is KERN_RESOURCE_SHORTAGE */
51*1031c584SApple OSS Distributions error = ENOMEM;
52*1031c584SApple OSS Distributions goto out;
53*1031c584SApple OSS Distributions }
54*1031c584SApple OSS Distributions
55*1031c584SApple OSS Distributions coal_dbg("(addr, %u) -> %llu", flags, cid);
56*1031c584SApple OSS Distributions error = copyout(&cid, cidp, sizeof(cid));
57*1031c584SApple OSS Distributions out:
58*1031c584SApple OSS Distributions return error;
59*1031c584SApple OSS Distributions }
60*1031c584SApple OSS Distributions
61*1031c584SApple OSS Distributions /*
62*1031c584SApple OSS Distributions * Request to terminate the coalition identified by ID.
63*1031c584SApple OSS Distributions * Attempts to spawn into this coalition using the posix_spawnattr will begin
64*1031c584SApple OSS Distributions * failing. Processes already within the coalition may still fork.
65*1031c584SApple OSS Distributions * Arms the 'coalition is empty' notification when the coalition's active
66*1031c584SApple OSS Distributions * count reaches zero.
67*1031c584SApple OSS Distributions *
68*1031c584SApple OSS Distributions * Returns:
69*1031c584SApple OSS Distributions * ESRCH No coalition with that ID could be found.
70*1031c584SApple OSS Distributions * EALREADY The coalition with that ID has already been terminated.
71*1031c584SApple OSS Distributions * EFAULT cidp parameter pointed to invalid memory.
72*1031c584SApple OSS Distributions * EPERM Caller doesn't have permission to terminate that coalition.
73*1031c584SApple OSS Distributions */
74*1031c584SApple OSS Distributions static
75*1031c584SApple OSS Distributions int
coalition_request_terminate_syscall(user_addr_t cidp,uint32_t flags)76*1031c584SApple OSS Distributions coalition_request_terminate_syscall(user_addr_t cidp, uint32_t flags)
77*1031c584SApple OSS Distributions {
78*1031c584SApple OSS Distributions kern_return_t kr;
79*1031c584SApple OSS Distributions int error = 0;
80*1031c584SApple OSS Distributions uint64_t cid;
81*1031c584SApple OSS Distributions coalition_t coal;
82*1031c584SApple OSS Distributions
83*1031c584SApple OSS Distributions if (flags != 0) {
84*1031c584SApple OSS Distributions return EINVAL;
85*1031c584SApple OSS Distributions }
86*1031c584SApple OSS Distributions
87*1031c584SApple OSS Distributions error = copyin(cidp, &cid, sizeof(cid));
88*1031c584SApple OSS Distributions if (error) {
89*1031c584SApple OSS Distributions return error;
90*1031c584SApple OSS Distributions }
91*1031c584SApple OSS Distributions
92*1031c584SApple OSS Distributions coal = coalition_find_by_id(cid);
93*1031c584SApple OSS Distributions if (coal == COALITION_NULL) {
94*1031c584SApple OSS Distributions return ESRCH;
95*1031c584SApple OSS Distributions }
96*1031c584SApple OSS Distributions
97*1031c584SApple OSS Distributions kr = coalition_request_terminate_internal(coal);
98*1031c584SApple OSS Distributions coalition_release(coal);
99*1031c584SApple OSS Distributions
100*1031c584SApple OSS Distributions switch (kr) {
101*1031c584SApple OSS Distributions case KERN_SUCCESS:
102*1031c584SApple OSS Distributions break;
103*1031c584SApple OSS Distributions case KERN_DEFAULT_SET:
104*1031c584SApple OSS Distributions error = EPERM;
105*1031c584SApple OSS Distributions break;
106*1031c584SApple OSS Distributions case KERN_TERMINATED:
107*1031c584SApple OSS Distributions error = EALREADY;
108*1031c584SApple OSS Distributions break;
109*1031c584SApple OSS Distributions case KERN_INVALID_NAME:
110*1031c584SApple OSS Distributions error = ESRCH;
111*1031c584SApple OSS Distributions break;
112*1031c584SApple OSS Distributions default:
113*1031c584SApple OSS Distributions error = EIO;
114*1031c584SApple OSS Distributions break;
115*1031c584SApple OSS Distributions }
116*1031c584SApple OSS Distributions
117*1031c584SApple OSS Distributions coal_dbg("(%llu, %u) -> %d", cid, flags, error);
118*1031c584SApple OSS Distributions
119*1031c584SApple OSS Distributions return error;
120*1031c584SApple OSS Distributions }
121*1031c584SApple OSS Distributions
122*1031c584SApple OSS Distributions /*
123*1031c584SApple OSS Distributions * Request the kernel to deallocate the coalition identified by ID, which
124*1031c584SApple OSS Distributions * must be both terminated and empty. This balances the reference taken
125*1031c584SApple OSS Distributions * in coalition_create.
126*1031c584SApple OSS Distributions * The memory containing the coalition object may not be freed just yet, if
127*1031c584SApple OSS Distributions * other kernel operations still hold references to it.
128*1031c584SApple OSS Distributions *
129*1031c584SApple OSS Distributions * Returns:
130*1031c584SApple OSS Distributions * EINVAL Flags parameter was invalid
131*1031c584SApple OSS Distributions * ESRCH Coalition ID refers to a coalition that doesn't exist.
132*1031c584SApple OSS Distributions * EBUSY Coalition has not yet been terminated.
133*1031c584SApple OSS Distributions * EBUSY Coalition is still active.
134*1031c584SApple OSS Distributions * EFAULT cidp parameter pointed to invalid memory.
135*1031c584SApple OSS Distributions * EPERM Caller doesn't have permission to terminate that coalition.
136*1031c584SApple OSS Distributions * Consumes one reference, "held" by caller since coalition_create
137*1031c584SApple OSS Distributions */
138*1031c584SApple OSS Distributions static
139*1031c584SApple OSS Distributions int
coalition_reap_syscall(user_addr_t cidp,uint32_t flags)140*1031c584SApple OSS Distributions coalition_reap_syscall(user_addr_t cidp, uint32_t flags)
141*1031c584SApple OSS Distributions {
142*1031c584SApple OSS Distributions kern_return_t kr;
143*1031c584SApple OSS Distributions int error = 0;
144*1031c584SApple OSS Distributions uint64_t cid;
145*1031c584SApple OSS Distributions coalition_t coal;
146*1031c584SApple OSS Distributions
147*1031c584SApple OSS Distributions if (flags != 0) {
148*1031c584SApple OSS Distributions return EINVAL;
149*1031c584SApple OSS Distributions }
150*1031c584SApple OSS Distributions
151*1031c584SApple OSS Distributions error = copyin(cidp, &cid, sizeof(cid));
152*1031c584SApple OSS Distributions if (error) {
153*1031c584SApple OSS Distributions return error;
154*1031c584SApple OSS Distributions }
155*1031c584SApple OSS Distributions
156*1031c584SApple OSS Distributions coal = coalition_find_by_id(cid);
157*1031c584SApple OSS Distributions if (coal == COALITION_NULL) {
158*1031c584SApple OSS Distributions return ESRCH;
159*1031c584SApple OSS Distributions }
160*1031c584SApple OSS Distributions
161*1031c584SApple OSS Distributions kr = coalition_reap_internal(coal);
162*1031c584SApple OSS Distributions coalition_release(coal);
163*1031c584SApple OSS Distributions
164*1031c584SApple OSS Distributions switch (kr) {
165*1031c584SApple OSS Distributions case KERN_SUCCESS:
166*1031c584SApple OSS Distributions break;
167*1031c584SApple OSS Distributions case KERN_DEFAULT_SET:
168*1031c584SApple OSS Distributions error = EPERM;
169*1031c584SApple OSS Distributions break;
170*1031c584SApple OSS Distributions case KERN_TERMINATED:
171*1031c584SApple OSS Distributions error = ESRCH;
172*1031c584SApple OSS Distributions break;
173*1031c584SApple OSS Distributions case KERN_FAILURE:
174*1031c584SApple OSS Distributions error = EBUSY;
175*1031c584SApple OSS Distributions break;
176*1031c584SApple OSS Distributions default:
177*1031c584SApple OSS Distributions error = EIO;
178*1031c584SApple OSS Distributions break;
179*1031c584SApple OSS Distributions }
180*1031c584SApple OSS Distributions
181*1031c584SApple OSS Distributions coal_dbg("(%llu, %u) -> %d", cid, flags, error);
182*1031c584SApple OSS Distributions
183*1031c584SApple OSS Distributions return error;
184*1031c584SApple OSS Distributions }
185*1031c584SApple OSS Distributions
186*1031c584SApple OSS Distributions /* Syscall demux.
187*1031c584SApple OSS Distributions * Returns EPERM if the calling process is not privileged to make this call.
188*1031c584SApple OSS Distributions */
189*1031c584SApple OSS Distributions int
coalition(proc_t p,struct coalition_args * cap,__unused int32_t * retval)190*1031c584SApple OSS Distributions coalition(proc_t p, struct coalition_args *cap, __unused int32_t *retval)
191*1031c584SApple OSS Distributions {
192*1031c584SApple OSS Distributions uint32_t operation = cap->operation;
193*1031c584SApple OSS Distributions user_addr_t cidp = cap->cid;
194*1031c584SApple OSS Distributions uint32_t flags = cap->flags;
195*1031c584SApple OSS Distributions int error = 0;
196*1031c584SApple OSS Distributions int type = COALITION_CREATE_FLAGS_GET_TYPE(flags);
197*1031c584SApple OSS Distributions
198*1031c584SApple OSS Distributions if (!task_is_in_privileged_coalition(proc_task(p), type)) {
199*1031c584SApple OSS Distributions return EPERM;
200*1031c584SApple OSS Distributions }
201*1031c584SApple OSS Distributions
202*1031c584SApple OSS Distributions switch (operation) {
203*1031c584SApple OSS Distributions case COALITION_OP_CREATE:
204*1031c584SApple OSS Distributions error = coalition_create_syscall(cidp, flags);
205*1031c584SApple OSS Distributions break;
206*1031c584SApple OSS Distributions case COALITION_OP_REAP:
207*1031c584SApple OSS Distributions error = coalition_reap_syscall(cidp, flags);
208*1031c584SApple OSS Distributions break;
209*1031c584SApple OSS Distributions case COALITION_OP_TERMINATE:
210*1031c584SApple OSS Distributions error = coalition_request_terminate_syscall(cidp, flags);
211*1031c584SApple OSS Distributions break;
212*1031c584SApple OSS Distributions default:
213*1031c584SApple OSS Distributions error = ENOSYS;
214*1031c584SApple OSS Distributions }
215*1031c584SApple OSS Distributions return error;
216*1031c584SApple OSS Distributions }
217*1031c584SApple OSS Distributions
218*1031c584SApple OSS Distributions /* This is a temporary interface, likely to be changed by 15385642. */
219*1031c584SApple OSS Distributions static int __attribute__ ((noinline))
coalition_info_resource_usage(coalition_t coal,user_addr_t buffer,user_size_t bufsize)220*1031c584SApple OSS Distributions coalition_info_resource_usage(coalition_t coal, user_addr_t buffer, user_size_t bufsize)
221*1031c584SApple OSS Distributions {
222*1031c584SApple OSS Distributions kern_return_t kr;
223*1031c584SApple OSS Distributions struct coalition_resource_usage cru = {};
224*1031c584SApple OSS Distributions
225*1031c584SApple OSS Distributions kr = coalition_resource_usage_internal(coal, &cru);
226*1031c584SApple OSS Distributions
227*1031c584SApple OSS Distributions switch (kr) {
228*1031c584SApple OSS Distributions case KERN_INVALID_ARGUMENT:
229*1031c584SApple OSS Distributions return EINVAL;
230*1031c584SApple OSS Distributions case KERN_RESOURCE_SHORTAGE:
231*1031c584SApple OSS Distributions return ENOMEM;
232*1031c584SApple OSS Distributions case KERN_SUCCESS:
233*1031c584SApple OSS Distributions break;
234*1031c584SApple OSS Distributions default:
235*1031c584SApple OSS Distributions return EIO; /* shrug */
236*1031c584SApple OSS Distributions }
237*1031c584SApple OSS Distributions
238*1031c584SApple OSS Distributions return copyout(&cru, buffer, MIN(bufsize, sizeof(cru)));
239*1031c584SApple OSS Distributions }
240*1031c584SApple OSS Distributions
241*1031c584SApple OSS Distributions #if DEVELOPMENT || DEBUG
242*1031c584SApple OSS Distributions static int __attribute__ ((noinline))
coalition_info_get_debug_info(coalition_t coal,user_addr_t buffer,user_size_t bufsize)243*1031c584SApple OSS Distributions coalition_info_get_debug_info(coalition_t coal, user_addr_t buffer, user_size_t bufsize)
244*1031c584SApple OSS Distributions {
245*1031c584SApple OSS Distributions kern_return_t kr;
246*1031c584SApple OSS Distributions struct coalinfo_debuginfo c_debuginfo = {};
247*1031c584SApple OSS Distributions
248*1031c584SApple OSS Distributions kr = coalition_debug_info_internal(coal, &c_debuginfo);
249*1031c584SApple OSS Distributions
250*1031c584SApple OSS Distributions if (kr != KERN_SUCCESS) {
251*1031c584SApple OSS Distributions return mach_to_bsd_errno(kr);
252*1031c584SApple OSS Distributions }
253*1031c584SApple OSS Distributions
254*1031c584SApple OSS Distributions return copyout(&c_debuginfo, buffer, MIN(bufsize, sizeof(c_debuginfo)));
255*1031c584SApple OSS Distributions }
256*1031c584SApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
257*1031c584SApple OSS Distributions
258*1031c584SApple OSS Distributions #if CONFIG_THREAD_GROUPS
259*1031c584SApple OSS Distributions static int
coalition_info_set_name_internal(coalition_t coal,user_addr_t buffer,user_size_t bufsize)260*1031c584SApple OSS Distributions coalition_info_set_name_internal(coalition_t coal, user_addr_t buffer, user_size_t bufsize)
261*1031c584SApple OSS Distributions {
262*1031c584SApple OSS Distributions int error;
263*1031c584SApple OSS Distributions char name[THREAD_GROUP_MAXNAME];
264*1031c584SApple OSS Distributions
265*1031c584SApple OSS Distributions if (coalition_type(coal) != COALITION_TYPE_JETSAM) {
266*1031c584SApple OSS Distributions return EINVAL;
267*1031c584SApple OSS Distributions }
268*1031c584SApple OSS Distributions bzero(name, sizeof(name));
269*1031c584SApple OSS Distributions error = copyin(buffer, name, MIN(bufsize, sizeof(name) - 1));
270*1031c584SApple OSS Distributions if (error) {
271*1031c584SApple OSS Distributions return error;
272*1031c584SApple OSS Distributions }
273*1031c584SApple OSS Distributions struct thread_group *tg = coalition_get_thread_group(coal);
274*1031c584SApple OSS Distributions thread_group_set_name(tg, name);
275*1031c584SApple OSS Distributions return error;
276*1031c584SApple OSS Distributions }
277*1031c584SApple OSS Distributions
278*1031c584SApple OSS Distributions #else /* CONFIG_THREAD_GROUPS */
279*1031c584SApple OSS Distributions #define coalition_info_set_name_internal(...) 0
280*1031c584SApple OSS Distributions #endif /* CONFIG_THREAD_GROUPS */
281*1031c584SApple OSS Distributions
282*1031c584SApple OSS Distributions static int
coalition_info_efficiency(coalition_t coal,user_addr_t buffer,user_size_t bufsize)283*1031c584SApple OSS Distributions coalition_info_efficiency(coalition_t coal, user_addr_t buffer, user_size_t bufsize)
284*1031c584SApple OSS Distributions {
285*1031c584SApple OSS Distributions int error = 0;
286*1031c584SApple OSS Distributions if (coalition_type(coal) != COALITION_TYPE_JETSAM) {
287*1031c584SApple OSS Distributions return EINVAL;
288*1031c584SApple OSS Distributions }
289*1031c584SApple OSS Distributions uint64_t flags = 0;
290*1031c584SApple OSS Distributions error = copyin(buffer, &flags, MIN(bufsize, sizeof(flags)));
291*1031c584SApple OSS Distributions if (error) {
292*1031c584SApple OSS Distributions return error;
293*1031c584SApple OSS Distributions }
294*1031c584SApple OSS Distributions if ((flags & COALITION_EFFICIENCY_VALID_FLAGS) == 0) {
295*1031c584SApple OSS Distributions return EINVAL;
296*1031c584SApple OSS Distributions }
297*1031c584SApple OSS Distributions if (flags & COALITION_FLAGS_EFFICIENT) {
298*1031c584SApple OSS Distributions // No longer supported; this flag must be set during create.
299*1031c584SApple OSS Distributions return ENOTSUP;
300*1031c584SApple OSS Distributions }
301*1031c584SApple OSS Distributions return error;
302*1031c584SApple OSS Distributions }
303*1031c584SApple OSS Distributions
304*1031c584SApple OSS Distributions static int
coalition_ledger_logical_writes_limit(coalition_t coal,user_addr_t buffer,user_size_t bufsize)305*1031c584SApple OSS Distributions coalition_ledger_logical_writes_limit(coalition_t coal, user_addr_t buffer, user_size_t bufsize)
306*1031c584SApple OSS Distributions {
307*1031c584SApple OSS Distributions int error = 0;
308*1031c584SApple OSS Distributions int64_t limit = 0;
309*1031c584SApple OSS Distributions
310*1031c584SApple OSS Distributions if (coalition_type(coal) != COALITION_TYPE_RESOURCE) {
311*1031c584SApple OSS Distributions error = EINVAL;
312*1031c584SApple OSS Distributions goto out;
313*1031c584SApple OSS Distributions }
314*1031c584SApple OSS Distributions error = copyin(buffer, &limit, MIN(bufsize, sizeof(limit)));
315*1031c584SApple OSS Distributions if (error) {
316*1031c584SApple OSS Distributions goto out;
317*1031c584SApple OSS Distributions }
318*1031c584SApple OSS Distributions
319*1031c584SApple OSS Distributions
320*1031c584SApple OSS Distributions error = coalition_ledger_set_logical_writes_limit(coal, limit);
321*1031c584SApple OSS Distributions out:
322*1031c584SApple OSS Distributions return error;
323*1031c584SApple OSS Distributions }
324*1031c584SApple OSS Distributions
325*1031c584SApple OSS Distributions int
coalition_info(proc_t p,struct coalition_info_args * uap,__unused int32_t * retval)326*1031c584SApple OSS Distributions coalition_info(proc_t p, struct coalition_info_args *uap, __unused int32_t *retval)
327*1031c584SApple OSS Distributions {
328*1031c584SApple OSS Distributions user_addr_t cidp = uap->cid;
329*1031c584SApple OSS Distributions user_addr_t buffer = uap->buffer;
330*1031c584SApple OSS Distributions user_addr_t bufsizep = uap->bufsize;
331*1031c584SApple OSS Distributions user_size_t bufsize;
332*1031c584SApple OSS Distributions uint32_t flavor = uap->flavor;
333*1031c584SApple OSS Distributions int error;
334*1031c584SApple OSS Distributions uint64_t cid;
335*1031c584SApple OSS Distributions coalition_t coal;
336*1031c584SApple OSS Distributions
337*1031c584SApple OSS Distributions error = copyin(cidp, &cid, sizeof(cid));
338*1031c584SApple OSS Distributions if (error) {
339*1031c584SApple OSS Distributions return error;
340*1031c584SApple OSS Distributions }
341*1031c584SApple OSS Distributions
342*1031c584SApple OSS Distributions coal = coalition_find_by_id(cid);
343*1031c584SApple OSS Distributions if (coal == COALITION_NULL) {
344*1031c584SApple OSS Distributions return ESRCH;
345*1031c584SApple OSS Distributions }
346*1031c584SApple OSS Distributions /* TODO: priv check? EPERM or ESRCH? */
347*1031c584SApple OSS Distributions
348*1031c584SApple OSS Distributions if (IS_64BIT_PROCESS(p)) {
349*1031c584SApple OSS Distributions user64_size_t size64;
350*1031c584SApple OSS Distributions error = copyin(bufsizep, &size64, sizeof(size64));
351*1031c584SApple OSS Distributions bufsize = (user_size_t)size64;
352*1031c584SApple OSS Distributions } else {
353*1031c584SApple OSS Distributions user32_size_t size32;
354*1031c584SApple OSS Distributions error = copyin(bufsizep, &size32, sizeof(size32));
355*1031c584SApple OSS Distributions bufsize = (user_size_t)size32;
356*1031c584SApple OSS Distributions }
357*1031c584SApple OSS Distributions if (error) {
358*1031c584SApple OSS Distributions goto bad;
359*1031c584SApple OSS Distributions }
360*1031c584SApple OSS Distributions
361*1031c584SApple OSS Distributions switch (flavor) {
362*1031c584SApple OSS Distributions case COALITION_INFO_RESOURCE_USAGE:
363*1031c584SApple OSS Distributions error = coalition_info_resource_usage(coal, buffer, bufsize);
364*1031c584SApple OSS Distributions break;
365*1031c584SApple OSS Distributions case COALITION_INFO_SET_NAME:
366*1031c584SApple OSS Distributions error = coalition_info_set_name_internal(coal, buffer, bufsize);
367*1031c584SApple OSS Distributions break;
368*1031c584SApple OSS Distributions case COALITION_INFO_SET_EFFICIENCY:
369*1031c584SApple OSS Distributions error = coalition_info_efficiency(coal, buffer, bufsize);
370*1031c584SApple OSS Distributions break;
371*1031c584SApple OSS Distributions #if DEVELOPMENT || DEBUG
372*1031c584SApple OSS Distributions case COALITION_INFO_GET_DEBUG_INFO:
373*1031c584SApple OSS Distributions error = coalition_info_get_debug_info(coal, buffer, bufsize);
374*1031c584SApple OSS Distributions break;
375*1031c584SApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
376*1031c584SApple OSS Distributions default:
377*1031c584SApple OSS Distributions error = EINVAL;
378*1031c584SApple OSS Distributions }
379*1031c584SApple OSS Distributions
380*1031c584SApple OSS Distributions bad:
381*1031c584SApple OSS Distributions coalition_release(coal);
382*1031c584SApple OSS Distributions return error;
383*1031c584SApple OSS Distributions }
384*1031c584SApple OSS Distributions
385*1031c584SApple OSS Distributions int
coalition_ledger(__unused proc_t p,__unused struct coalition_ledger_args * uap,__unused int32_t * retval)386*1031c584SApple OSS Distributions coalition_ledger(__unused proc_t p, __unused struct coalition_ledger_args *uap, __unused int32_t *retval)
387*1031c584SApple OSS Distributions {
388*1031c584SApple OSS Distributions user_addr_t cidp = uap->cid;
389*1031c584SApple OSS Distributions user_addr_t buffer = uap->buffer;
390*1031c584SApple OSS Distributions user_addr_t bufsizep = uap->bufsize;
391*1031c584SApple OSS Distributions user_size_t bufsize;
392*1031c584SApple OSS Distributions uint32_t operation = uap->operation;
393*1031c584SApple OSS Distributions int error;
394*1031c584SApple OSS Distributions uint64_t cid;
395*1031c584SApple OSS Distributions coalition_t coal = COALITION_NULL;
396*1031c584SApple OSS Distributions
397*1031c584SApple OSS Distributions if (!kauth_cred_issuser(kauth_cred_get())) {
398*1031c584SApple OSS Distributions error = EPERM;
399*1031c584SApple OSS Distributions goto out;
400*1031c584SApple OSS Distributions }
401*1031c584SApple OSS Distributions
402*1031c584SApple OSS Distributions error = copyin(cidp, &cid, sizeof(cid));
403*1031c584SApple OSS Distributions if (error) {
404*1031c584SApple OSS Distributions goto out;
405*1031c584SApple OSS Distributions }
406*1031c584SApple OSS Distributions
407*1031c584SApple OSS Distributions coal = coalition_find_by_id(cid);
408*1031c584SApple OSS Distributions if (coal == COALITION_NULL) {
409*1031c584SApple OSS Distributions error = ESRCH;
410*1031c584SApple OSS Distributions goto out;
411*1031c584SApple OSS Distributions }
412*1031c584SApple OSS Distributions
413*1031c584SApple OSS Distributions if (IS_64BIT_PROCESS(p)) {
414*1031c584SApple OSS Distributions user64_size_t size64;
415*1031c584SApple OSS Distributions error = copyin(bufsizep, &size64, sizeof(size64));
416*1031c584SApple OSS Distributions bufsize = (user_size_t)size64;
417*1031c584SApple OSS Distributions } else {
418*1031c584SApple OSS Distributions user32_size_t size32;
419*1031c584SApple OSS Distributions error = copyin(bufsizep, &size32, sizeof(size32));
420*1031c584SApple OSS Distributions bufsize = (user_size_t)size32;
421*1031c584SApple OSS Distributions }
422*1031c584SApple OSS Distributions if (error) {
423*1031c584SApple OSS Distributions goto out;
424*1031c584SApple OSS Distributions }
425*1031c584SApple OSS Distributions
426*1031c584SApple OSS Distributions switch (operation) {
427*1031c584SApple OSS Distributions case COALITION_LEDGER_SET_LOGICAL_WRITES_LIMIT:
428*1031c584SApple OSS Distributions error = coalition_ledger_logical_writes_limit(coal, buffer, bufsize);
429*1031c584SApple OSS Distributions break;
430*1031c584SApple OSS Distributions default:
431*1031c584SApple OSS Distributions error = EINVAL;
432*1031c584SApple OSS Distributions }
433*1031c584SApple OSS Distributions out:
434*1031c584SApple OSS Distributions if (coal != COALITION_NULL) {
435*1031c584SApple OSS Distributions coalition_release(coal);
436*1031c584SApple OSS Distributions }
437*1031c584SApple OSS Distributions return error;
438*1031c584SApple OSS Distributions }
439*1031c584SApple OSS Distributions #if DEVELOPMENT || DEBUG
440*1031c584SApple OSS Distributions static int sysctl_coalition_get_ids SYSCTL_HANDLER_ARGS
441*1031c584SApple OSS Distributions {
442*1031c584SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
443*1031c584SApple OSS Distributions int error, pid;
444*1031c584SApple OSS Distributions proc_t tproc;
445*1031c584SApple OSS Distributions uint64_t value;
446*1031c584SApple OSS Distributions uint64_t ids[COALITION_NUM_TYPES] = {};
447*1031c584SApple OSS Distributions
448*1031c584SApple OSS Distributions
449*1031c584SApple OSS Distributions error = SYSCTL_IN(req, &value, sizeof(value));
450*1031c584SApple OSS Distributions if (error) {
451*1031c584SApple OSS Distributions return error;
452*1031c584SApple OSS Distributions }
453*1031c584SApple OSS Distributions if (!req->newptr) {
454*1031c584SApple OSS Distributions pid = proc_getpid(req->p);
455*1031c584SApple OSS Distributions } else {
456*1031c584SApple OSS Distributions pid = (int)value;
457*1031c584SApple OSS Distributions }
458*1031c584SApple OSS Distributions
459*1031c584SApple OSS Distributions coal_dbg("looking up coalitions for pid:%d", pid);
460*1031c584SApple OSS Distributions tproc = proc_find(pid);
461*1031c584SApple OSS Distributions if (tproc == NULL) {
462*1031c584SApple OSS Distributions coal_dbg("ERROR: Couldn't find pid:%d", pid);
463*1031c584SApple OSS Distributions return ESRCH;
464*1031c584SApple OSS Distributions }
465*1031c584SApple OSS Distributions
466*1031c584SApple OSS Distributions task_coalition_ids(proc_task(tproc), ids);
467*1031c584SApple OSS Distributions proc_rele(tproc);
468*1031c584SApple OSS Distributions
469*1031c584SApple OSS Distributions return SYSCTL_OUT(req, ids, sizeof(ids));
470*1031c584SApple OSS Distributions }
471*1031c584SApple OSS Distributions
472*1031c584SApple OSS Distributions SYSCTL_PROC(_kern, OID_AUTO, coalitions, CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED,
473*1031c584SApple OSS Distributions 0, 0, sysctl_coalition_get_ids, "Q", "coalition ids of a given process");
474*1031c584SApple OSS Distributions
475*1031c584SApple OSS Distributions
476*1031c584SApple OSS Distributions static int sysctl_coalition_get_roles SYSCTL_HANDLER_ARGS
477*1031c584SApple OSS Distributions {
478*1031c584SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
479*1031c584SApple OSS Distributions int error, pid;
480*1031c584SApple OSS Distributions proc_t tproc;
481*1031c584SApple OSS Distributions int value;
482*1031c584SApple OSS Distributions int roles[COALITION_NUM_TYPES] = {};
483*1031c584SApple OSS Distributions
484*1031c584SApple OSS Distributions
485*1031c584SApple OSS Distributions error = SYSCTL_IN(req, &value, sizeof(value));
486*1031c584SApple OSS Distributions if (error) {
487*1031c584SApple OSS Distributions return error;
488*1031c584SApple OSS Distributions }
489*1031c584SApple OSS Distributions if (!req->newptr) {
490*1031c584SApple OSS Distributions pid = proc_getpid(req->p);
491*1031c584SApple OSS Distributions } else {
492*1031c584SApple OSS Distributions pid = (int)value;
493*1031c584SApple OSS Distributions }
494*1031c584SApple OSS Distributions
495*1031c584SApple OSS Distributions coal_dbg("looking up coalitions for pid:%d", pid);
496*1031c584SApple OSS Distributions tproc = proc_find(pid);
497*1031c584SApple OSS Distributions if (tproc == NULL) {
498*1031c584SApple OSS Distributions coal_dbg("ERROR: Couldn't find pid:%d", pid);
499*1031c584SApple OSS Distributions return ESRCH;
500*1031c584SApple OSS Distributions }
501*1031c584SApple OSS Distributions
502*1031c584SApple OSS Distributions task_coalition_roles(proc_task(tproc), roles);
503*1031c584SApple OSS Distributions proc_rele(tproc);
504*1031c584SApple OSS Distributions
505*1031c584SApple OSS Distributions return SYSCTL_OUT(req, roles, sizeof(roles));
506*1031c584SApple OSS Distributions }
507*1031c584SApple OSS Distributions
508*1031c584SApple OSS Distributions SYSCTL_PROC(_kern, OID_AUTO, coalition_roles, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
509*1031c584SApple OSS Distributions 0, 0, sysctl_coalition_get_roles, "I", "coalition roles of a given process");
510*1031c584SApple OSS Distributions
511*1031c584SApple OSS Distributions
512*1031c584SApple OSS Distributions static int sysctl_coalition_get_page_count SYSCTL_HANDLER_ARGS
513*1031c584SApple OSS Distributions {
514*1031c584SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
515*1031c584SApple OSS Distributions int error, pid;
516*1031c584SApple OSS Distributions proc_t tproc;
517*1031c584SApple OSS Distributions coalition_t coal;
518*1031c584SApple OSS Distributions uint64_t value;
519*1031c584SApple OSS Distributions uint64_t pgcount[COALITION_NUM_TYPES];
520*1031c584SApple OSS Distributions
521*1031c584SApple OSS Distributions
522*1031c584SApple OSS Distributions error = SYSCTL_IN(req, &value, sizeof(value));
523*1031c584SApple OSS Distributions if (error) {
524*1031c584SApple OSS Distributions return error;
525*1031c584SApple OSS Distributions }
526*1031c584SApple OSS Distributions if (!req->newptr) {
527*1031c584SApple OSS Distributions pid = proc_getpid(req->p);
528*1031c584SApple OSS Distributions } else {
529*1031c584SApple OSS Distributions pid = (int)value;
530*1031c584SApple OSS Distributions }
531*1031c584SApple OSS Distributions
532*1031c584SApple OSS Distributions coal_dbg("looking up coalitions for pid:%d", pid);
533*1031c584SApple OSS Distributions tproc = proc_find(pid);
534*1031c584SApple OSS Distributions if (tproc == NULL) {
535*1031c584SApple OSS Distributions coal_dbg("ERROR: Couldn't find pid:%d", pid);
536*1031c584SApple OSS Distributions return ESRCH;
537*1031c584SApple OSS Distributions }
538*1031c584SApple OSS Distributions
539*1031c584SApple OSS Distributions memset(pgcount, 0, sizeof(pgcount));
540*1031c584SApple OSS Distributions
541*1031c584SApple OSS Distributions for (int t = 0; t < COALITION_NUM_TYPES; t++) {
542*1031c584SApple OSS Distributions coal = task_get_coalition(proc_task(tproc), t);
543*1031c584SApple OSS Distributions if (coal != COALITION_NULL) {
544*1031c584SApple OSS Distributions int ntasks = 0;
545*1031c584SApple OSS Distributions pgcount[t] = coalition_get_page_count(coal, &ntasks);
546*1031c584SApple OSS Distributions coal_dbg("PID:%d, Coalition:%lld, type:%d, pgcount:%lld",
547*1031c584SApple OSS Distributions pid, coalition_id(coal), t, pgcount[t]);
548*1031c584SApple OSS Distributions }
549*1031c584SApple OSS Distributions }
550*1031c584SApple OSS Distributions
551*1031c584SApple OSS Distributions proc_rele(tproc);
552*1031c584SApple OSS Distributions
553*1031c584SApple OSS Distributions return SYSCTL_OUT(req, pgcount, sizeof(pgcount));
554*1031c584SApple OSS Distributions }
555*1031c584SApple OSS Distributions
556*1031c584SApple OSS Distributions SYSCTL_PROC(_kern, OID_AUTO, coalition_page_count, CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED,
557*1031c584SApple OSS Distributions 0, 0, sysctl_coalition_get_page_count, "Q", "coalition page count of a specified process");
558*1031c584SApple OSS Distributions
559*1031c584SApple OSS Distributions
560*1031c584SApple OSS Distributions static int sysctl_coalition_get_pid_list SYSCTL_HANDLER_ARGS
561*1031c584SApple OSS Distributions {
562*1031c584SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
563*1031c584SApple OSS Distributions int error, type, sort_order, pid;
564*1031c584SApple OSS Distributions int value[3];
565*1031c584SApple OSS Distributions int has_pid = 1;
566*1031c584SApple OSS Distributions
567*1031c584SApple OSS Distributions coalition_t coal = COALITION_NULL;
568*1031c584SApple OSS Distributions proc_t tproc = PROC_NULL;
569*1031c584SApple OSS Distributions int npids = 0;
570*1031c584SApple OSS Distributions int pidlist[100] = { 0, };
571*1031c584SApple OSS Distributions
572*1031c584SApple OSS Distributions
573*1031c584SApple OSS Distributions error = SYSCTL_IN(req, &value, sizeof(value));
574*1031c584SApple OSS Distributions if (error) {
575*1031c584SApple OSS Distributions has_pid = 0;
576*1031c584SApple OSS Distributions error = SYSCTL_IN(req, &value, sizeof(value) - sizeof(value[0]));
577*1031c584SApple OSS Distributions }
578*1031c584SApple OSS Distributions if (error) {
579*1031c584SApple OSS Distributions return error;
580*1031c584SApple OSS Distributions }
581*1031c584SApple OSS Distributions if (!req->newptr) {
582*1031c584SApple OSS Distributions type = COALITION_TYPE_RESOURCE;
583*1031c584SApple OSS Distributions sort_order = COALITION_SORT_DEFAULT;
584*1031c584SApple OSS Distributions pid = proc_getpid(req->p);
585*1031c584SApple OSS Distributions } else {
586*1031c584SApple OSS Distributions type = value[0];
587*1031c584SApple OSS Distributions sort_order = value[1];
588*1031c584SApple OSS Distributions if (has_pid) {
589*1031c584SApple OSS Distributions pid = value[2];
590*1031c584SApple OSS Distributions } else {
591*1031c584SApple OSS Distributions pid = proc_getpid(req->p);
592*1031c584SApple OSS Distributions }
593*1031c584SApple OSS Distributions }
594*1031c584SApple OSS Distributions
595*1031c584SApple OSS Distributions if (type < 0 || type >= COALITION_NUM_TYPES) {
596*1031c584SApple OSS Distributions return EINVAL;
597*1031c584SApple OSS Distributions }
598*1031c584SApple OSS Distributions
599*1031c584SApple OSS Distributions coal_dbg("getting constituent PIDS for coalition of type %d "
600*1031c584SApple OSS Distributions "containing pid:%d (sort:%d)", type, pid, sort_order);
601*1031c584SApple OSS Distributions tproc = proc_find(pid);
602*1031c584SApple OSS Distributions if (tproc == NULL) {
603*1031c584SApple OSS Distributions coal_dbg("ERROR: Couldn't find pid:%d", pid);
604*1031c584SApple OSS Distributions return ESRCH;
605*1031c584SApple OSS Distributions }
606*1031c584SApple OSS Distributions
607*1031c584SApple OSS Distributions coal = task_get_coalition(proc_task(tproc), type);
608*1031c584SApple OSS Distributions if (coal == COALITION_NULL) {
609*1031c584SApple OSS Distributions goto out;
610*1031c584SApple OSS Distributions }
611*1031c584SApple OSS Distributions
612*1031c584SApple OSS Distributions npids = coalition_get_pid_list(coal, COALITION_ROLEMASK_ALLROLES, sort_order,
613*1031c584SApple OSS Distributions pidlist, sizeof(pidlist) / sizeof(pidlist[0]));
614*1031c584SApple OSS Distributions if (npids > (int)(sizeof(pidlist) / sizeof(pidlist[0]))) {
615*1031c584SApple OSS Distributions coal_dbg("Too many members in coalition %llu (from pid:%d): %d!",
616*1031c584SApple OSS Distributions coalition_id(coal), pid, npids);
617*1031c584SApple OSS Distributions npids = sizeof(pidlist) / sizeof(pidlist[0]);
618*1031c584SApple OSS Distributions }
619*1031c584SApple OSS Distributions
620*1031c584SApple OSS Distributions out:
621*1031c584SApple OSS Distributions proc_rele(tproc);
622*1031c584SApple OSS Distributions
623*1031c584SApple OSS Distributions if (npids < 0) {
624*1031c584SApple OSS Distributions /* npids is a negative errno */
625*1031c584SApple OSS Distributions return -npids;
626*1031c584SApple OSS Distributions }
627*1031c584SApple OSS Distributions
628*1031c584SApple OSS Distributions if (npids == 0) {
629*1031c584SApple OSS Distributions return ENOENT;
630*1031c584SApple OSS Distributions }
631*1031c584SApple OSS Distributions
632*1031c584SApple OSS Distributions return SYSCTL_OUT(req, pidlist, sizeof(pidlist[0]) * npids);
633*1031c584SApple OSS Distributions }
634*1031c584SApple OSS Distributions
635*1031c584SApple OSS Distributions SYSCTL_PROC(_kern, OID_AUTO, coalition_pid_list, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
636*1031c584SApple OSS Distributions 0, 0, sysctl_coalition_get_pid_list, "I", "list of PIDS which are members of the coalition of the current process");
637*1031c584SApple OSS Distributions
638*1031c584SApple OSS Distributions #if DEVELOPMENT
639*1031c584SApple OSS Distributions static int sysctl_coalition_notify SYSCTL_HANDLER_ARGS
640*1031c584SApple OSS Distributions {
641*1031c584SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
642*1031c584SApple OSS Distributions int error, should_set;
643*1031c584SApple OSS Distributions coalition_t coal;
644*1031c584SApple OSS Distributions uint64_t value[2];
645*1031c584SApple OSS Distributions
646*1031c584SApple OSS Distributions should_set = 1;
647*1031c584SApple OSS Distributions error = SYSCTL_IN(req, value, sizeof(value));
648*1031c584SApple OSS Distributions if (error) {
649*1031c584SApple OSS Distributions error = SYSCTL_IN(req, value, sizeof(value) - sizeof(value[0]));
650*1031c584SApple OSS Distributions if (error) {
651*1031c584SApple OSS Distributions return error;
652*1031c584SApple OSS Distributions }
653*1031c584SApple OSS Distributions should_set = 0;
654*1031c584SApple OSS Distributions }
655*1031c584SApple OSS Distributions if (!req->newptr) {
656*1031c584SApple OSS Distributions return error;
657*1031c584SApple OSS Distributions }
658*1031c584SApple OSS Distributions
659*1031c584SApple OSS Distributions coal = coalition_find_by_id(value[0]);
660*1031c584SApple OSS Distributions if (coal == COALITION_NULL) {
661*1031c584SApple OSS Distributions coal_dbg("Can't find coalition with ID:%lld", value[0]);
662*1031c584SApple OSS Distributions return ESRCH;
663*1031c584SApple OSS Distributions }
664*1031c584SApple OSS Distributions
665*1031c584SApple OSS Distributions if (should_set) {
666*1031c584SApple OSS Distributions coalition_set_notify(coal, (int)value[1]);
667*1031c584SApple OSS Distributions }
668*1031c584SApple OSS Distributions
669*1031c584SApple OSS Distributions value[0] = (uint64_t)coalition_should_notify(coal);
670*1031c584SApple OSS Distributions
671*1031c584SApple OSS Distributions coalition_release(coal);
672*1031c584SApple OSS Distributions
673*1031c584SApple OSS Distributions return SYSCTL_OUT(req, value, sizeof(value[0]));
674*1031c584SApple OSS Distributions }
675*1031c584SApple OSS Distributions
676*1031c584SApple OSS Distributions SYSCTL_PROC(_kern, OID_AUTO, coalition_notify, CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED,
677*1031c584SApple OSS Distributions 0, 0, sysctl_coalition_notify, "Q", "get/set coalition notification flag");
678*1031c584SApple OSS Distributions
679*1031c584SApple OSS Distributions extern int unrestrict_coalition_syscalls;
680*1031c584SApple OSS Distributions SYSCTL_INT(_kern, OID_AUTO, unrestrict_coalitions,
681*1031c584SApple OSS Distributions CTLFLAG_RW, &unrestrict_coalition_syscalls, 0,
682*1031c584SApple OSS Distributions "unrestrict the coalition interface");
683*1031c584SApple OSS Distributions
684*1031c584SApple OSS Distributions #endif /* DEVELOPMENT */
685*1031c584SApple OSS Distributions
686*1031c584SApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
687