X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/39236c6e673c41db228275375ab7fdb0f837b292..d9a64523371fa019c4575bb400cbbc3a50ac9903:/bsd/kern/process_policy.c diff --git a/bsd/kern/process_policy.c b/bsd/kern/process_policy.c index 9ae4b32bc..8c2b5b230 100644 --- a/bsd/kern/process_policy.c +++ b/bsd/kern/process_policy.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2005-2016 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -43,15 +44,14 @@ #include #include -#include - #include #include #include #include -#include #include #include +#include + #include #include #include @@ -71,14 +71,26 @@ #include #include +#if CONFIG_EMBEDDED +#include +#endif /* CONFIG_EMBEDDED */ + +#if CONFIG_MACF +#include +#include +#endif /* CONFIG_MACF */ + static int handle_lowresource(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid); -static int handle_resourceuse(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid); +static int handle_cpuuse(int action, user_addr_t attrp, proc_t proc, uint64_t target_threadid); static int handle_apptype(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid); static int handle_boost(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid); extern kern_return_t task_suspend(task_t); extern kern_return_t task_resume(task_t); +#if CONFIG_EMBEDDED +static int handle_applifecycle(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid); +#endif /* CONFIG_EMBEDDED */ /***************************** process_policy ********************/ @@ -103,8 +115,13 @@ process_policy(__unused struct proc *p, struct process_policy_args * uap, __unus pid_t target_pid = uap->target_pid; uint64_t target_threadid = uap->target_threadid; proc_t target_proc = PROC_NULL; +#if CONFIG_MACF || !CONFIG_EMBEDDED proc_t curp = current_proc(); +#endif kauth_cred_t my_cred; +#if CONFIG_EMBEDDED + kauth_cred_t target_cred; +#endif if ((scope != PROC_POLICY_SCOPE_PROCESS) && (scope != PROC_POLICY_SCOPE_THREAD)) { return(EINVAL); @@ -120,6 +137,13 @@ process_policy(__unused struct proc *p, struct process_policy_args * uap, __unus my_cred = kauth_cred_get(); +#if CONFIG_EMBEDDED + target_cred = kauth_cred_proc_ref(target_proc); + + if (!kauth_cred_issuser(my_cred) && kauth_cred_getruid(my_cred) && + kauth_cred_getuid(my_cred) != kauth_cred_getuid(target_cred) && + kauth_cred_getruid(my_cred) != kauth_cred_getuid(target_cred)) +#else /* * Resoure starvation control can be used by unpriv resource owner but priv at the time of ownership claim. This is * checked in low resource handle routine. So bypass the checks here. @@ -127,6 +151,7 @@ process_policy(__unused struct proc *p, struct process_policy_args * uap, __unus if ((policy != PROC_POLICY_RESOURCE_STARVATION) && (policy != PROC_POLICY_APPTYPE) && (!kauth_cred_issuser(my_cred) && curp != p)) +#endif { error = EPERM; goto out; @@ -136,6 +161,10 @@ process_policy(__unused struct proc *p, struct process_policy_args * uap, __unus switch (policy) { case PROC_POLICY_BOOST: case PROC_POLICY_RESOURCE_USAGE: +#if CONFIG_EMBEDDED + case PROC_POLICY_APPTYPE: + case PROC_POLICY_APP_LIFECYCLE: +#endif /* These policies do their own appropriate mac checks */ break; default: @@ -156,8 +185,29 @@ process_policy(__unused struct proc *p, struct process_policy_args * uap, __unus error = handle_lowresource(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); break; case PROC_POLICY_RESOURCE_USAGE: - error = handle_resourceuse(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); + switch(policy_subtype) { + case PROC_POLICY_RUSAGE_NONE: + case PROC_POLICY_RUSAGE_WIREDMEM: + case PROC_POLICY_RUSAGE_VIRTMEM: + case PROC_POLICY_RUSAGE_DISK: + case PROC_POLICY_RUSAGE_NETWORK: + case PROC_POLICY_RUSAGE_POWER: + error = ENOTSUP; + goto out; + default: + error = EINVAL; + goto out; + case PROC_POLICY_RUSAGE_CPU: + break; + } + + error = handle_cpuuse(action, attrp, target_proc, target_threadid); break; +#if CONFIG_EMBEDDED + case PROC_POLICY_APP_LIFECYCLE: + error = handle_applifecycle(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); + break; +#endif /* CONFIG_EMBEDDED */ case PROC_POLICY_APPTYPE: error = handle_apptype(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); break; @@ -171,6 +221,9 @@ process_policy(__unused struct proc *p, struct process_policy_args * uap, __unus out: proc_rele(target_proc); +#if CONFIG_EMBEDDED + kauth_cred_unref(&target_cred); +#endif return(error); } @@ -197,49 +250,46 @@ handle_lowresource(__unused int scope, int action, __unused int policy, int poli static int -handle_resourceuse(__unused int scope, __unused int action, __unused int policy, int policy_subtype, user_addr_t attrp, proc_t proc, __unused uint64_t target_threadid) +handle_cpuuse(int action, user_addr_t attrp, proc_t proc, __unused uint64_t target_threadid) { - proc_policy_cpuusage_attr_t cpuattr; -#if CONFIG_MACF + proc_policy_cpuusage_attr_t cpuattr = { }; +#if CONFIG_MACF || !CONFIG_EMBEDDED proc_t curp = current_proc(); #endif - int entitled = TRUE; + Boolean privileged = FALSE; + Boolean canEnable = FALSE; uint64_t interval = -1ULL; int error = 0; + uint8_t percentage; - switch(policy_subtype) { - case PROC_POLICY_RUSAGE_NONE: - case PROC_POLICY_RUSAGE_WIREDMEM: - case PROC_POLICY_RUSAGE_VIRTMEM: - case PROC_POLICY_RUSAGE_DISK: - case PROC_POLICY_RUSAGE_NETWORK: - case PROC_POLICY_RUSAGE_POWER: - return(ENOTSUP); - break; - default: - return(EINVAL); - case PROC_POLICY_RUSAGE_CPU: - break; +#if !CONFIG_EMBEDDED + /* On macOS, tasks can only set and clear their own CPU limits. */ + if ((action == PROC_POLICY_ACTION_APPLY || action == PROC_POLICY_ACTION_RESTORE) + && curp != proc) { + return (EPERM); } + /* No privilege required on macOS. */ + privileged = TRUE; +#endif #if CONFIG_MACF - if (curp != proc) { - /* the cpumon entitlement manages messing with CPU limits on self */ - error = mac_proc_check_sched(curp, proc); - if (error) - return error; + /* Is caller privileged to set less-restrictive scheduling parameters? */ + if (!privileged) { + privileged = (priv_check_cred(kauth_cred_get(), PRIV_PROC_CPUMON_OVERRIDE, 0) == 0); } + canEnable = (privileged && action == PROC_POLICY_ACTION_ENABLE); - /* - * Allow a process to change CPU usage monitor parameters, unless a MAC policy - * overrides it with an entitlement check. - */ - entitled = (mac_proc_check_cpumon(curp) == 0) ? TRUE : FALSE; + if (!canEnable && curp != proc) { + /* + * Can the current process change scheduling parameters for + * the target process? + */ + error = mac_proc_check_sched(curp, proc); + if (error) return error; + } #endif switch (action) { - uint8_t percentage; - case PROC_POLICY_ACTION_GET: error = proc_get_task_ruse_cpu(proc->task, &cpuattr.ppattr_cpu_attr, &percentage, @@ -274,13 +324,21 @@ handle_resourceuse(__unused int scope, __unused int action, __unused int policy, cpuattr.ppattr_cpu_percentage, interval, cpuattr.ppattr_cpu_attr_deadline, - entitled); + privileged); break; + /* restore process to prior state */ case PROC_POLICY_ACTION_RESTORE: - error = proc_clear_task_ruse_cpu(proc->task, entitled); + error = proc_clear_task_ruse_cpu(proc->task, privileged); break; + /* re-enable suspended monitor */ + case PROC_POLICY_ACTION_ENABLE: + error = task_resume_cpumon(proc->task); + break; + + case PROC_POLICY_ACTION_REMOVE: + default: error = EINVAL; break; @@ -290,6 +348,78 @@ handle_resourceuse(__unused int scope, __unused int action, __unused int policy, return(error); } +#if CONFIG_EMBEDDED +static int +handle_applifecycle(__unused int scope, + int action, + __unused int policy, + int policy_subtype, + user_addr_t attrp, + proc_t proc, + uint64_t target_threadid) +{ + int error = 0; + int state = 0; + + switch(policy_subtype) { + case PROC_POLICY_APPLIFE_NONE: + error = 0; + break; + + case PROC_POLICY_APPLIFE_STATE: + /* appstate is no longer supported */ + error = ENOTSUP; + break; + + case PROC_POLICY_APPLIFE_DEVSTATUS: +#if CONFIG_MACF + /* ToDo - this should be a generic check, since we could potentially hang other behaviours here. */ + error = mac_proc_check_suspend_resume(current_proc(), MAC_PROC_CHECK_HIBERNATE); + if (error) { + error = EPERM; + goto out; + } +#endif +#if CONFIG_MEMORYSTATUS + if (action == PROC_POLICY_ACTION_APPLY) { + /* Used as a freeze hint */ + memorystatus_on_inactivity(proc); + + /* in future use devicestatus for pid_socketshutdown() */ + error = 0; + } else +#endif + { + error = EINVAL; + } + break; + + case PROC_POLICY_APPLIFE_PIDBIND: +#if CONFIG_MACF + error = mac_proc_check_suspend_resume(current_proc(), MAC_PROC_CHECK_PIDBIND); + if (error) { + error = EPERM; + goto out; + } +#endif + error = copyin((user_addr_t)attrp, (int *)&state, sizeof(int)); + if (error != 0) + goto out; + if (action == PROC_POLICY_ACTION_APPLY) { + /* bind the thread in target_thread in current process to target_proc */ + error = proc_lf_pidbind(current_task(), target_threadid, proc->task, state); + } else + error = EINVAL; + break; + default: + error = EINVAL; + break; + } + +out: + return(error); +} +#endif /* CONFIG_EMBEDDED */ static int handle_apptype( int scope, @@ -325,7 +455,7 @@ handle_apptype( int scope, return (EINVAL); /* PROCESS ENABLE APPTYPE HOLDIMP */ - error = task_importance_hold_external_assertion(current_task(), 1); + error = task_importance_hold_legacy_external_assertion(current_task(), 1); return(error); @@ -336,7 +466,7 @@ handle_apptype( int scope, return (EINVAL); /* PROCESS ENABLE APPTYPE DROPIMP */ - error = task_importance_drop_external_assertion(current_task(), 1); + error = task_importance_drop_legacy_external_assertion(current_task(), 1); return(error); @@ -358,19 +488,18 @@ handle_apptype( int scope, switch (action) { case PROC_POLICY_ACTION_ENABLE: /* PROCESS ENABLE APPTYPE TAL */ - proc_set_task_policy(target_proc->task, THREAD_NULL, - TASK_POLICY_ATTRIBUTE, TASK_POLICY_TAL, - TASK_POLICY_ENABLE); + proc_set_task_policy(target_proc->task, + TASK_POLICY_ATTRIBUTE, TASK_POLICY_TAL, + TASK_POLICY_ENABLE); break; case PROC_POLICY_ACTION_DISABLE: /* PROCESS DISABLE APPTYPE TAL */ - proc_set_task_policy(target_proc->task, THREAD_NULL, - TASK_POLICY_ATTRIBUTE, TASK_POLICY_TAL, - TASK_POLICY_DISABLE); + proc_set_task_policy(target_proc->task, + TASK_POLICY_ATTRIBUTE, TASK_POLICY_TAL, + TASK_POLICY_DISABLE); break; default: return (EINVAL); - break; } return(0); @@ -397,17 +526,17 @@ handle_boost(int scope, switch(policy_subtype) { case PROC_POLICY_IMP_IMPORTANT: - if (task_is_importance_receiver(target_proc->task) == FALSE) + if (task_is_importance_receiver_type(target_proc->task) == FALSE) return (EINVAL); switch (action) { case PROC_POLICY_ACTION_HOLD: /* PROCESS HOLD BOOST IMPORTANT */ - error = task_importance_hold_external_assertion(current_task(), 1); + error = task_importance_hold_legacy_external_assertion(current_task(), 1); break; case PROC_POLICY_ACTION_DROP: /* PROCESS DROP BOOST IMPORTANT */ - error = task_importance_drop_external_assertion(current_task(), 1); + error = task_importance_drop_legacy_external_assertion(current_task(), 1); break; default: error = (EINVAL); @@ -469,6 +598,56 @@ proc_pidbackgrounded(pid_t pid, uint32_t* state) return (0); } +/* + * Get the darwin background state of the originator. If the current + * process app type is App, then it is the originator, else if it is + * a Daemon, then creator of the Resource Accounting attribute of + * the current thread voucher is the originator of the work. + */ +int +proc_get_originatorbgstate(uint32_t *is_backgrounded) +{ + uint32_t bgstate; + proc_t p = current_proc(); + uint32_t flagsp = 0; + kern_return_t kr; + pid_t pid; + int ret; + thread_t thread = current_thread(); + + bgstate = proc_get_effective_thread_policy(thread, TASK_POLICY_DARWIN_BG); + + /* If current thread or task backgrounded, return background */ + if (bgstate) { + *is_backgrounded = 1; + return 0; + } + + /* Check if current process app type is App, then return foreground */ + proc_get_darwinbgstate(p->task, &flagsp); + if ((flagsp & PROC_FLAG_APPLICATION) == PROC_FLAG_APPLICATION) { + *is_backgrounded = 0; + return 0; + } + + /* + * Get the current voucher origin pid and it's bgstate.The pid + * returned here might not be valid or may have been recycled. + */ + kr = thread_get_current_voucher_origin_pid(&pid); + if (kr != KERN_SUCCESS) { + if (kr == KERN_INVALID_TASK) + return ESRCH; + else if (kr == KERN_INVALID_VALUE) + return ENOATTR; + else + return EINVAL; + } + + ret = proc_pidbackgrounded(pid, is_backgrounded); + return ret; +} + int proc_apply_resource_actions(void * bsdinfo, __unused int type, int action) { @@ -499,7 +678,6 @@ proc_apply_resource_actions(void * bsdinfo, __unused int type, int action) return(0); } - int proc_restore_resource_actions(void * bsdinfo, __unused int type, int action) {