1/* 2 * Copyright (c) 2005, 2010 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29/* 30 * process policy syscall implementation 31 */ 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/kernel.h> 36#include <sys/malloc.h> 37#include <sys/proc_internal.h> 38#include <sys/proc.h> 39#include <sys/kauth.h> 40#include <sys/unistd.h> 41#include <sys/buf.h> 42#include <sys/ioctl.h> 43#include <sys/vm.h> 44#include <sys/user.h> 45 46#include <security/audit/audit.h> 47 48#include <mach/machine.h> 49#include <mach/mach_types.h> 50#include <mach/vm_param.h> 51#include <kern/task.h> 52#include <kern/lock.h> 53#include <kern/kalloc.h> 54#include <kern/assert.h> 55#include <vm/vm_kern.h> 56#include <vm/vm_map.h> 57#include <mach/host_info.h> 58#include <mach/task_info.h> 59#include <mach/thread_info.h> 60#include <mach/vm_region.h> 61 62#include <sys/process_policy.h> 63#include <sys/proc_info.h> 64#include <sys/bsdtask_info.h> 65#include <sys/kdebug.h> 66#include <sys/sysproto.h> 67#include <sys/msgbuf.h> 68 69#include <machine/machine_routines.h> 70 71#include <kern/ipc_misc.h> 72#include <vm/vm_protos.h> 73 74static int handle_lowresource(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid); 75static int handle_resourceuse(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid); 76static int handle_apptype(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid); 77static int handle_boost(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid); 78 79extern kern_return_t task_suspend(task_t); 80extern kern_return_t task_resume(task_t); 81 82 83/***************************** process_policy ********************/ 84 85/* 86 *int process_policy(int scope, int action, int policy, int policy_subtype, 87 * proc_policy_attribute_t * attrp, pid_t target_pid, 88 * uint64_t target_threadid) 89 *{ int process_policy(int scope, int action, int policy, int policy_subtype, 90 * user_addr_t attrp, pid_t target_pid, uint64_t target_threadid); } 91 */ 92 93/* system call implementation */ 94int 95process_policy(__unused struct proc *p, struct process_policy_args * uap, __unused int32_t *retval) 96{ 97 int error = 0; 98 int scope = uap->scope; 99 int policy = uap->policy; 100 int action = uap->action; 101 int policy_subtype = uap->policy_subtype; 102 user_addr_t attrp = uap->attrp; 103 pid_t target_pid = uap->target_pid; 104 uint64_t target_threadid = uap->target_threadid; 105 proc_t target_proc = PROC_NULL; 106 proc_t curp = current_proc(); 107 kauth_cred_t my_cred; 108 109 if ((scope != PROC_POLICY_SCOPE_PROCESS) && (scope != PROC_POLICY_SCOPE_THREAD)) { 110 return(EINVAL); 111 } 112 113 if (target_pid == 0 || target_pid == proc_selfpid()) 114 target_proc = proc_self(); 115 else 116 target_proc = proc_find(target_pid); 117 118 if (target_proc == PROC_NULL) 119 return(ESRCH); 120 121 my_cred = kauth_cred_get(); 122 123 /* 124 * Resoure starvation control can be used by unpriv resource owner but priv at the time of ownership claim. This is 125 * checked in low resource handle routine. So bypass the checks here. 126 */ 127 if ((policy != PROC_POLICY_RESOURCE_STARVATION) && 128 (policy != PROC_POLICY_APPTYPE) && 129 (!kauth_cred_issuser(my_cred) && curp != p)) 130 { 131 error = EPERM; 132 goto out; 133 } 134 135#if CONFIG_MACF 136 switch (policy) { 137 case PROC_POLICY_BOOST: 138 case PROC_POLICY_RESOURCE_USAGE: 139 /* These policies do their own appropriate mac checks */ 140 break; 141 default: 142 error = mac_proc_check_sched(curp, target_proc); 143 if (error) goto out; 144 break; 145 } 146#endif /* CONFIG_MACF */ 147 148 switch(policy) { 149 case PROC_POLICY_BACKGROUND: 150 error = ENOTSUP; 151 break; 152 case PROC_POLICY_HARDWARE_ACCESS: 153 error = ENOTSUP; 154 break; 155 case PROC_POLICY_RESOURCE_STARVATION: 156 error = handle_lowresource(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); 157 break; 158 case PROC_POLICY_RESOURCE_USAGE: 159 error = handle_resourceuse(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); 160 break; 161 case PROC_POLICY_APPTYPE: 162 error = handle_apptype(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); 163 break; 164 case PROC_POLICY_BOOST: 165 error = handle_boost(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); 166 break; 167 default: 168 error = EINVAL; 169 break; 170 } 171 172out: 173 proc_rele(target_proc); 174 return(error); 175} 176 177static int 178handle_lowresource(__unused int scope, int action, __unused int policy, int policy_subtype, __unused user_addr_t attrp, proc_t proc, __unused uint64_t target_threadid) 179{ 180 int error = 0; 181 182 switch(policy_subtype) { 183 case PROC_POLICY_RS_NONE: 184 case PROC_POLICY_RS_VIRTUALMEM: 185 break; 186 default: 187 return(EINVAL); 188 } 189 190 if (action == PROC_POLICY_ACTION_RESTORE) 191 error = proc_resetpcontrol(proc_pid(proc)); 192 else 193 error = EINVAL; 194 195 return(error); 196} 197 198 199static int 200handle_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) 201{ 202 proc_policy_cpuusage_attr_t cpuattr; 203#if CONFIG_MACF 204 proc_t curp = current_proc(); 205#endif 206 int entitled = TRUE; 207 uint64_t interval = -1ULL; 208 int error = 0; 209 210 switch(policy_subtype) { 211 case PROC_POLICY_RUSAGE_NONE: 212 case PROC_POLICY_RUSAGE_WIREDMEM: 213 case PROC_POLICY_RUSAGE_VIRTMEM: 214 case PROC_POLICY_RUSAGE_DISK: 215 case PROC_POLICY_RUSAGE_NETWORK: 216 case PROC_POLICY_RUSAGE_POWER: 217 return(ENOTSUP); 218 break; 219 default: 220 return(EINVAL); 221 case PROC_POLICY_RUSAGE_CPU: 222 break; 223 } 224 225#if CONFIG_MACF 226 if (curp != proc) { 227 /* the cpumon entitlement manages messing with CPU limits on self */ 228 error = mac_proc_check_sched(curp, proc); 229 if (error) 230 return error; 231 } 232 233 /* 234 * Allow a process to change CPU usage monitor parameters, unless a MAC policy 235 * overrides it with an entitlement check. 236 */ 237 entitled = (mac_proc_check_cpumon(curp) == 0) ? TRUE : FALSE; 238#endif 239 240 switch (action) { 241 uint8_t percentage; 242 243 case PROC_POLICY_ACTION_GET: 244 error = proc_get_task_ruse_cpu(proc->task, &cpuattr.ppattr_cpu_attr, 245 &percentage, 246 &cpuattr.ppattr_cpu_attr_interval, 247 &cpuattr.ppattr_cpu_attr_deadline); 248 if (error == 0) { 249 cpuattr.ppattr_cpu_percentage = percentage; 250 cpuattr.ppattr_cpu_attr_interval /= NSEC_PER_SEC; 251 error = copyout((proc_policy_cpuusage_attr_t *)&cpuattr, (user_addr_t)attrp, sizeof(proc_policy_cpuusage_attr_t)); 252 } 253 break; 254 255 case PROC_POLICY_ACTION_APPLY: 256 case PROC_POLICY_ACTION_SET: 257 error = copyin((user_addr_t)attrp, (proc_policy_cpuusage_attr_t *)&cpuattr, sizeof(proc_policy_cpuusage_attr_t)); 258 if (error != 0) { 259 return (error); 260 } 261 262 /* 263 * The process_policy API uses seconds as the units for the interval, 264 * but the mach task policy SPI uses nanoseconds. Do the conversion, 265 * but preserve -1 as it has special meaning. 266 */ 267 if (cpuattr.ppattr_cpu_attr_interval != -1ULL) { 268 interval = cpuattr.ppattr_cpu_attr_interval * NSEC_PER_SEC; 269 } else { 270 interval = -1ULL; 271 } 272 273 error = proc_set_task_ruse_cpu(proc->task, cpuattr.ppattr_cpu_attr, 274 cpuattr.ppattr_cpu_percentage, 275 interval, 276 cpuattr.ppattr_cpu_attr_deadline, 277 entitled); 278 break; 279 280 case PROC_POLICY_ACTION_RESTORE: 281 error = proc_clear_task_ruse_cpu(proc->task, entitled); 282 break; 283 284 default: 285 error = EINVAL; 286 break; 287 288 } 289 290 return(error); 291} 292 293 294static int 295handle_apptype( int scope, 296 int action, 297 __unused int policy, 298 int policy_subtype, 299 __unused user_addr_t attrp, 300 proc_t target_proc, 301 __unused uint64_t target_threadid) 302{ 303 int error = 0; 304 305 if (scope != PROC_POLICY_SCOPE_PROCESS) 306 return (EINVAL); 307 308 /* Temporary compatibility with old importance donation interface until libproc is moved to new boost calls */ 309 switch (policy_subtype) { 310 case PROC_POLICY_IOS_DONATEIMP: 311 if (action != PROC_POLICY_ACTION_ENABLE) 312 return (EINVAL); 313 if (target_proc != current_proc()) 314 return (EINVAL); 315 316 /* PROCESS ENABLE APPTYPE DONATEIMP */ 317 task_importance_mark_donor(target_proc->task, TRUE); 318 319 return(0); 320 321 case PROC_POLICY_IOS_HOLDIMP: 322 if (action != PROC_POLICY_ACTION_ENABLE) 323 return (EINVAL); 324 if (target_proc != current_proc()) 325 return (EINVAL); 326 327 /* PROCESS ENABLE APPTYPE HOLDIMP */ 328 error = task_importance_hold_external_assertion(current_task(), 1); 329 330 return(error); 331 332 case PROC_POLICY_IOS_DROPIMP: 333 if (action != PROC_POLICY_ACTION_ENABLE) 334 return (EINVAL); 335 if (target_proc != current_proc()) 336 return (EINVAL); 337 338 /* PROCESS ENABLE APPTYPE DROPIMP */ 339 error = task_importance_drop_external_assertion(current_task(), 1); 340 341 return(error); 342 343 default: 344 /* continue to TAL handling */ 345 break; 346 } 347 348 if (policy_subtype != PROC_POLICY_OSX_APPTYPE_TAL) 349 return (EINVAL); 350 351 /* need to be super user to do this */ 352 if (kauth_cred_issuser(kauth_cred_get()) == 0) 353 return (EPERM); 354 355 if (proc_task_is_tal(target_proc->task) == FALSE) 356 return (EINVAL); 357 358 switch (action) { 359 case PROC_POLICY_ACTION_ENABLE: 360 /* PROCESS ENABLE APPTYPE TAL */ 361 proc_set_task_policy(target_proc->task, THREAD_NULL, 362 TASK_POLICY_ATTRIBUTE, TASK_POLICY_TAL, 363 TASK_POLICY_ENABLE); 364 break; 365 case PROC_POLICY_ACTION_DISABLE: 366 /* PROCESS DISABLE APPTYPE TAL */ 367 proc_set_task_policy(target_proc->task, THREAD_NULL, 368 TASK_POLICY_ATTRIBUTE, TASK_POLICY_TAL, 369 TASK_POLICY_DISABLE); 370 break; 371 default: 372 return (EINVAL); 373 break; 374 } 375 376 return(0); 377} 378 379static int 380handle_boost(int scope, 381 int action, 382 __unused int policy, 383 int policy_subtype, 384 __unused user_addr_t attrp, 385 proc_t target_proc, 386 __unused uint64_t target_threadid) 387{ 388 int error = 0; 389 390 assert(policy == PROC_POLICY_BOOST); 391 392 if (scope != PROC_POLICY_SCOPE_PROCESS) 393 return (EINVAL); 394 395 if (target_proc != current_proc()) 396 return (EINVAL); 397 398 switch(policy_subtype) { 399 case PROC_POLICY_IMP_IMPORTANT: 400 if (task_is_importance_receiver(target_proc->task) == FALSE) 401 return (EINVAL); 402 403 switch (action) { 404 case PROC_POLICY_ACTION_HOLD: 405 /* PROCESS HOLD BOOST IMPORTANT */ 406 error = task_importance_hold_external_assertion(current_task(), 1); 407 break; 408 case PROC_POLICY_ACTION_DROP: 409 /* PROCESS DROP BOOST IMPORTANT */ 410 error = task_importance_drop_external_assertion(current_task(), 1); 411 break; 412 default: 413 error = (EINVAL); 414 break; 415 } 416 break; 417 418 case PROC_POLICY_IMP_DONATION: 419#if CONFIG_MACF 420 error = mac_proc_check_sched(current_proc(), target_proc); 421 if (error) return error; 422#endif 423 switch (action) { 424 case PROC_POLICY_ACTION_SET: 425 /* PROCESS SET BOOST DONATION */ 426 task_importance_mark_donor(target_proc->task, TRUE); 427 break; 428 default: 429 error = (EINVAL); 430 break; 431 } 432 break; 433 434 default: 435 error = (EINVAL); 436 break; 437 } 438 439 return(error); 440} 441 442 443/* 444 * KPI to determine if a pid is currently backgrounded. 445 * Returns ESRCH if pid cannot be found or has started exiting. 446 * Returns EINVAL if state is NULL. 447 * Sets *state to 1 if pid is backgrounded, and 0 otherwise. 448 */ 449int 450proc_pidbackgrounded(pid_t pid, uint32_t* state) 451{ 452 proc_t target_proc = PROC_NULL; 453 454 if (state == NULL) 455 return(EINVAL); 456 457 target_proc = proc_find(pid); 458 459 if (target_proc == PROC_NULL) 460 return(ESRCH); 461 462 if ( proc_get_effective_task_policy(target_proc->task, TASK_POLICY_DARWIN_BG) ) { 463 *state = 1; 464 } else { 465 *state = 0; 466 } 467 468 proc_rele(target_proc); 469 return (0); 470} 471 472int 473proc_apply_resource_actions(void * bsdinfo, __unused int type, int action) 474{ 475 proc_t p = (proc_t)bsdinfo; 476 477 switch(action) { 478 case PROC_POLICY_RSRCACT_THROTTLE: 479 /* no need to do anything */ 480 break; 481 482 case PROC_POLICY_RSRCACT_SUSPEND: 483 task_suspend(p->task); 484 break; 485 486 case PROC_POLICY_RSRCACT_TERMINATE: 487 psignal(p, SIGKILL); 488 break; 489 490 case PROC_POLICY_RSRCACT_NOTIFY_KQ: 491 /* not implemented */ 492 break; 493 494 case PROC_POLICY_RSRCACT_NOTIFY_EXC: 495 panic("shouldn't be applying exception notification to process!"); 496 break; 497 } 498 499 return(0); 500} 501 502 503int 504proc_restore_resource_actions(void * bsdinfo, __unused int type, int action) 505{ 506 proc_t p = (proc_t)bsdinfo; 507 508 switch(action) { 509 case PROC_POLICY_RSRCACT_THROTTLE: 510 case PROC_POLICY_RSRCACT_TERMINATE: 511 case PROC_POLICY_RSRCACT_NOTIFY_KQ: 512 case PROC_POLICY_RSRCACT_NOTIFY_EXC: 513 /* no need to do anything */ 514 break; 515 516 case PROC_POLICY_RSRCACT_SUSPEND: 517 task_resume(p->task); 518 break; 519 520 } 521 522 return(0); 523} 524 525