1 #include <kern/kern_types.h>
2 #include <mach/mach_types.h>
3 #include <mach/boolean.h>
5 #include <kern/coalition.h>
7 #include <sys/coalition.h>
9 #include <sys/kernel.h>
10 #include <sys/sysproto.h>
11 #include <sys/systm.h>
13 /* Coalitions syscalls */
16 * Create a new, empty coalition and return its ID.
19 * EINVAL Flags parameter was invalid
20 * ENOMEM Unable to allocate kernel resources for a new coalition
21 * EFAULT cidp parameter pointed to invalid memory.
23 * Returns with reference held for userspace caller.
27 coalition_create_syscall(user_addr_t cidp
, uint32_t flags
)
34 if ((flags
& (~COALITION_CREATE_FLAG_MASK
)) != 0) {
38 boolean_t privileged
= flags
& COALITION_CREATE_FLAG_PRIVILEGED
;
40 kr
= coalition_create_internal(&coal
, privileged
);
41 if (kr
!= KERN_SUCCESS
) {
42 /* for now, the only kr is KERN_RESOURCE_SHORTAGE */
47 cid
= coalition_id(coal
);
50 printf("%s(addr, %u) -> %llu\n", __func__
, flags
, cid
);
52 error
= copyout(&cid
, cidp
, sizeof(cid
));
58 * Request to terminate the coalition identified by ID.
59 * Attempts to spawn into this coalition using the posix_spawnattr will begin
60 * failing. Processes already within the coalition may still fork.
61 * Arms the 'coalition is empty' notification when the coalition's active
65 * ESRCH No coalition with that ID could be found.
66 * EALREADY The coalition with that ID has already been terminated.
67 * EFAULT cidp parameter pointed to invalid memory.
68 * EPERM Caller doesn't have permission to terminate that coalition.
72 coalition_request_terminate_syscall(user_addr_t cidp
, uint32_t flags
)
83 error
= copyin(cidp
, &cid
, sizeof(cid
));
88 coal
= coalition_find_by_id(cid
);
89 if (coal
== COALITION_NULL
) {
93 kr
= coalition_request_terminate_internal(coal
);
94 coalition_release(coal
);
99 case KERN_DEFAULT_SET
:
101 case KERN_TERMINATED
:
103 case KERN_INVALID_NAME
:
110 printf("%s(%llu, %u) -> %d\n", __func__
, cid
, flags
, error
);
117 * Request the kernel to deallocate the coalition identified by ID, which
118 * must be both terminated and empty. This balances the reference taken
119 * in coalition_create.
120 * The memory containig the coalition object may not be freed just yet, if
121 * other kernel operations still hold references to it.
124 * EINVAL Flags parameter was invalid
125 * ESRCH Coalition ID refers to a coalition that doesn't exist.
126 * EBUSY Coalition has not yet been terminated.
127 * EBUSY Coalition is still active.
128 * EFAULT cidp parameter pointed to invalid memory.
129 * EPERM Caller doesn't have permission to terminate that coalition.
130 * Consumes one reference, "held" by caller since coalition_create
134 coalition_reap_syscall(user_addr_t cidp
, uint32_t flags
)
145 error
= copyin(cidp
, &cid
, sizeof(cid
));
150 coal
= coalition_find_by_id(cid
);
151 if (coal
== COALITION_NULL
) {
155 kr
= coalition_reap_internal(coal
);
156 coalition_release(coal
);
161 case KERN_DEFAULT_SET
:
163 case KERN_TERMINATED
:
172 printf("%s(%llu, %u) -> %d\n", __func__
, cid
, flags
, error
);
179 * Returns EPERM if the calling process is not privileged to make this call.
181 int coalition(proc_t p
, struct coalition_args
*cap
, __unused
int32_t *retval
)
183 uint32_t operation
= cap
->operation
;
184 user_addr_t cidp
= cap
->cid
;
185 uint32_t flags
= cap
->flags
;
188 if (!task_is_in_privileged_coalition(p
->task
)) {
193 case COALITION_OP_CREATE
:
194 error
= coalition_create_syscall(cidp
, flags
);
196 case COALITION_OP_REAP
:
197 error
= coalition_reap_syscall(cidp
, flags
);
199 case COALITION_OP_TERMINATE
:
200 error
= coalition_request_terminate_syscall(cidp
, flags
);
208 /* This is a temporary interface, likely to be changed by 15385642. */
209 static int __attribute__ ((noinline
))
210 coalition_info_resource_usage(coalition_t coal
, user_addr_t buffer
, user_size_t bufsize
)
213 struct coalition_resource_usage cru
;
215 if (bufsize
!= sizeof(cru
)) {
219 kr
= coalition_resource_usage_internal(coal
, &cru
);
222 case KERN_INVALID_ARGUMENT
:
224 case KERN_RESOURCE_SHORTAGE
:
229 return EIO
; /* shrug */
232 return copyout(&cru
, buffer
, bufsize
);
235 int coalition_info(proc_t p
, struct coalition_info_args
*uap
, __unused
int32_t *retval
)
237 user_addr_t cidp
= uap
->cid
;
238 user_addr_t buffer
= uap
->buffer
;
239 user_addr_t bufsizep
= uap
->bufsize
;
241 uint32_t flavor
= uap
->flavor
;
246 error
= copyin(cidp
, &cid
, sizeof(cid
));
251 coal
= coalition_find_by_id(cid
);
252 if (coal
== COALITION_NULL
) {
255 /* TODO: priv check? EPERM or ESRCH? */
257 if (IS_64BIT_PROCESS(p
)) {
258 user64_size_t size64
;
259 error
= copyin(bufsizep
, &size64
, sizeof(size64
));
260 bufsize
= (user_size_t
)size64
;
262 user32_size_t size32
;
263 error
= copyin(bufsizep
, &size32
, sizeof(size32
));
264 bufsize
= (user_size_t
)size32
;
271 case COALITION_INFO_RESOURCE_USAGE
:
272 error
= coalition_info_resource_usage(coal
, buffer
, bufsize
);
279 coalition_release(coal
);