X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/4bd07ac2140668789aa3ee8ec4dde4a3e0a3bba5..a991bd8d3e7fe02dbca0644054bab73c5b75324a:/bsd/kern/sys_coalition.c diff --git a/bsd/kern/sys_coalition.c b/bsd/kern/sys_coalition.c index e35a8a878..28e3d3f40 100644 --- a/bsd/kern/sys_coalition.c +++ b/bsd/kern/sys_coalition.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -6,6 +7,7 @@ #include #include +#include #include #include #include @@ -31,22 +33,23 @@ coalition_create_syscall(user_addr_t cidp, uint32_t flags) uint64_t cid; coalition_t coal; int type = COALITION_CREATE_FLAGS_GET_TYPE(flags); + int role = COALITION_CREATE_FLAGS_GET_ROLE(flags); boolean_t privileged = !!(flags & COALITION_CREATE_FLAGS_PRIVILEGED); - if ((flags & (~COALITION_CREATE_FLAGS_MASK)) != 0) + if ((flags & (~COALITION_CREATE_FLAGS_MASK)) != 0) { return EINVAL; - if (type < 0 || type > COALITION_TYPE_MAX) + } + if (type < 0 || type > COALITION_TYPE_MAX) { return EINVAL; + } - kr = coalition_create_internal(type, privileged, &coal); + kr = coalition_create_internal(type, role, privileged, &coal, &cid); if (kr != KERN_SUCCESS) { /* for now, the only kr is KERN_RESOURCE_SHORTAGE */ error = ENOMEM; goto out; } - cid = coalition_id(coal); - coal_dbg("(addr, %u) -> %llu", flags, cid); error = copyout(&cid, cidp, sizeof(cid)); out: @@ -118,7 +121,7 @@ coalition_request_terminate_syscall(user_addr_t cidp, uint32_t flags) * Request the kernel to deallocate the coalition identified by ID, which * must be both terminated and empty. This balances the reference taken * in coalition_create. - * The memory containig the coalition object may not be freed just yet, if + * The memory containing the coalition object may not be freed just yet, if * other kernel operations still hold references to it. * * Returns: @@ -181,7 +184,8 @@ coalition_reap_syscall(user_addr_t cidp, uint32_t flags) /* Syscall demux. * Returns EPERM if the calling process is not privileged to make this call. */ -int coalition(proc_t p, struct coalition_args *cap, __unused int32_t *retval) +int +coalition(proc_t p, struct coalition_args *cap, __unused int32_t *retval) { uint32_t operation = cap->operation; user_addr_t cidp = cap->cid; @@ -214,7 +218,7 @@ static int __attribute__ ((noinline)) coalition_info_resource_usage(coalition_t coal, user_addr_t buffer, user_size_t bufsize) { kern_return_t kr; - struct coalition_resource_usage cru; + struct coalition_resource_usage cru = {}; kr = coalition_resource_usage_internal(coal, &cru); @@ -232,7 +236,80 @@ coalition_info_resource_usage(coalition_t coal, user_addr_t buffer, user_size_t return copyout(&cru, buffer, MIN(bufsize, sizeof(cru))); } -int coalition_info(proc_t p, struct coalition_info_args *uap, __unused int32_t *retval) +#if CONFIG_THREAD_GROUPS +static int +coalition_info_set_name_internal(coalition_t coal, user_addr_t buffer, user_size_t bufsize) +{ + int error; + char name[THREAD_GROUP_MAXNAME]; + + if (coalition_type(coal) != COALITION_TYPE_JETSAM) { + return EINVAL; + } + bzero(name, sizeof(name)); + error = copyin(buffer, name, MIN(bufsize, sizeof(name) - 1)); + if (error) { + return error; + } + struct thread_group *tg = coalition_get_thread_group(coal); + thread_group_set_name(tg, name); + thread_group_release(tg); + return error; +} + +#else /* CONFIG_THREAD_GROUPS */ +#define coalition_info_set_name_internal(...) 0 +#endif /* CONFIG_THREAD_GROUPS */ + +static int +coalition_info_efficiency(coalition_t coal, user_addr_t buffer, user_size_t bufsize) +{ + int error = 0; + if (coalition_type(coal) != COALITION_TYPE_JETSAM) { + return EINVAL; + } + uint64_t flags = 0; + error = copyin(buffer, &flags, MIN(bufsize, sizeof(flags))); + if (error) { + return error; + } + if ((flags & COALITION_EFFICIENCY_VALID_FLAGS) == 0) { + return EINVAL; + } + if (flags & COALITION_FLAGS_EFFICIENT) { + coalition_set_efficient(coal); +#if CONFIG_THREAD_GROUPS + struct thread_group *tg = coalition_get_thread_group(coal); + thread_group_set_flags(tg, THREAD_GROUP_FLAGS_EFFICIENT); + thread_group_release(tg); +#endif /* CONFIG_THREAD_GROUPS */ + } + return error; +} + +static int +coalition_ledger_logical_writes_limit(coalition_t coal, user_addr_t buffer, user_size_t bufsize) +{ + int error = 0; + int64_t limit = 0; + + if (coalition_type(coal) != COALITION_TYPE_RESOURCE) { + error = EINVAL; + goto out; + } + error = copyin(buffer, &limit, MIN(bufsize, sizeof(limit))); + if (error) { + goto out; + } + + + error = coalition_ledger_set_logical_writes_limit(coal, limit); +out: + return error; +} + +int +coalition_info(proc_t p, struct coalition_info_args *uap, __unused int32_t *retval) { user_addr_t cidp = uap->cid; user_addr_t buffer = uap->buffer; @@ -271,6 +348,12 @@ int coalition_info(proc_t p, struct coalition_info_args *uap, __unused int32_t * case COALITION_INFO_RESOURCE_USAGE: error = coalition_info_resource_usage(coal, buffer, bufsize); break; + case COALITION_INFO_SET_NAME: + error = coalition_info_set_name_internal(coal, buffer, bufsize); + break; + case COALITION_INFO_SET_EFFICIENCY: + error = coalition_info_efficiency(coal, buffer, bufsize); + break; default: error = EINVAL; } @@ -280,23 +363,79 @@ bad: return error; } -#if defined(DEVELOPMENT) || defined(DEBUG) +int +coalition_ledger(__unused proc_t p, __unused struct coalition_ledger_args *uap, __unused int32_t *retval) +{ + user_addr_t cidp = uap->cid; + user_addr_t buffer = uap->buffer; + user_addr_t bufsizep = uap->bufsize; + user_size_t bufsize; + uint32_t operation = uap->operation; + int error; + uint64_t cid; + coalition_t coal = COALITION_NULL; + + if (!kauth_cred_issuser(kauth_cred_get())) { + error = EPERM; + goto out; + } + + error = copyin(cidp, &cid, sizeof(cid)); + if (error) { + goto out; + } + + coal = coalition_find_by_id(cid); + if (coal == COALITION_NULL) { + error = ESRCH; + goto out; + } + + if (IS_64BIT_PROCESS(p)) { + user64_size_t size64; + error = copyin(bufsizep, &size64, sizeof(size64)); + bufsize = (user_size_t)size64; + } else { + user32_size_t size32; + error = copyin(bufsizep, &size32, sizeof(size32)); + bufsize = (user_size_t)size32; + } + if (error) { + goto out; + } + + switch (operation) { + case COALITION_LEDGER_SET_LOGICAL_WRITES_LIMIT: + error = coalition_ledger_logical_writes_limit(coal, buffer, bufsize); + break; + default: + error = EINVAL; + } +out: + if (coal != COALITION_NULL) { + coalition_release(coal); + } + return error; +} +#if DEVELOPMENT || DEBUG static int sysctl_coalition_get_ids SYSCTL_HANDLER_ARGS { #pragma unused(oidp, arg1, arg2) int error, pid; proc_t tproc; uint64_t value; - uint64_t ids[COALITION_NUM_TYPES]; + uint64_t ids[COALITION_NUM_TYPES] = {}; error = SYSCTL_IN(req, &value, sizeof(value)); - if (error) + if (error) { return error; - if (!req->newptr) + } + if (!req->newptr) { pid = req->p->p_pid; - else + } else { pid = (int)value; + } coal_dbg("looking up coalitions for pid:%d", pid); tproc = proc_find(pid); @@ -312,7 +451,7 @@ static int sysctl_coalition_get_ids SYSCTL_HANDLER_ARGS } SYSCTL_PROC(_kern, OID_AUTO, coalitions, CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED, - 0, 0, sysctl_coalition_get_ids, "Q", "coalition ids of a given process"); + 0, 0, sysctl_coalition_get_ids, "Q", "coalition ids of a given process"); static int sysctl_coalition_get_roles SYSCTL_HANDLER_ARGS @@ -321,16 +460,18 @@ static int sysctl_coalition_get_roles SYSCTL_HANDLER_ARGS int error, pid; proc_t tproc; int value; - int roles[COALITION_NUM_TYPES]; + int roles[COALITION_NUM_TYPES] = {}; error = SYSCTL_IN(req, &value, sizeof(value)); - if (error) + if (error) { return error; - if (!req->newptr) + } + if (!req->newptr) { pid = req->p->p_pid; - else + } else { pid = (int)value; + } coal_dbg("looking up coalitions for pid:%d", pid); tproc = proc_find(pid); @@ -346,7 +487,7 @@ static int sysctl_coalition_get_roles SYSCTL_HANDLER_ARGS } SYSCTL_PROC(_kern, OID_AUTO, coalition_roles, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, - 0, 0, sysctl_coalition_get_roles, "I", "coalition roles of a given process"); + 0, 0, sysctl_coalition_get_roles, "I", "coalition roles of a given process"); static int sysctl_coalition_get_page_count SYSCTL_HANDLER_ARGS @@ -360,12 +501,14 @@ static int sysctl_coalition_get_page_count SYSCTL_HANDLER_ARGS error = SYSCTL_IN(req, &value, sizeof(value)); - if (error) + if (error) { return error; - if (!req->newptr) + } + if (!req->newptr) { pid = req->p->p_pid; - else + } else { pid = (int)value; + } coal_dbg("looking up coalitions for pid:%d", pid); tproc = proc_find(pid); @@ -377,13 +520,12 @@ static int sysctl_coalition_get_page_count SYSCTL_HANDLER_ARGS memset(pgcount, 0, sizeof(pgcount)); for (int t = 0; t < COALITION_NUM_TYPES; t++) { - coal = COALITION_NULL; - coalition_is_leader(tproc->task, t, &coal); + coal = task_get_coalition(tproc->task, t); if (coal != COALITION_NULL) { int ntasks = 0; pgcount[t] = coalition_get_page_count(coal, &ntasks); coal_dbg("PID:%d, Coalition:%lld, type:%d, pgcount:%lld", - pid, coalition_id(coal), t, pgcount[t]); + pid, coalition_id(coal), t, pgcount[t]); } } @@ -393,7 +535,7 @@ static int sysctl_coalition_get_page_count SYSCTL_HANDLER_ARGS } SYSCTL_PROC(_kern, OID_AUTO, coalition_page_count, CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED, - 0, 0, sysctl_coalition_get_page_count, "Q", "coalition page count of a specified process"); + 0, 0, sysctl_coalition_get_page_count, "Q", "coalition page count of a specified process"); static int sysctl_coalition_get_pid_list SYSCTL_HANDLER_ARGS @@ -414,8 +556,9 @@ static int sysctl_coalition_get_pid_list SYSCTL_HANDLER_ARGS has_pid = 0; error = SYSCTL_IN(req, &value, sizeof(value) - sizeof(value[0])); } - if (error) + if (error) { return error; + } if (!req->newptr) { type = COALITION_TYPE_RESOURCE; sort_order = COALITION_SORT_DEFAULT; @@ -423,47 +566,55 @@ static int sysctl_coalition_get_pid_list SYSCTL_HANDLER_ARGS } else { type = value[0]; sort_order = value[1]; - if (has_pid) + if (has_pid) { pid = value[2]; - else + } else { pid = req->p->p_pid; + } } - if (type < 0 || type >= COALITION_NUM_TYPES) + if (type < 0 || type >= COALITION_NUM_TYPES) { return EINVAL; + } coal_dbg("getting constituent PIDS for coalition of type %d " - "containing pid:%d (sort:%d)", type, pid, sort_order); + "containing pid:%d (sort:%d)", type, pid, sort_order); tproc = proc_find(pid); if (tproc == NULL) { coal_dbg("ERROR: Couldn't find pid:%d", pid); return ESRCH; } - (void)coalition_is_leader(tproc->task, type, &coal); + coal = task_get_coalition(tproc->task, type); if (coal == COALITION_NULL) { goto out; } npids = coalition_get_pid_list(coal, COALITION_ROLEMASK_ALLROLES, sort_order, - pidlist, sizeof(pidlist) / sizeof(pidlist[0])); + pidlist, sizeof(pidlist) / sizeof(pidlist[0])); if (npids > (int)(sizeof(pidlist) / sizeof(pidlist[0]))) { coal_dbg("Too many members in coalition %llu (from pid:%d): %d!", - coalition_id(coal), pid, npids); + coalition_id(coal), pid, npids); npids = sizeof(pidlist) / sizeof(pidlist[0]); } out: proc_rele(tproc); - if (npids == 0) + if (npids < 0) { + /* npids is a negative errno */ + return -npids; + } + + if (npids == 0) { return ENOENT; + } return SYSCTL_OUT(req, pidlist, sizeof(pidlist[0]) * npids); } SYSCTL_PROC(_kern, OID_AUTO, coalition_pid_list, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, - 0, 0, sysctl_coalition_get_pid_list, "I", "list of PIDS which are members of the coalition of the current process"); + 0, 0, sysctl_coalition_get_pid_list, "I", "list of PIDS which are members of the coalition of the current process"); #if DEVELOPMENT static int sysctl_coalition_notify SYSCTL_HANDLER_ARGS @@ -477,12 +628,14 @@ static int sysctl_coalition_notify SYSCTL_HANDLER_ARGS error = SYSCTL_IN(req, value, sizeof(value)); if (error) { error = SYSCTL_IN(req, value, sizeof(value) - sizeof(value[0])); - if (error) + if (error) { return error; + } should_set = 0; } - if (!req->newptr) + if (!req->newptr) { return error; + } coal = coalition_find_by_id(value[0]); if (coal == COALITION_NULL) { @@ -490,8 +643,9 @@ static int sysctl_coalition_notify SYSCTL_HANDLER_ARGS return ESRCH; } - if (should_set) + if (should_set) { coalition_set_notify(coal, (int)value[1]); + } value[0] = (uint64_t)coalition_should_notify(coal); @@ -501,12 +655,12 @@ static int sysctl_coalition_notify SYSCTL_HANDLER_ARGS } SYSCTL_PROC(_kern, OID_AUTO, coalition_notify, CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED, - 0, 0, sysctl_coalition_notify, "Q", "get/set coalition notification flag"); + 0, 0, sysctl_coalition_notify, "Q", "get/set coalition notification flag"); extern int unrestrict_coalition_syscalls; SYSCTL_INT(_kern, OID_AUTO, unrestrict_coalitions, - CTLFLAG_RW, &unrestrict_coalition_syscalls, 0, - "unrestrict the coalition interface"); + CTLFLAG_RW, &unrestrict_coalition_syscalls, 0, + "unrestrict the coalition interface"); #endif /* DEVELOPMENT */