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