X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/fe8ab488e9161c46dd9885d58fc52996dc0249ff..a39ff7e25e19b3a8c3020042a3872ca9ec9659f1:/bsd/kern/kern_resource.c diff --git a/bsd/kern/kern_resource.c b/bsd/kern/kern_resource.c index 2900cd52b..780159263 100644 --- a/bsd/kern/kern_resource.c +++ b/bsd/kern/kern_resource.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2008 Apple Inc. All rights reserved. + * Copyright (c) 2000-2017 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -81,8 +81,6 @@ #include #include #include -#include - #include #include @@ -98,36 +96,45 @@ #include #include /* for thread_policy_set( ) */ #include +#include #include #include /* for absolutetime_to_microtime() */ #include /* for TRAFFIC_MGT_SO_* */ #include /* for struct socket */ +#if NECP +#include +#endif /* NECP */ #include #include #include +#include +#include + +#if CONFIG_MACF +#include +#endif int donice(struct proc *curp, struct proc *chgp, int n); int dosetrlimit(struct proc *p, u_int which, struct rlimit *limp); int uthread_get_background_state(uthread_t); static void do_background_socket(struct proc *p, thread_t thread); -static int do_background_thread(struct proc *curp, thread_t thread, int priority); +static int do_background_thread(thread_t thread, int priority); static int do_background_proc(struct proc *curp, struct proc *targetp, int priority); static int set_gpudeny_proc(struct proc *curp, struct proc *targetp, int priority); static int proc_set_darwin_role(proc_t curp, proc_t targetp, int priority); static int proc_get_darwin_role(proc_t curp, proc_t targetp, int *priority); static int get_background_proc(struct proc *curp, struct proc *targetp, int *priority); -void proc_apply_task_networkbg_internal(proc_t, thread_t); -void proc_restore_task_networkbg_internal(proc_t, thread_t); int proc_pid_rusage(int pid, int flavor, user_addr_t buf, int32_t *retval); void gather_rusage_info(proc_t p, rusage_info_current *ru, int flavor); int fill_task_rusage(task_t task, rusage_info_current *ri); void fill_task_billed_usage(task_t task, rusage_info_current *ri); int fill_task_io_rusage(task_t task, rusage_info_current *ri); int fill_task_qos_rusage(task_t task, rusage_info_current *ri); -static void rusage_info_conversion(rusage_info_t ri_info, rusage_info_current *ri_current, int flavor); +uint64_t get_task_logical_writes(task_t task); +void fill_task_monotonic_rusage(task_t task, rusage_info_current *ri); int proc_get_rusage(proc_t p, int flavor, user_addr_t buffer, __unused int is_zombie); @@ -211,7 +218,7 @@ getpriority(struct proc *curp, struct getpriority_args *uap, int32_t *retval) } /* No need for iteration as it is a simple scan */ pgrp_lock(pg); - for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) { + PGMEMBERS_FOREACH(pg, p) { if (p->p_nice < low) low = p->p_nice; } @@ -243,7 +250,7 @@ getpriority(struct proc *curp, struct getpriority_args *uap, int32_t *retval) if (uap->who != 0) return (EINVAL); - low = proc_get_task_policy(current_task(), current_thread(), TASK_POLICY_INTERNAL, TASK_POLICY_DARWIN_BG); + low = proc_get_thread_policy(current_thread(), TASK_POLICY_INTERNAL, TASK_POLICY_DARWIN_BG); break; @@ -416,7 +423,7 @@ setpriority(struct proc *curp, struct setpriority_args *uap, int32_t *retval) if (uap->who != 0) return (EINVAL); - error = do_background_thread(curp, current_thread(), uap->prio); + error = do_background_thread(current_thread(), uap->prio); found++; break; } @@ -582,7 +589,7 @@ static int proc_set_darwin_role(proc_t curp, proc_t targetp, int priority) { int error = 0; - uint32_t flagsp; + uint32_t flagsp = 0; kauth_cred_t ucred, target_cred; @@ -592,8 +599,10 @@ proc_set_darwin_role(proc_t curp, proc_t targetp, int priority) if (!kauth_cred_issuser(ucred) && kauth_cred_getruid(ucred) && kauth_cred_getuid(ucred) != kauth_cred_getuid(target_cred) && kauth_cred_getruid(ucred) != kauth_cred_getuid(target_cred)) { - error = EPERM; - goto out; + if (priv_check_cred(ucred, PRIV_SETPRIORITY_DARWIN_ROLE, 0) != 0) { + error = EPERM; + goto out; + } } if (curp != targetp) { @@ -611,26 +620,11 @@ proc_set_darwin_role(proc_t curp, proc_t targetp, int priority) integer_t role = 0; - switch (priority) { - case PRIO_DARWIN_ROLE_DEFAULT: - role = TASK_UNSPECIFIED; - break; - case PRIO_DARWIN_ROLE_UI_FOCAL: - role = TASK_FOREGROUND_APPLICATION; - break; - case PRIO_DARWIN_ROLE_UI: - role = TASK_BACKGROUND_APPLICATION; - break; - case PRIO_DARWIN_ROLE_NON_UI: - role = TASK_NONUI_APPLICATION; - break; - default: - error = EINVAL; - goto out; - } + if ((error = proc_darwin_role_to_task_role(priority, &role))) + goto out; - proc_set_task_policy(proc_task(targetp), THREAD_NULL, - TASK_POLICY_ATTRIBUTE, TASK_POLICY_ROLE, role); + proc_set_task_policy(proc_task(targetp), TASK_POLICY_ATTRIBUTE, + TASK_POLICY_ROLE, role); out: kauth_cred_unref(&target_cred); @@ -662,24 +656,9 @@ proc_get_darwin_role(proc_t curp, proc_t targetp, int *priority) #endif } - role = proc_get_task_policy(proc_task(targetp), THREAD_NULL, - TASK_POLICY_ATTRIBUTE, TASK_POLICY_ROLE); + role = proc_get_task_policy(proc_task(targetp), TASK_POLICY_ATTRIBUTE, TASK_POLICY_ROLE); - switch (role) { - case TASK_FOREGROUND_APPLICATION: - *priority = PRIO_DARWIN_ROLE_UI_FOCAL; - break; - case TASK_BACKGROUND_APPLICATION: - *priority = PRIO_DARWIN_ROLE_UI; - break; - case TASK_NONUI_APPLICATION: - *priority = PRIO_DARWIN_ROLE_NON_UI; - break; - case TASK_UNSPECIFIED: - default: - *priority = PRIO_DARWIN_ROLE_DEFAULT; - break; - } + *priority = proc_task_role_to_darwin_role(role); out: kauth_cred_unref(&target_cred); @@ -706,7 +685,7 @@ get_background_proc(struct proc *curp, struct proc *targetp, int *priority) external = (curp == targetp) ? TASK_POLICY_INTERNAL : TASK_POLICY_EXTERNAL; - *priority = proc_get_task_policy(current_task(), THREAD_NULL, external, TASK_POLICY_DARWIN_BG); + *priority = proc_get_task_policy(current_task(), external, TASK_POLICY_DARWIN_BG); out: kauth_cred_unref(&target_cred); @@ -757,7 +736,7 @@ do_background_proc(struct proc *curp, struct proc *targetp, int priority) break; } - proc_set_task_policy(proc_task(targetp), THREAD_NULL, external, TASK_POLICY_DARWIN_BG, enable); + proc_set_task_policy(proc_task(targetp), external, TASK_POLICY_DARWIN_BG, enable); out: kauth_cred_unref(&target_cred); @@ -789,16 +768,20 @@ do_background_socket(struct proc *p, thread_t thread) fdp = p->p_fd; for (i = 0; i < fdp->fd_nfiles; i++) { - struct socket *sockp; - fp = fdp->fd_ofiles[i]; - if (fp == NULL || (fdp->fd_ofileflags[i] & UF_RESERVED) != 0 || - FILEGLOB_DTYPE(fp->f_fglob) != DTYPE_SOCKET) { + if (fp == NULL || (fdp->fd_ofileflags[i] & UF_RESERVED) != 0) { continue; } - sockp = (struct socket *)fp->f_fglob->fg_data; - socket_set_traffic_mgt_flags(sockp, TRAFFIC_MGT_SO_BACKGROUND); - sockp->so_background_thread = NULL; + if (FILEGLOB_DTYPE(fp->f_fglob) == DTYPE_SOCKET) { + struct socket *sockp = (struct socket *)fp->f_fglob->fg_data; + socket_set_traffic_mgt_flags(sockp, TRAFFIC_MGT_SO_BACKGROUND); + sockp->so_background_thread = NULL; + } +#if NECP + else if (FILEGLOB_DTYPE(fp->f_fglob) == DTYPE_NETPOLICY) { + necp_set_client_as_background(p, fp, background); + } +#endif /* NECP */ } } } else { @@ -812,17 +795,23 @@ do_background_socket(struct proc *p, thread_t thread) struct socket *sockp; fp = fdp->fd_ofiles[ i ]; - if ( fp == NULL || (fdp->fd_ofileflags[ i ] & UF_RESERVED) != 0 || - FILEGLOB_DTYPE(fp->f_fglob) != DTYPE_SOCKET ) { + if (fp == NULL || (fdp->fd_ofileflags[ i ] & UF_RESERVED) != 0) { continue; } - sockp = (struct socket *)fp->f_fglob->fg_data; - /* skip if only clearing this thread's sockets */ - if ((thread) && (sockp->so_background_thread != thread)) { - continue; + if (FILEGLOB_DTYPE(fp->f_fglob) == DTYPE_SOCKET) { + sockp = (struct socket *)fp->f_fglob->fg_data; + /* skip if only clearing this thread's sockets */ + if ((thread) && (sockp->so_background_thread != thread)) { + continue; + } + socket_clear_traffic_mgt_flags(sockp, TRAFFIC_MGT_SO_BACKGROUND); + sockp->so_background_thread = NULL; + } +#if NECP + else if (FILEGLOB_DTYPE(fp->f_fglob) == DTYPE_NETPOLICY) { + necp_set_client_as_background(p, fp, background); } - socket_clear_traffic_mgt_flags(sockp, TRAFFIC_MGT_SO_BACKGROUND); - sockp->so_background_thread = NULL; +#endif /* NECP */ } } @@ -835,12 +824,15 @@ do_background_socket(struct proc *p, thread_t thread) /* * do_background_thread + * + * Requires: thread reference + * * Returns: 0 Success * EPERM Tried to background while in vfork * XXX - todo - does this need a MACF hook? */ static int -do_background_thread(struct proc *curp, thread_t thread, int priority) +do_background_thread(thread_t thread, int priority) { struct uthread *ut; int enable, external; @@ -852,6 +844,7 @@ do_background_thread(struct proc *curp, thread_t thread, int priority) if ((ut->uu_flag & UT_VFORK) != 0) return(EPERM); + /* Backgrounding is unsupported for workq threads */ if (thread_is_static_param(thread)) { return(EPERM); } @@ -866,8 +859,7 @@ do_background_thread(struct proc *curp, thread_t thread, int priority) enable = (priority == PRIO_DARWIN_BG) ? TASK_POLICY_ENABLE : TASK_POLICY_DISABLE; external = (current_thread() == thread) ? TASK_POLICY_INTERNAL : TASK_POLICY_EXTERNAL; - proc_set_task_policy_thread(curp->task, thread_tid(thread), external, - TASK_POLICY_DARWIN_BG, enable); + proc_set_thread_policy(thread, external, TASK_POLICY_DARWIN_BG, enable); return rv; } @@ -1152,7 +1144,7 @@ out: int getrlimit(struct proc *p, struct getrlimit_args *uap, __unused int32_t *retval) { - struct rlimit lim; + struct rlimit lim = {}; /* * Take out flag now in case we need to use it to trigger variant @@ -1533,9 +1525,15 @@ iopolicysys_disk(struct proc *p __unused, int cmd, int scope, int policy, struct break; case IOPOL_SCOPE_DARWIN_BG: +#if CONFIG_EMBEDDED + /* Embedded doesn't want this as BG is always IOPOL_THROTTLE */ + error = ENOTSUP; + goto out; +#else /* CONFIG_EMBEDDED */ thread = THREAD_NULL; policy_flavor = TASK_POLICY_DARWIN_BG_IOPOL; break; +#endif /* CONFIG_EMBEDDED */ default: error = EINVAL; @@ -1580,14 +1578,16 @@ iopolicysys_disk(struct proc *p __unused, int cmd, int scope, int policy, struct /* Perform command */ switch(cmd) { case IOPOL_CMD_SET: - proc_set_task_policy(current_task(), thread, - TASK_POLICY_INTERNAL, policy_flavor, - policy); + if (thread != THREAD_NULL) + proc_set_thread_policy(thread, TASK_POLICY_INTERNAL, policy_flavor, policy); + else + proc_set_task_policy(current_task(), TASK_POLICY_INTERNAL, policy_flavor, policy); break; case IOPOL_CMD_GET: - policy = proc_get_task_policy(current_task(), thread, - TASK_POLICY_INTERNAL, policy_flavor); - + if (thread != THREAD_NULL) + policy = proc_get_thread_policy(thread, TASK_POLICY_INTERNAL, policy_flavor); + else + policy = proc_get_task_policy(current_task(), TASK_POLICY_INTERNAL, policy_flavor); iop_param->iop_policy = policy; break; default: @@ -1632,8 +1632,13 @@ iopolicysys_vfs(struct proc *p, int cmd, int scope, int policy, struct _iopol_pa switch(cmd) { case IOPOL_CMD_SET: if (0 == kauth_cred_issuser(kauth_cred_get())) { - error = EPERM; - goto out; + /* If it's a non-root process, it needs to have the entitlement to set the policy */ + boolean_t entitled = FALSE; + entitled = IOTaskHasEntitlement(current_task(), "com.apple.private.iopol.case_sensitivity"); + if (!entitled) { + error = EPERM; + goto out; + } } switch (policy) { @@ -1663,9 +1668,7 @@ out: return (error); } -/* BSD call back function for task_policy */ -void proc_apply_task_networkbg(void * bsd_info, thread_t thread); - +/* BSD call back function for task_policy networking changes */ void proc_apply_task_networkbg(void * bsd_info, thread_t thread) { @@ -1689,7 +1692,13 @@ gather_rusage_info(proc_t p, rusage_info_current *ru, int flavor) struct rusage_info_child *ri_child; assert(p->p_stats != NULL); + memset(ru, 0, sizeof(*ru)); switch(flavor) { + case RUSAGE_INFO_V4: + ru->ri_logical_writes = get_task_logical_writes(p->task); + ru->ri_lifetime_max_phys_footprint = get_task_phys_footprint_lifetime_max(p->task); + fill_task_monotonic_rusage(p->task, ru); + /* fall through */ case RUSAGE_INFO_V3: fill_task_qos_rusage(p->task, ru); @@ -1724,131 +1733,57 @@ gather_rusage_info(proc_t p, rusage_info_current *ru, int flavor) } } -static void -rusage_info_conversion(rusage_info_t ri_info, rusage_info_current *ri_current, int flavor) -{ - struct rusage_info_v0 *ri_v0; - struct rusage_info_v1 *ri_v1; - struct rusage_info_v2 *ri_v2; - - switch (flavor) { - - case RUSAGE_INFO_V2: - ri_v2 = (struct rusage_info_v2 *)ri_info; - ri_v2->ri_diskio_bytesread = ri_current->ri_diskio_bytesread; - ri_v2->ri_diskio_byteswritten = ri_current->ri_diskio_byteswritten; - /* fall through */ - - case RUSAGE_INFO_V1: - ri_v1 = (struct rusage_info_v1 *)ri_info; - ri_v1->ri_child_user_time = ri_current->ri_child_user_time; - ri_v1->ri_child_system_time = ri_current->ri_child_system_time; - ri_v1->ri_child_pkg_idle_wkups = ri_current->ri_child_pkg_idle_wkups; - ri_v1->ri_child_interrupt_wkups = ri_current->ri_child_interrupt_wkups; - ri_v1->ri_child_pageins = ri_current->ri_child_pageins; - ri_v1->ri_child_elapsed_abstime = ri_current->ri_child_elapsed_abstime; - /* fall through */ - - case RUSAGE_INFO_V0: - ri_v0 = (struct rusage_info_v0 *)ri_info; - memcpy(&ri_v0->ri_uuid[0], &ri_current->ri_uuid[0], sizeof(ri_v0->ri_uuid)); - ri_v0->ri_user_time = ri_current->ri_user_time; - ri_v0->ri_system_time = ri_current->ri_system_time; - ri_v0->ri_pkg_idle_wkups = ri_current->ri_pkg_idle_wkups; - ri_v0->ri_interrupt_wkups = ri_current->ri_interrupt_wkups; - ri_v0->ri_pageins = ri_current->ri_pageins; - ri_v0->ri_wired_size = ri_current->ri_wired_size; - ri_v0->ri_resident_size = ri_current->ri_resident_size; - ri_v0->ri_phys_footprint = ri_current->ri_phys_footprint; - ri_v0->ri_proc_start_abstime = ri_current->ri_proc_start_abstime; - ri_v0->ri_proc_exit_abstime = ri_current->ri_proc_exit_abstime; - - break; - - default: - break; - } -} - - int proc_get_rusage(proc_t p, int flavor, user_addr_t buffer, __unused int is_zombie) { - struct rusage_info_v0 ri_v0; - struct rusage_info_v1 ri_v1; - struct rusage_info_v2 ri_v2; - struct rusage_info_v3 ri_v3; - rusage_info_current ri_current; int error = 0; + size_t size = 0; switch (flavor) { case RUSAGE_INFO_V0: - /* - * If task is still alive, collect info from the live task itself. - * Otherwise, look to the cached info in the zombie proc. - */ - if (p->p_ru == NULL) { - gather_rusage_info(p, &ri_current, flavor); - ri_current.ri_proc_exit_abstime = 0; - rusage_info_conversion(&ri_v0, &ri_current, flavor); - } else { - rusage_info_conversion(&ri_v0, &p->p_ru->ri, flavor); - } - error = copyout(&ri_v0, buffer, sizeof (ri_v0)); + size = sizeof(struct rusage_info_v0); break; case RUSAGE_INFO_V1: - /* - * If task is still alive, collect info from the live task itself. - * Otherwise, look to the cached info in the zombie proc. - */ - if (p->p_ru == NULL) { - gather_rusage_info(p, &ri_current, flavor); - ri_current.ri_proc_exit_abstime = 0; - rusage_info_conversion(&ri_v1, &ri_current, flavor); - } else { - rusage_info_conversion(&ri_v1, &p->p_ru->ri, flavor); - } - error = copyout(&ri_v1, buffer, sizeof (ri_v1)); + size = sizeof(struct rusage_info_v1); break; case RUSAGE_INFO_V2: - /* - * If task is still alive, collect info from the live task itself. - * Otherwise, look to the cached info in the zombie proc. - */ - if (p->p_ru == NULL) { - gather_rusage_info(p, &ri_current, flavor); - ri_current.ri_proc_exit_abstime = 0; - rusage_info_conversion(&ri_v2, &ri_current, flavor); - } else { - rusage_info_conversion(&ri_v2, &p->p_ru->ri, flavor); - } - error = copyout(&ri_v2, buffer, sizeof (ri_v2)); + size = sizeof(struct rusage_info_v2); break; case RUSAGE_INFO_V3: - /* - * If task is still alive, collect info from the live task itself. - * Otherwise, look to the cached info in the zombie proc. - */ - if (p->p_ru == NULL) { - gather_rusage_info(p, &ri_v3, flavor); - ri_v3.ri_proc_exit_abstime = 0; - } else { - ri_v3 = p->p_ru->ri; - } - error = copyout(&ri_v3, buffer, sizeof (ri_v3)); + size = sizeof(struct rusage_info_v3); break; - default: - error = EINVAL; + case RUSAGE_INFO_V4: + size = sizeof(struct rusage_info_v4); break; + + default: + return EINVAL; + } + + if(size == 0) { + return EINVAL; + } + + /* + * If task is still alive, collect info from the live task itself. + * Otherwise, look to the cached info in the zombie proc. + */ + if (p->p_ru == NULL) { + gather_rusage_info(p, &ri_current, flavor); + ri_current.ri_proc_exit_abstime = 0; + error = copyout(&ri_current, buffer, size); + } else { + ri_current = p->p_ru->ri; + error = copyout(&p->p_ru->ri, buffer, size); } - return (error); + return (error); } static int @@ -1974,3 +1909,10 @@ int thread_selfusage(struct proc *p __unused, struct thread_selfusage_args *uap return (0); } + +#if !MONOTONIC +int thread_selfcounts(__unused struct proc *p, __unused struct thread_selfcounts_args *uap, __unused int *ret_out) +{ + return ENOTSUP; +} +#endif /* !MONOTONIC */