X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/d9a64523371fa019c4575bb400cbbc3a50ac9903..a991bd8d3e7fe02dbca0644054bab73c5b75324a:/bsd/kern/sys_coalition.c diff --git a/bsd/kern/sys_coalition.c b/bsd/kern/sys_coalition.c index 4741bfc16..28e3d3f40 100644 --- a/bsd/kern/sys_coalition.c +++ b/bsd/kern/sys_coalition.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -35,20 +36,20 @@ coalition_create_syscall(user_addr_t cidp, uint32_t 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, role, 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: @@ -183,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; @@ -234,27 +236,80 @@ coalition_info_resource_usage(coalition_t coal, user_addr_t buffer, user_size_t return copyout(&cru, buffer, MIN(bufsize, sizeof(cru))); } +#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) + if (coalition_type(coal) != COALITION_TYPE_JETSAM) { return EINVAL; - uint64_t flags = 0; + } + uint64_t flags = 0; error = copyin(buffer, &flags, MIN(bufsize, sizeof(flags))); - if (error) + if (error) { return error; - if ((flags & COALITION_EFFICIENCY_VALID_FLAGS) == 0) + } + if ((flags & COALITION_EFFICIENCY_VALID_FLAGS) == 0) { return EINVAL; + } if (flags & COALITION_FLAGS_EFFICIENT) { - coalition_set_efficient(coal); + 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) +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; @@ -308,6 +363,60 @@ bad: return error; } +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 { @@ -319,12 +428,14 @@ static int sysctl_coalition_get_ids 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); @@ -340,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 @@ -353,12 +464,14 @@ static int sysctl_coalition_get_roles 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); @@ -374,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 @@ -388,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); @@ -405,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]); } } @@ -421,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 @@ -442,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; @@ -451,33 +566,35 @@ 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]); } @@ -489,14 +606,15 @@ out: return -npids; } - if (npids == 0) + 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 @@ -510,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) { @@ -523,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); @@ -534,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 */