1// Copyright 2016 The Fuchsia Authors 2// 3// Use of this source code is governed by a MIT-style 4// license that can be found in the LICENSE file or at 5// https://opensource.org/licenses/MIT 6 7#include <err.h> 8#include <inttypes.h> 9#include <platform.h> 10#include <stdint.h> 11#include <stdio.h> 12#include <stdlib.h> 13#include <string.h> 14#include <trace.h> 15 16#include <arch/arch_ops.h> 17 18#include <lib/ktrace.h> 19#include <lib/user_copy/user_ptr.h> 20#include <object/handle.h> 21#include <object/job_dispatcher.h> 22#include <object/process_dispatcher.h> 23#include <object/resource_dispatcher.h> 24#include <object/suspend_token_dispatcher.h> 25#include <object/thread_dispatcher.h> 26#include <object/vm_address_region_dispatcher.h> 27 28#include <fbl/auto_lock.h> 29#include <fbl/inline_array.h> 30#include <fbl/ref_ptr.h> 31#include <fbl/string_piece.h> 32#include <zircon/syscalls/debug.h> 33#include <zircon/syscalls/policy.h> 34 35#include "priv.h" 36 37#define LOCAL_TRACE 0 38#define THREAD_SET_PRIORITY_EXPERIMENT 1 39 40#if THREAD_SET_PRIORITY_EXPERIMENT 41#include <kernel/cmdline.h> 42#include <kernel/thread.h> 43#include <lk/init.h> 44#endif 45 46namespace { 47 48constexpr size_t kMaxDebugReadBlock = 64 * 1024u * 1024u; 49constexpr size_t kMaxDebugWriteBlock = 64 * 1024u * 1024u; 50 51// Assume the typical set-policy call has 8 items or less. 52constexpr size_t kPolicyBasicInlineCount = 8; 53 54#if THREAD_SET_PRIORITY_EXPERIMENT 55// This was initially set to false by default. See ZX-940 for the rationale 56// for being enabled by default. 57bool thread_set_priority_allowed = true; 58void thread_set_priority_experiment_init_hook(uint) { 59 thread_set_priority_allowed = !cmdline_get_bool("thread.set.priority.disable", false); 60 printf("thread set priority experiment is : %s\n", 61 thread_set_priority_allowed ? "ENABLED" : "DISABLED"); 62} 63LK_INIT_HOOK(thread_set_priority_experiment, 64 thread_set_priority_experiment_init_hook, 65 LK_INIT_LEVEL_THREADING - 1); 66#endif 67 68// TODO(ZX-1025): copy_user_string may truncate the incoming string, 69// and may copy extra data past the NUL. 70// TODO(dbort): If anyone else needs this, move it into user_ptr. 71zx_status_t copy_user_string(const user_in_ptr<const char>& src, 72 size_t src_len, 73 char* buf, size_t buf_len, 74 fbl::StringPiece* sp) { 75 if (!src || src_len > buf_len) { 76 return ZX_ERR_INVALID_ARGS; 77 } 78 zx_status_t result = src.copy_array_from_user(buf, src_len); 79 if (result != ZX_OK) { 80 return ZX_ERR_INVALID_ARGS; 81 } 82 83 // ensure zero termination 84 size_t str_len = (src_len == buf_len ? src_len - 1 : src_len); 85 buf[str_len] = 0; 86 *sp = fbl::StringPiece(buf); 87 88 return ZX_OK; 89} 90 91// Convenience function to go from process handle to process. 92zx_status_t get_process(ProcessDispatcher* up, 93 zx_handle_t proc_handle, 94 fbl::RefPtr<ProcessDispatcher>* proc) { 95 return up->GetDispatcherWithRights(proc_handle, ZX_RIGHT_WRITE, proc); 96} 97 98// This represents the local storage for thread_read/write_state. It should be large enough to 99// handle all structures passed over these APIs. 100union thread_state_local_buffer_t { 101 zx_thread_state_general_regs_t general_regs; // ZX_THREAD_STATE_GENERAL_REGS 102 zx_thread_state_fp_regs_t fp_regs; // ZX_THREAD_STATE_FP_REGS 103 zx_thread_state_vector_regs_t vector_regs; // ZX_THREAD_STATE_VECTOR_REGS 104 uint32_t single_step; // ZX_THREAD_STATE_SINGLE_STEP 105 uint64_t x86_register_fs; // ZX_THREAD_X86_REGISTER_FS; 106 uint64_t x86_register_gs; // ZX_THREAD_X86_REGISTER_GS; 107}; 108 109// Validates the input topic to thread_read_state and thread_write_state is a valid value, and 110// checks that the input buffer size is at least as large as necessary for the topic. On ZX_OK, the 111// actual size necessary for the buffer will be placed in the output parameter. 112zx_status_t validate_thread_state_input(uint32_t in_topic, size_t in_len, size_t* out_len) { 113 switch (in_topic) { 114 case ZX_THREAD_STATE_GENERAL_REGS: 115 *out_len = sizeof(zx_thread_state_general_regs_t); 116 break; 117 case ZX_THREAD_STATE_FP_REGS: 118 *out_len = sizeof(zx_thread_state_fp_regs_t); 119 break; 120 case ZX_THREAD_STATE_VECTOR_REGS: 121 *out_len = sizeof(zx_thread_state_vector_regs_t); 122 break; 123 case ZX_THREAD_STATE_SINGLE_STEP: 124 *out_len = sizeof(zx_thread_state_single_step_t); 125 break; 126 case ZX_THREAD_X86_REGISTER_FS: 127 *out_len = sizeof(zx_thread_x86_register_fs_t); 128 break; 129 case ZX_THREAD_X86_REGISTER_GS: 130 *out_len = sizeof(zx_thread_x86_register_gs_t); 131 break; 132 default: 133 return ZX_ERR_INVALID_ARGS; 134 } 135 136 if (in_len < *out_len) 137 return ZX_ERR_BUFFER_TOO_SMALL; 138 return ZX_OK; 139} 140 141} // namespace 142 143zx_status_t sys_thread_create(zx_handle_t process_handle, 144 user_in_ptr<const char> _name, size_t name_len, 145 uint32_t options, user_out_handle* out) { 146 LTRACEF("process handle %x, options %#x\n", process_handle, options); 147 148 // currently, the only valid option value is 0 149 if (options != 0) 150 return ZX_ERR_INVALID_ARGS; 151 152 // copy out the name 153 char buf[ZX_MAX_NAME_LEN]; 154 fbl::StringPiece sp; 155 // Silently truncate the given name. 156 if (name_len > sizeof(buf)) 157 name_len = sizeof(buf); 158 zx_status_t result = copy_user_string(_name, name_len, 159 buf, sizeof(buf), &sp); 160 if (result != ZX_OK) 161 return result; 162 LTRACEF("name %s\n", buf); 163 164 // convert process handle to process dispatcher 165 auto up = ProcessDispatcher::GetCurrent(); 166 167 fbl::RefPtr<ProcessDispatcher> process; 168 result = get_process(up, process_handle, &process); 169 if (result != ZX_OK) 170 return result; 171 172 uint32_t pid = (uint32_t)process->get_koid(); 173 174 // create the thread dispatcher 175 fbl::RefPtr<Dispatcher> thread_dispatcher; 176 zx_rights_t thread_rights; 177 result = ThreadDispatcher::Create(fbl::move(process), options, sp, 178 &thread_dispatcher, &thread_rights); 179 if (result != ZX_OK) 180 return result; 181 182 uint32_t tid = (uint32_t)thread_dispatcher->get_koid(); 183 ktrace(TAG_THREAD_CREATE, tid, pid, 0, 0); 184 ktrace_name(TAG_THREAD_NAME, tid, pid, buf); 185 186 return out->make(fbl::move(thread_dispatcher), thread_rights); 187} 188 189zx_status_t sys_thread_start(zx_handle_t thread_handle, zx_vaddr_t entry, 190 zx_vaddr_t stack, uintptr_t arg1, uintptr_t arg2) { 191 LTRACEF("handle %x, entry %#" PRIxPTR ", sp %#" PRIxPTR 192 ", arg1 %#" PRIxPTR ", arg2 %#" PRIxPTR "\n", 193 thread_handle, entry, stack, arg1, arg2); 194 195 auto up = ProcessDispatcher::GetCurrent(); 196 197 fbl::RefPtr<ThreadDispatcher> thread; 198 zx_status_t status = up->GetDispatcherWithRights(thread_handle, ZX_RIGHT_MANAGE_THREAD, 199 &thread); 200 if (status != ZX_OK) { 201 // Try again, but with the WRITE right. 202 // TODO(kulakowski) Remove this when all callers are using MANAGE_THREAD. 203 status = up->GetDispatcherWithRights(thread_handle, ZX_RIGHT_WRITE, &thread); 204 if (status != ZX_OK) 205 return status; 206 } 207 208 ktrace(TAG_THREAD_START, (uint32_t)thread->get_koid(), 0, 0, 0); 209 return thread->Start(entry, stack, arg1, arg2, /* initial_thread= */ false); 210} 211 212void sys_thread_exit() { 213 LTRACE_ENTRY; 214 ThreadDispatcher::GetCurrent()->Exit(); 215} 216 217zx_status_t sys_thread_read_state(zx_handle_t handle, uint32_t state_kind, 218 user_out_ptr<void> _buffer, size_t buffer_len) { 219 LTRACEF("handle %x, state_kind %u\n", handle, state_kind); 220 221 auto up = ProcessDispatcher::GetCurrent(); 222 223 // TODO(ZX-968): debug rights 224 fbl::RefPtr<ThreadDispatcher> thread; 225 zx_status_t status = up->GetDispatcherWithRights(handle, ZX_RIGHT_READ, &thread); 226 if (status != ZX_OK) 227 return status; 228 229 thread_state_local_buffer_t local_buffer; 230 size_t local_buffer_len = 0; 231 status = validate_thread_state_input(state_kind, buffer_len, &local_buffer_len); 232 if (status != ZX_OK) 233 return status; 234 235 status = thread->ReadState(static_cast<zx_thread_state_topic_t>(state_kind), &local_buffer, 236 local_buffer_len); 237 if (status != ZX_OK) 238 return status; 239 240 if (_buffer.copy_array_to_user(&local_buffer, local_buffer_len) != ZX_OK) 241 return ZX_ERR_INVALID_ARGS; 242 return ZX_OK; 243} 244 245zx_status_t sys_thread_write_state(zx_handle_t handle, uint32_t state_kind, 246 user_in_ptr<const void> _buffer, size_t buffer_len) { 247 LTRACEF("handle %x, state_kind %u\n", handle, state_kind); 248 249 auto up = ProcessDispatcher::GetCurrent(); 250 251 // TODO(ZX-968): debug rights 252 fbl::RefPtr<ThreadDispatcher> thread; 253 zx_status_t status = up->GetDispatcherWithRights(handle, ZX_RIGHT_WRITE, &thread); 254 if (status != ZX_OK) 255 return status; 256 257 thread_state_local_buffer_t local_buffer; 258 size_t local_buffer_len = 0; 259 status = validate_thread_state_input(state_kind, buffer_len, &local_buffer_len); 260 if (status != ZX_OK) 261 return status; 262 263 // Additionally check that the buffer is the exact size expected (validate only checks it's 264 // larger, which is sufficient for reading). 265 if (local_buffer_len != buffer_len) 266 return ZX_ERR_INVALID_ARGS; 267 268 status = _buffer.copy_array_from_user(&local_buffer, local_buffer_len); 269 if (status != ZX_OK) 270 return ZX_ERR_INVALID_ARGS; 271 272 return thread->WriteState(static_cast<zx_thread_state_topic_t>(state_kind), &local_buffer, 273 local_buffer_len); 274} 275 276// See ZX-940 277zx_status_t sys_thread_set_priority(int32_t prio) { 278#if THREAD_SET_PRIORITY_EXPERIMENT 279 // If the experimental zx_thread_set_priority has not been enabled using the 280 // kernel command line option, simply deny this request. 281 if (!thread_set_priority_allowed) 282 return ZX_ERR_NOT_SUPPORTED; 283 284 if ((prio < LOWEST_PRIORITY) || (prio > HIGHEST_PRIORITY)) 285 return ZX_ERR_INVALID_ARGS; 286 287 thread_set_priority(get_current_thread(), prio); 288 289 return ZX_OK; 290#else 291 return ZX_ERR_NOT_SUPPORTED; 292#endif 293} 294 295zx_status_t sys_task_suspend(zx_handle_t task_handle, user_out_handle* token) { 296 LTRACE_ENTRY; 297 298 auto up = ProcessDispatcher::GetCurrent(); 299 300 // TODO(ZX-1840): Add support for tasks other than threads 301 fbl::RefPtr<ThreadDispatcher> thread; 302 zx_status_t status = up->GetDispatcherWithRights(task_handle, ZX_RIGHT_WRITE, 303 &thread); 304 if (status != ZX_OK) 305 return status; 306 307 fbl::RefPtr<Dispatcher> suspend_token; 308 zx_rights_t rights; 309 status = SuspendTokenDispatcher::Create(fbl::move(thread), &suspend_token, &rights); 310 if (status == ZX_OK) 311 status = token->make(fbl::move(suspend_token), rights); 312 return status; 313} 314 315zx_status_t sys_task_suspend_token(zx_handle_t task_handle, user_out_handle* token) { 316 return sys_task_suspend(task_handle, token); 317} 318 319zx_status_t sys_process_create(zx_handle_t job_handle, 320 user_in_ptr<const char> _name, size_t name_len, 321 uint32_t options, 322 user_out_handle* proc_handle, 323 user_out_handle* vmar_handle) { 324 LTRACEF("job handle %x, options %#x\n", job_handle, options); 325 326 // currently, the only valid option value is 0 327 if (options != 0) 328 return ZX_ERR_INVALID_ARGS; 329 330 auto up = ProcessDispatcher::GetCurrent(); 331 332 // We check the policy against the process calling zx_process_create, which 333 // is the operative policy, rather than against |job_handle|. Access to 334 // |job_handle| is controlled by the rights associated with the handle. 335 zx_status_t result = up->QueryPolicy(ZX_POL_NEW_PROCESS); 336 if (result != ZX_OK) 337 return result; 338 339 // copy out the name 340 char buf[ZX_MAX_NAME_LEN]; 341 fbl::StringPiece sp; 342 // Silently truncate the given name. 343 if (name_len > sizeof(buf)) 344 name_len = sizeof(buf); 345 result = copy_user_string(_name, name_len, buf, sizeof(buf), &sp); 346 if (result != ZX_OK) 347 return result; 348 LTRACEF("name %s\n", buf); 349 350 fbl::RefPtr<JobDispatcher> job; 351 // TODO(ZX-968): define process creation job rights. 352 auto status = up->GetDispatcherWithRights(job_handle, ZX_RIGHT_WRITE, &job); 353 if (status != ZX_OK) 354 return status; 355 356 // create a new process dispatcher 357 fbl::RefPtr<Dispatcher> proc_dispatcher; 358 fbl::RefPtr<VmAddressRegionDispatcher> vmar_dispatcher; 359 zx_rights_t proc_rights, vmar_rights; 360 result = ProcessDispatcher::Create(fbl::move(job), sp, options, 361 &proc_dispatcher, &proc_rights, 362 &vmar_dispatcher, &vmar_rights); 363 if (result != ZX_OK) 364 return result; 365 366 uint32_t koid = (uint32_t)proc_dispatcher->get_koid(); 367 ktrace(TAG_PROC_CREATE, koid, 0, 0, 0); 368 ktrace_name(TAG_PROC_NAME, koid, 0, buf); 369 370 // Give arch-specific tracing a chance to record process creation. 371 arch_trace_process_create(koid, vmar_dispatcher->vmar()->aspace()->arch_aspace().arch_table_phys()); 372 373 result = proc_handle->make(fbl::move(proc_dispatcher), proc_rights); 374 if (result == ZX_OK) 375 result = vmar_handle->make(fbl::move(vmar_dispatcher), vmar_rights); 376 return result; 377} 378 379// Note: This is used to start the main thread (as opposed to using 380// sys_thread_start for that) for a few reasons: 381// - less easily exploitable 382// We want to make sure we can't generically transfer handles to a process. 383// This has the nice property of restricting the evil (transferring handle 384// to new process) to exactly one spot, and can be called exactly once per 385// process, since it also pushes it into a new state. 386// - maintains the state machine invariant that 'started' processes have one 387// thread running 388 389zx_status_t sys_process_start(zx_handle_t process_handle, zx_handle_t thread_handle, 390 zx_vaddr_t pc, zx_vaddr_t sp, 391 zx_handle_t arg_handle_value, uintptr_t arg2) { 392 LTRACEF("phandle %x, thandle %x, pc %#" PRIxPTR ", sp %#" PRIxPTR 393 ", arg_handle %x, arg2 %#" PRIxPTR "\n", 394 process_handle, thread_handle, pc, sp, arg_handle_value, arg2); 395 396 auto up = ProcessDispatcher::GetCurrent(); 397 398 // get process dispatcher 399 fbl::RefPtr<ProcessDispatcher> process; 400 zx_status_t status = get_process(up, process_handle, &process); 401 if (status != ZX_OK) { 402 up->RemoveHandle(arg_handle_value); 403 return status; 404 } 405 406 // get thread_dispatcher 407 fbl::RefPtr<ThreadDispatcher> thread; 408 status = up->GetDispatcherWithRights(thread_handle, ZX_RIGHT_WRITE, &thread); 409 if (status != ZX_OK) { 410 up->RemoveHandle(arg_handle_value); 411 return status; 412 } 413 414 HandleOwner arg_handle = up->RemoveHandle(arg_handle_value); 415 416 // test that the thread belongs to the starting process 417 if (thread->process() != process.get()) 418 return ZX_ERR_ACCESS_DENIED; 419 if (!arg_handle) 420 return ZX_ERR_BAD_HANDLE; 421 if (!arg_handle->HasRights(ZX_RIGHT_TRANSFER)) 422 return ZX_ERR_ACCESS_DENIED; 423 424 auto arg_nhv = process->MapHandleToValue(arg_handle); 425 process->AddHandle(fbl::move(arg_handle)); 426 427 status = thread->Start(pc, sp, static_cast<uintptr_t>(arg_nhv), 428 arg2, /* initial_thread */ true); 429 if (status != ZX_OK) { 430 // Remove |arg_handle| from the process that failed to start. 431 process->RemoveHandle(arg_nhv); 432 return status; 433 } 434 435 ktrace(TAG_PROC_START, (uint32_t)thread->get_koid(), 436 (uint32_t)process->get_koid(), 0, 0); 437 438 return ZX_OK; 439} 440 441void sys_process_exit(int64_t retcode) { 442 LTRACEF("retcode %" PRId64 "\n", retcode); 443 ProcessDispatcher::GetCurrent()->Exit(retcode); 444} 445 446zx_status_t sys_process_read_memory(zx_handle_t proc, zx_vaddr_t vaddr, 447 user_out_ptr<void> _buffer, 448 size_t len, user_out_ptr<size_t> _actual) { 449 LTRACEF("vaddr 0x%" PRIxPTR ", size %zu\n", vaddr, len); 450 451 if (!_buffer) 452 return ZX_ERR_INVALID_ARGS; 453 if (len == 0 || len > kMaxDebugReadBlock) 454 return ZX_ERR_INVALID_ARGS; 455 456 auto up = ProcessDispatcher::GetCurrent(); 457 458 fbl::RefPtr<ProcessDispatcher> process; 459 zx_status_t status = up->GetDispatcherWithRights(proc, ZX_RIGHT_READ | ZX_RIGHT_WRITE, 460 &process); 461 if (status != ZX_OK) 462 return status; 463 464 auto aspace = process->aspace(); 465 if (!aspace) 466 return ZX_ERR_BAD_STATE; 467 468 auto region = aspace->FindRegion(vaddr); 469 if (!region) 470 return ZX_ERR_NO_MEMORY; 471 472 auto vm_mapping = region->as_vm_mapping(); 473 if (!vm_mapping) 474 return ZX_ERR_NO_MEMORY; 475 476 auto vmo = vm_mapping->vmo(); 477 if (!vmo) 478 return ZX_ERR_NO_MEMORY; 479 480 // Force map the range, even if it crosses multiple mappings. 481 // TODO(ZX-730): This is a workaround for this bug. If we start decommitting 482 // things, the bug will come back. We should fix this more properly. 483 { 484 uint8_t byte = 0; 485 auto int_data = _buffer.reinterpret<uint8_t>(); 486 for (size_t i = 0; i < len; i += PAGE_SIZE) { 487 status = int_data.copy_array_to_user(&byte, 1, i); 488 if (status != ZX_OK) { 489 return status; 490 } 491 } 492 if (len > 0) { 493 status = int_data.copy_array_to_user(&byte, 1, len - 1); 494 if (status != ZX_OK) { 495 return status; 496 } 497 } 498 } 499 500 uint64_t offset = vaddr - vm_mapping->base() + vm_mapping->object_offset(); 501 // TODO(ZX-1631): While this limits reading to the mapped address space of 502 // this VMO, it should be reading from multiple VMOs, not a single one. 503 // Additionally, it is racy with the mapping going away. 504 len = MIN(len, vm_mapping->size() - (vaddr - vm_mapping->base())); 505 zx_status_t st = vmo->ReadUser(_buffer, offset, len); 506 507 if (st == ZX_OK) { 508 zx_status_t status = _actual.copy_to_user(static_cast<size_t>(len)); 509 if (status != ZX_OK) 510 return status; 511 } 512 return st; 513} 514 515zx_status_t sys_process_write_memory(zx_handle_t proc, zx_vaddr_t vaddr, 516 user_in_ptr<const void> _buffer, 517 size_t len, user_out_ptr<size_t> _actual) { 518 LTRACEF("vaddr 0x%" PRIxPTR ", size %zu\n", vaddr, len); 519 520 if (!_buffer) 521 return ZX_ERR_INVALID_ARGS; 522 if (len == 0 || len > kMaxDebugWriteBlock) 523 return ZX_ERR_INVALID_ARGS; 524 525 auto up = ProcessDispatcher::GetCurrent(); 526 527 fbl::RefPtr<ProcessDispatcher> process; 528 zx_status_t status = up->GetDispatcherWithRights(proc, ZX_RIGHT_WRITE, &process); 529 if (status != ZX_OK) 530 return status; 531 532 auto aspace = process->aspace(); 533 if (!aspace) 534 return ZX_ERR_BAD_STATE; 535 536 auto region = aspace->FindRegion(vaddr); 537 if (!region) 538 return ZX_ERR_NO_MEMORY; 539 540 auto vm_mapping = region->as_vm_mapping(); 541 if (!vm_mapping) 542 return ZX_ERR_NO_MEMORY; 543 544 auto vmo = vm_mapping->vmo(); 545 if (!vmo) 546 return ZX_ERR_NO_MEMORY; 547 548 // Force map the range, even if it crosses multiple mappings. 549 // TODO(ZX-730): This is a workaround for this bug. If we start decommitting 550 // things, the bug will come back. We should fix this more properly. 551 { 552 uint8_t byte = 0; 553 auto int_data = _buffer.reinterpret<const uint8_t>(); 554 for (size_t i = 0; i < len; i += PAGE_SIZE) { 555 status = int_data.copy_array_from_user(&byte, 1, i); 556 if (status != ZX_OK) { 557 return status; 558 } 559 } 560 if (len > 0) { 561 status = int_data.copy_array_from_user(&byte, 1, len - 1); 562 if (status != ZX_OK) { 563 return status; 564 } 565 } 566 } 567 568 uint64_t offset = vaddr - vm_mapping->base() + vm_mapping->object_offset(); 569 // TODO(ZX-1631): While this limits writing to the mapped address space of 570 // this VMO, it should be writing to multiple VMOs, not a single one. 571 // Additionally, it is racy with the mapping going away. 572 len = MIN(len, vm_mapping->size() - (vaddr - vm_mapping->base())); 573 zx_status_t st = vmo->WriteUser(_buffer, offset, len); 574 575 if (st == ZX_OK) { 576 zx_status_t status = _actual.copy_to_user(static_cast<size_t>(len)); 577 if (status != ZX_OK) 578 return status; 579 } 580 return st; 581} 582 583// helper routine for sys_task_kill 584template <typename T> 585static zx_status_t kill_task(fbl::RefPtr<Dispatcher> dispatcher) { 586 auto task = DownCastDispatcher<T>(&dispatcher); 587 if (!task) 588 return ZX_ERR_WRONG_TYPE; 589 590 task->Kill(); 591 return ZX_OK; 592} 593 594zx_status_t sys_task_kill(zx_handle_t task_handle) { 595 LTRACEF("handle %x\n", task_handle); 596 597 auto up = ProcessDispatcher::GetCurrent(); 598 599 fbl::RefPtr<Dispatcher> dispatcher; 600 auto status = up->GetDispatcherWithRights(task_handle, ZX_RIGHT_DESTROY, &dispatcher); 601 if (status != ZX_OK) 602 return status; 603 604 // see if it's a process or thread and dispatch accordingly 605 switch (dispatcher->get_type()) { 606 case ZX_OBJ_TYPE_PROCESS: 607 return kill_task<ProcessDispatcher>(fbl::move(dispatcher)); 608 case ZX_OBJ_TYPE_THREAD: 609 return kill_task<ThreadDispatcher>(fbl::move(dispatcher)); 610 case ZX_OBJ_TYPE_JOB: 611 return kill_task<JobDispatcher>(fbl::move(dispatcher)); 612 default: 613 return ZX_ERR_WRONG_TYPE; 614 } 615} 616 617zx_status_t sys_job_create(zx_handle_t parent_job, uint32_t options, 618 user_out_handle* out) { 619 LTRACEF("parent: %x\n", parent_job); 620 621 if (options != 0u) 622 return ZX_ERR_INVALID_ARGS; 623 624 auto up = ProcessDispatcher::GetCurrent(); 625 626 fbl::RefPtr<JobDispatcher> parent; 627 zx_status_t status = up->GetDispatcherWithRights(parent_job, ZX_RIGHT_MANAGE_JOB, &parent); 628 if (status != ZX_OK) { 629 // Try again, but with the WRITE right. 630 // TODO(kulakowski) Remove this when all callers are using MANAGE_JOB. 631 status = up->GetDispatcherWithRights(parent_job, ZX_RIGHT_WRITE, &parent); 632 if (status != ZX_OK) { 633 return status; 634 } 635 } 636 637 fbl::RefPtr<Dispatcher> job; 638 zx_rights_t rights; 639 status = JobDispatcher::Create(options, fbl::move(parent), &job, &rights); 640 if (status == ZX_OK) 641 status = out->make(fbl::move(job), rights); 642 return status; 643} 644 645zx_status_t sys_job_set_policy(zx_handle_t job_handle, uint32_t options, 646 uint32_t topic, user_in_ptr<const void> _policy, 647 uint32_t count) { 648 649 if ((options != ZX_JOB_POL_RELATIVE) && (options != ZX_JOB_POL_ABSOLUTE)) 650 return ZX_ERR_INVALID_ARGS; 651 if (!_policy || (count == 0u)) 652 return ZX_ERR_INVALID_ARGS; 653 654 if (topic != ZX_JOB_POL_BASIC) 655 return ZX_ERR_INVALID_ARGS; 656 657 fbl::AllocChecker ac; 658 fbl::InlineArray< 659 zx_policy_basic, kPolicyBasicInlineCount> 660 policy(&ac, count); 661 if (!ac.check()) 662 return ZX_ERR_NO_MEMORY; 663 664 auto status = _policy.copy_array_from_user(policy.get(), sizeof(zx_policy_basic) * count); 665 if (status != ZX_OK) 666 return ZX_ERR_INVALID_ARGS; 667 668 auto up = ProcessDispatcher::GetCurrent(); 669 670 fbl::RefPtr<JobDispatcher> job; 671 status = up->GetDispatcherWithRights(job_handle, ZX_RIGHT_SET_POLICY, &job); 672 if (status != ZX_OK) 673 return status; 674 675 return job->SetPolicy(options, policy.get(), policy.size()); 676} 677