1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <lib/fdio/spawn.h> 6 7#include <fcntl.h> 8#include <fuchsia/process/c/fidl.h> 9#include <lib/fdio/io.h> 10#include <lib/fdio/limits.h> 11#include <lib/fdio/namespace.h> 12#include <lib/fdio/util.h> 13#include <stdarg.h> 14#include <stdio.h> 15#include <string.h> 16#include <unistd.h> 17#include <zircon/assert.h> 18#include <zircon/dlfcn.h> 19#include <zircon/process.h> 20#include <zircon/processargs.h> 21#include <zircon/syscalls.h> 22 23#define FDIO_SPAWN_LAUNCH_HANDLE_EXECUTABLE ((size_t)0u) 24#define FDIO_SPAWN_LAUNCH_HANDLE_JOB ((size_t)1u) 25#define FDIO_SPAWN_LAUNCH_HANDLE_COUNT ((size_t)2u) 26 27#define FDIO_SPAWN_LAUNCH_REPLY_HANDLE_COUNT ((size_t)1u) 28 29// Even though FDIO_MAX_HANDLES is 3, the clone and transfer operations can only 30// ever generate 2 handles. 31#define FDIO_MAX_HANDLES_FOR_CLONE_OR_TRANSFER ((size_t)2u) 32 33// The fdio_spawn_action_t is replicated in various ffi interfaces, including 34// the rust and golang standard libraries. 35static_assert(sizeof(fdio_spawn_action_t) == 24, 36 "fdio_spawn_action_t must have a stable ABI"); 37static_assert(offsetof(fdio_spawn_action_t, action) == 0, 38 "fdio_spawn_action_t must have a stable ABI"); 39static_assert(offsetof(fdio_spawn_action_t, fd) == 8, 40 "fdio_spawn_action_t must have a stable ABI"); 41static_assert(offsetof(fdio_spawn_action_t, fd.local_fd) == 8, 42 "fdio_spawn_action_t must have a stable ABI"); 43static_assert(offsetof(fdio_spawn_action_t, fd.target_fd) == 12, 44 "fdio_spawn_action_t must have a stable ABI"); 45static_assert(offsetof(fdio_spawn_action_t, ns) == 8, 46 "fdio_spawn_action_t must have a stable ABI"); 47static_assert(offsetof(fdio_spawn_action_t, ns.prefix) == 8, 48 "fdio_spawn_action_t must have a stable ABI"); 49static_assert(offsetof(fdio_spawn_action_t, ns.handle) == 16, 50 "fdio_spawn_action_t must have a stable ABI"); 51static_assert(offsetof(fdio_spawn_action_t, h) == 8, 52 "fdio_spawn_action_t must have a stable ABI"); 53static_assert(offsetof(fdio_spawn_action_t, h.id) == 8, 54 "fdio_spawn_action_t must have a stable ABI"); 55static_assert(offsetof(fdio_spawn_action_t, h.handle) == 12, 56 "fdio_spawn_action_t must have a stable ABI"); 57static_assert(offsetof(fdio_spawn_action_t, name) == 8, 58 "fdio_spawn_action_t must have a stable ABI"); 59static_assert(offsetof(fdio_spawn_action_t, name.data) == 8, 60 "fdio_spawn_action_t must have a stable ABI"); 61 62static zx_status_t load_path(const char* path, zx_handle_t* vmo) { 63 int fd = open(path, O_RDONLY); 64 if (fd < 0) 65 return ZX_ERR_IO; 66 zx_status_t status = fdio_get_vmo_clone(fd, vmo); 67 close(fd); 68 69 if (status == ZX_OK) { 70 if (strlen(path) >= ZX_MAX_NAME_LEN) { 71 const char* p = strrchr(path, '/'); 72 if (p != NULL) { 73 path = p + 1; 74 } 75 } 76 77 zx_object_set_property(*vmo, ZX_PROP_NAME, path, strlen(path)); 78 } 79 80 return status; 81} 82 83static void measure_string_array(const char* const* array, size_t* count_out, size_t* len_out) { 84 size_t i = 0; 85 size_t len = 0; 86 while (array[i]) { 87 len += FIDL_ALIGN(strlen(array[i])); 88 ++i; 89 } 90 *count_out = i; 91 *len_out = len; 92} 93 94static void report_error(char* err_msg, const char* format, ...) { 95 if (!err_msg) 96 return; 97 va_list args; 98 va_start(args, format); 99 vsnprintf(err_msg, FDIO_SPAWN_ERR_MSG_MAX_LENGTH, format, args); 100 va_end(args); 101} 102 103static zx_status_t send_string_array(zx_handle_t launcher, int ordinal, const char* const* array) { 104 size_t count = 0; 105 size_t len = 0; 106 107 // TODO(abarth): In principle, we should chunk array into separate 108 // messages if we exceed ZX_CHANNEL_MAX_MSG_BYTES. 109 measure_string_array(array, &count, &len); 110 111 if (count == 0) 112 return ZX_OK; 113 114 size_t msg_len = sizeof(fidl_message_header_t) + sizeof(fidl_vector_t) + count * sizeof(fidl_string_t) + FIDL_ALIGN(len); 115 uint8_t msg[msg_len]; 116 memset(msg, 0, msg_len); 117 118 fidl_message_header_t* hdr = (fidl_message_header_t*)msg; 119 fidl_vector_t* vector = (fidl_vector_t*)hdr + 1; 120 fidl_string_t* strings = (fidl_string_t*)(vector + 1); 121 uint8_t* payload = (uint8_t*)(strings + count); 122 123 hdr->ordinal = ordinal; 124 vector->count = count; 125 vector->data = (void*)FIDL_ALLOC_PRESENT; 126 127 size_t offset = 0; 128 for (size_t i = 0; i < count; ++i) { 129 size_t size = strlen(array[i]); 130 strings[i].size = size; 131 strings[i].data = (void*)FIDL_ALLOC_PRESENT; 132 memcpy(payload + offset, array[i], size); 133 offset += FIDL_ALIGN(size); 134 } 135 136 return zx_channel_write(launcher, 0, msg, msg_len, NULL, 0); 137} 138 139static zx_status_t send_handles(zx_handle_t launcher, size_t handle_capacity, 140 uint32_t flags, zx_handle_t job, size_t action_count, 141 const fdio_spawn_action_t* actions, char* err_msg) { 142 // TODO(abarth): In principle, we should chunk array into separate 143 // messages if we exceed ZX_CHANNEL_MAX_MSG_HANDLES. 144 145 size_t msg_capacity = sizeof(fuchsia_process_LauncherAddHandlesRequest) + FIDL_ALIGN(handle_capacity * sizeof(fuchsia_process_HandleInfo)); 146 uint8_t msg[msg_capacity]; 147 memset(msg, 0, msg_capacity); 148 149 fuchsia_process_LauncherAddHandlesRequest* req = (fuchsia_process_LauncherAddHandlesRequest*)msg; 150 fuchsia_process_HandleInfo* handle_infos = (fuchsia_process_HandleInfo*)(req + 1); 151 152 zx_handle_t handles[handle_capacity]; 153 154 memset(handles, 0, sizeof(handles)); 155 156 req->hdr.ordinal = fuchsia_process_LauncherAddHandlesOrdinal; 157 158 zx_status_t status = ZX_OK; 159 size_t h = 0; 160 size_t a = 0; 161 162 if ((flags & FDIO_SPAWN_CLONE_JOB) != 0) { 163 handle_infos[h].handle = FIDL_HANDLE_PRESENT; 164 handle_infos[h].id = PA_JOB_DEFAULT; 165 status = zx_handle_duplicate(job, ZX_RIGHT_SAME_RIGHTS, &handles[h++]); 166 if (status != ZX_OK) { 167 report_error(err_msg, "failed to duplicate job: %d", status); 168 goto cleanup; 169 } 170 } 171 172 if ((flags & FDIO_SPAWN_CLONE_LDSVC) != 0) { 173 handle_infos[h].handle = FIDL_HANDLE_PRESENT; 174 handle_infos[h].id = PA_LDSVC_LOADER; 175 status = dl_clone_loader_service(&handles[h++]); 176 if (status != ZX_OK) { 177 report_error(err_msg, "failed to clone library loader service: %d", status); 178 goto cleanup; 179 } 180 } 181 182 if ((flags & FDIO_SPAWN_CLONE_STDIO) != 0) { 183 for (int fd = 0; fd < 3; ++fd) { 184 zx_handle_t fdio_handles[FDIO_MAX_HANDLES]; 185 uint32_t fdio_types[FDIO_MAX_HANDLES]; 186 status = fdio_clone_fd(fd, fd, fdio_handles, fdio_types); 187 if (status == ZX_ERR_BAD_HANDLE) { 188 // This file descriptor is closed. We just skip it rather than 189 // generating an error. 190 continue; 191 } 192 if (status < ZX_OK) { 193 report_error(err_msg, "failed to clone fd %d: %d", fd, status); 194 goto cleanup; 195 } 196 ZX_ASSERT((size_t)status <= FDIO_MAX_HANDLES_FOR_CLONE_OR_TRANSFER); 197 for (int i = 0; i < status; ++i) { 198 handle_infos[h].handle = FIDL_HANDLE_PRESENT; 199 handle_infos[h].id = fdio_types[i]; 200 handles[h++] = fdio_handles[i]; 201 } 202 } 203 } 204 205 for (; a < action_count; ++a) { 206 zx_handle_t fdio_handles[FDIO_MAX_HANDLES]; 207 uint32_t fdio_types[FDIO_MAX_HANDLES]; 208 209 switch (actions[a].action) { 210 case FDIO_SPAWN_ACTION_CLONE_FD: 211 status = fdio_clone_fd(actions[a].fd.local_fd, actions[a].fd.target_fd, fdio_handles, fdio_types); 212 if (status < ZX_OK) { 213 report_error(err_msg, "failed to clone fd %d (action index %zu): %d", actions[a].fd.local_fd, a, status); 214 goto cleanup; 215 } 216 break; 217 case FDIO_SPAWN_ACTION_TRANSFER_FD: 218 status = fdio_transfer_fd(actions[a].fd.local_fd, actions[a].fd.target_fd, fdio_handles, fdio_types); 219 if (status < ZX_OK) { 220 report_error(err_msg, "failed to transfer fd %d (action index %zu): %d", actions[a].fd.local_fd, a, status); 221 goto cleanup; 222 } 223 break; 224 case FDIO_SPAWN_ACTION_ADD_HANDLE: 225 handle_infos[h].handle = FIDL_HANDLE_PRESENT; 226 handle_infos[h].id = actions[a].h.id; 227 handles[h++] = actions[a].h.handle; 228 continue; 229 default: 230 continue; 231 } 232 233 ZX_ASSERT((size_t)status <= FDIO_MAX_HANDLES_FOR_CLONE_OR_TRANSFER); 234 for (int j = 0; j < status; ++j) { 235 handle_infos[h].handle = FIDL_HANDLE_PRESENT; 236 handle_infos[h].id = fdio_types[j]; 237 handles[h++] = fdio_handles[j]; 238 } 239 } 240 241 req->handles.count = h; 242 req->handles.data = (void*)FIDL_ALLOC_PRESENT; 243 244 ZX_DEBUG_ASSERT(h <= handle_capacity); 245 246 size_t msg_len = sizeof(fuchsia_process_LauncherAddHandlesRequest) + FIDL_ALIGN(h * sizeof(fuchsia_process_HandleInfo)); 247 status = zx_channel_write(launcher, 0, msg, msg_len, handles, h); 248 249 if (status != ZX_OK) 250 report_error(err_msg, "failed send handles: %d", status); 251 252 return status; 253 254cleanup: 255 zx_handle_close_many(handles, h); 256 257 // If |a| is less than |action_count|, that means we encountered an error 258 // before we processed all the actions. We need to iterate through the rest 259 // of the table and close the file descriptors and handles that we're 260 // supposed to consume. 261 for (size_t i = a; i < action_count; ++i) { 262 switch (actions[i].action) { 263 case FDIO_SPAWN_ACTION_TRANSFER_FD: 264 close(actions[i].fd.local_fd); 265 break; 266 case FDIO_SPAWN_ACTION_ADD_HANDLE: 267 zx_handle_close(actions[i].h.handle); 268 break; 269 } 270 } 271 272 return status; 273} 274 275static zx_status_t send_namespace(zx_handle_t launcher, size_t name_count, size_t name_len, 276 fdio_flat_namespace_t* flat, size_t action_count, 277 const fdio_spawn_action_t* actions, char* err_msg) { 278 size_t msg_len = sizeof(fuchsia_process_LauncherAddNamesRequest) + FIDL_ALIGN(name_count * sizeof(fuchsia_process_NameInfo)) + FIDL_ALIGN(name_len); 279 uint8_t msg[msg_len]; 280 memset(msg, 0, msg_len); 281 282 fuchsia_process_LauncherAddNamesRequest* req = (fuchsia_process_LauncherAddNamesRequest*)msg; 283 fuchsia_process_NameInfo* names = (fuchsia_process_NameInfo*)(req + 1); 284 uint8_t* payload = (uint8_t*)(names + name_count); 285 286 zx_handle_t handles[name_count]; 287 288 memset(handles, 0, sizeof(handles)); 289 290 req->hdr.ordinal = fuchsia_process_LauncherAddNamesOrdinal; 291 req->names.count = name_count; 292 req->names.data = (void*)FIDL_ALLOC_PRESENT; 293 294 size_t n = 0; 295 size_t h = 0; 296 size_t offset = 0; 297 298 if (flat) { 299 while (n < flat->count) { 300 size_t size = strlen(flat->path[n]); 301 names[n].path.size = size; 302 names[n].path.data = (void*)FIDL_ALLOC_PRESENT; 303 names[n].directory = FIDL_HANDLE_PRESENT; 304 memcpy(payload + offset, flat->path[n], size); 305 offset += FIDL_ALIGN(size); 306 handles[h++] = flat->handle[n]; 307 n++; 308 } 309 } 310 311 for (size_t i = 0; i < action_count; ++i) { 312 if (actions[i].action == FDIO_SPAWN_ACTION_ADD_NS_ENTRY) { 313 size_t size = strlen(actions[i].ns.prefix); 314 names[n].path.size = size; 315 names[n].path.data = (void*)FIDL_ALLOC_PRESENT; 316 names[n].directory = FIDL_HANDLE_PRESENT; 317 memcpy(payload + offset, actions[i].ns.prefix, size); 318 offset += FIDL_ALIGN(size); 319 handles[h++] = actions[i].ns.handle; 320 n++; 321 } 322 } 323 324 ZX_DEBUG_ASSERT(n == name_count); 325 ZX_DEBUG_ASSERT(h == name_count); 326 327 zx_status_t status = zx_channel_write(launcher, 0, msg, msg_len, handles, h); 328 329 if (status != ZX_OK) 330 report_error(err_msg, "failed send namespace: %d", status); 331 332 return status; 333} 334 335__EXPORT 336zx_status_t fdio_spawn(zx_handle_t job, 337 uint32_t flags, 338 const char* path, 339 const char* const* argv, 340 zx_handle_t* process_out) { 341 return fdio_spawn_etc(job, flags, path, argv, NULL, 0, NULL, process_out, NULL); 342} 343 344__EXPORT 345zx_status_t fdio_spawn_etc(zx_handle_t job, 346 uint32_t flags, 347 const char* path, 348 const char* const* argv, 349 const char* const* explicit_environ, 350 size_t action_count, 351 const fdio_spawn_action_t* actions, 352 zx_handle_t* process_out, 353 char* err_msg) { 354 zx_handle_t executable_vmo = ZX_HANDLE_INVALID; 355 356 zx_status_t status = load_path(path, &executable_vmo); 357 if (status != ZX_OK) { 358 report_error(err_msg, "failed to load executable from %s", path); 359 // Set |err_msg| to NULL to prevent |fdio_spawn_vmo| from generating 360 // a less useful error message. 361 err_msg = NULL; 362 } 363 364 // Always call fdio_spawn_vmo to clean up arguments. If |executable_vmo| is 365 // |ZX_HANDLE_INVALID|, then |fdio_spawn_vmo| will generate an error. 366 zx_status_t spawn_status = fdio_spawn_vmo(job, flags, executable_vmo, argv, explicit_environ, 367 action_count, actions, process_out, err_msg); 368 369 // Use |status| if we already had an error before calling |fdio_spawn_vmo|. 370 // Otherwise, we'll always return |ZX_ERR_INVALID_ARGS| rather than the more 371 // useful status from |load_path|. 372 return status != ZX_OK ? status : spawn_status; 373} 374 375__EXPORT 376zx_status_t fdio_spawn_vmo(zx_handle_t job, 377 uint32_t flags, 378 zx_handle_t executable_vmo, 379 const char* const* argv, 380 const char* const* explicit_environ, 381 size_t action_count, 382 const fdio_spawn_action_t* actions, 383 zx_handle_t* process_out, 384 char* err_msg) { 385 zx_status_t status = ZX_OK; 386 fdio_flat_namespace_t* flat = NULL; 387 size_t name_count = 0; 388 size_t name_len = 0; 389 size_t handle_capacity = 0; 390 zx_handle_t launcher = ZX_HANDLE_INVALID; 391 zx_handle_t launcher_request = ZX_HANDLE_INVALID; 392 zx_handle_t msg_handles[FDIO_SPAWN_LAUNCH_HANDLE_COUNT]; 393 394 memset(msg_handles, 0, sizeof(msg_handles)); 395 396 if (err_msg) 397 err_msg[0] = '\0'; 398 399 if (executable_vmo == ZX_HANDLE_INVALID || !argv || (action_count != 0 && !actions)) { 400 status = ZX_ERR_INVALID_ARGS; 401 goto cleanup; 402 } 403 404 if (job == ZX_HANDLE_INVALID) 405 job = zx_job_default(); 406 407 const char* process_name = argv[0]; 408 409 for (size_t i = 0; i < action_count; ++i) { 410 switch (actions[i].action) { 411 case FDIO_SPAWN_ACTION_CLONE_FD: 412 case FDIO_SPAWN_ACTION_TRANSFER_FD: 413 handle_capacity += FDIO_MAX_HANDLES_FOR_CLONE_OR_TRANSFER; 414 break; 415 case FDIO_SPAWN_ACTION_ADD_NS_ENTRY: 416 if (actions[i].ns.handle == ZX_HANDLE_INVALID || !actions[i].ns.prefix) { 417 status = ZX_ERR_INVALID_ARGS; 418 goto cleanup; 419 } 420 ++name_count; 421 name_len += FIDL_ALIGN(strlen(actions[i].ns.prefix)); 422 break; 423 case FDIO_SPAWN_ACTION_ADD_HANDLE: 424 if (actions[i].h.handle == ZX_HANDLE_INVALID) { 425 status = ZX_ERR_INVALID_ARGS; 426 goto cleanup; 427 } 428 ++handle_capacity; 429 break; 430 case FDIO_SPAWN_ACTION_SET_NAME: 431 if (actions[i].name.data == NULL) { 432 status = ZX_ERR_INVALID_ARGS; 433 goto cleanup; 434 } 435 process_name = actions[i].name.data; 436 break; 437 default: 438 break; 439 } 440 } 441 442 if (!process_name) { 443 status = ZX_ERR_INVALID_ARGS; 444 goto cleanup; 445 } 446 447 if ((flags & FDIO_SPAWN_CLONE_JOB) != 0) 448 ++handle_capacity; 449 450 if ((flags & FDIO_SPAWN_CLONE_LDSVC) != 0) 451 ++handle_capacity; 452 453 if ((flags & FDIO_SPAWN_CLONE_STDIO) != 0) 454 handle_capacity += 3 * FDIO_MAX_HANDLES_FOR_CLONE_OR_TRANSFER; 455 456 if ((flags & FDIO_SPAWN_CLONE_NAMESPACE) != 0) { 457 status = fdio_ns_export_root(&flat); 458 name_count += flat->count; 459 for (size_t i = 0; i < flat->count; ++i) { 460 name_len += FIDL_ALIGN(strlen(flat->path[i])); 461 } 462 } 463 464 status = zx_channel_create(0, &launcher, &launcher_request); 465 if (status != ZX_OK) { 466 report_error(err_msg, "failed to create channel for process launcher: %d", status); 467 goto cleanup; 468 } 469 470 status = fdio_service_connect("/svc/fuchsia.process.Launcher", launcher_request); 471 launcher_request = ZX_HANDLE_INVALID; 472 if (status != ZX_OK) { 473 report_error(err_msg, "failed to connect to launcher service: %d", status); 474 goto cleanup; 475 } 476 477 status = send_string_array(launcher, fuchsia_process_LauncherAddArgsOrdinal, argv); 478 if (status != ZX_OK) { 479 report_error(err_msg, "failed to send argument vector: %d", status); 480 goto cleanup; 481 } 482 483 if (explicit_environ) { 484 status = send_string_array(launcher, fuchsia_process_LauncherAddEnvironsOrdinal, explicit_environ); 485 if (status != ZX_OK) { 486 report_error(err_msg, "failed to send environment: %d", status); 487 goto cleanup; 488 } 489 } else if ((flags & FDIO_SPAWN_CLONE_ENVIRON) != 0) { 490 status = send_string_array(launcher, fuchsia_process_LauncherAddEnvironsOrdinal, (const char* const*)environ); 491 if (status != ZX_OK) { 492 report_error(err_msg, "failed to send environment clone with FDIO_SPAWN_CLONE_ENVIRON: %d", status); 493 goto cleanup; 494 } 495 } 496 497 if (handle_capacity) { 498 status = send_handles(launcher, handle_capacity, flags, job, action_count, actions, err_msg); 499 if (status != ZX_OK) { 500 // When |send_handles| fails, it consumes all the action handles 501 // that it knows about, but it doesn't consume the handles used for 502 // |FDIO_SPAWN_ACTION_ADD_NS_ENTRY|. 503 504 for (size_t i = 0; i < action_count; ++i) { 505 switch (actions[i].action) { 506 case FDIO_SPAWN_ACTION_ADD_NS_ENTRY: 507 zx_handle_close(actions[i].ns.handle); 508 break; 509 default: 510 break; 511 } 512 } 513 514 action_count = 0; // We've now consumed all the handles. 515 goto cleanup; 516 } 517 } 518 519 if (name_count) { 520 status = send_namespace(launcher, name_count, name_len, flat, action_count, actions, err_msg); 521 if (status != ZX_OK) { 522 action_count = 0; 523 goto cleanup; 524 } 525 } 526 527 action_count = 0; // We've consumed all the actions at this point. 528 529 size_t process_name_size = strlen(process_name); 530 if (process_name_size >= ZX_MAX_NAME_LEN) 531 process_name_size = ZX_MAX_NAME_LEN - 1; 532 533 { 534 535 struct { 536 FIDL_ALIGNDECL 537 fuchsia_process_LauncherLaunchRequest req; 538 uint8_t process_name[FIDL_ALIGN(ZX_MAX_NAME_LEN)]; 539 } msg; 540 541 memset(&msg, 0, sizeof(msg)); 542 size_t msg_len = sizeof(fuchsia_process_LauncherLaunchRequest) + FIDL_ALIGN(process_name_size); 543 544 msg.req.hdr.ordinal = fuchsia_process_LauncherLaunchOrdinal; 545 msg.req.info.executable = FIDL_HANDLE_PRESENT; 546 msg.req.info.job = FIDL_HANDLE_PRESENT; 547 msg.req.info.name.size = process_name_size; 548 msg.req.info.name.data = (void*)FIDL_ALLOC_PRESENT; 549 memcpy(msg.process_name, process_name, process_name_size); 550 551 msg_handles[FDIO_SPAWN_LAUNCH_HANDLE_EXECUTABLE] = executable_vmo; 552 executable_vmo = ZX_HANDLE_INVALID; 553 554 status = zx_handle_duplicate(job, ZX_RIGHT_SAME_RIGHTS, &msg_handles[FDIO_SPAWN_LAUNCH_HANDLE_JOB]); 555 if (status != ZX_OK) { 556 report_error(err_msg, "failed to duplicate job handle: %d", status); 557 goto cleanup; 558 } 559 560 struct { 561 FIDL_ALIGNDECL 562 fuchsia_process_LauncherLaunchResponse rsp; 563 uint8_t err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; 564 } reply; 565 566 zx_handle_t process = ZX_HANDLE_INVALID; 567 568 memset(&reply, 0, sizeof(reply)); 569 570 zx_channel_call_args_t args; 571 args.wr_bytes = &msg; 572 args.wr_handles = msg_handles; 573 args.rd_bytes = &reply; 574 args.rd_handles = &process; 575 args.wr_num_bytes = msg_len; 576 args.wr_num_handles = FDIO_SPAWN_LAUNCH_HANDLE_COUNT; 577 args.rd_num_bytes = sizeof(reply); 578 args.rd_num_handles = FDIO_SPAWN_LAUNCH_REPLY_HANDLE_COUNT; 579 580 uint32_t actual_bytes = 0; 581 uint32_t actual_handles = 0; 582 583 status = zx_channel_call(launcher, 0, ZX_TIME_INFINITE, &args, 584 &actual_bytes, &actual_handles); 585 586 // zx_channel_call always consumes handles. 587 memset(msg_handles, 0, sizeof(msg_handles)); 588 589 if (status != ZX_OK) { 590 report_error(err_msg, "failed to send launch message: %d", status); 591 goto cleanup; 592 } 593 594 status = reply.rsp.result.status; 595 596 if (status == ZX_OK) { 597 // The launcher claimed to succeed but didn't actually give us a 598 // process handle. Something is wrong with the launcher. 599 if (process == ZX_HANDLE_INVALID) { 600 status = ZX_ERR_BAD_HANDLE; 601 report_error(err_msg, "failed receive process handle"); 602 // This jump skips over closing the process handle, but that's 603 // fine because we didn't receive a process handle. 604 goto cleanup; 605 } 606 607 if (process_out) { 608 *process_out = process; 609 process = ZX_HANDLE_INVALID; 610 } 611 } else { 612 if (err_msg) { 613 size_t n = reply.rsp.result.error_message.size; 614 if (n >= FDIO_SPAWN_ERR_MSG_MAX_LENGTH) 615 n = FDIO_SPAWN_ERR_MSG_MAX_LENGTH - 1; 616 memcpy(err_msg, reply.err_msg, n); 617 err_msg[n] = '\0'; 618 } 619 } 620 621 if (process != ZX_HANDLE_INVALID) 622 zx_handle_close(process); 623 } 624 625cleanup: 626 if (actions) { 627 for (size_t i = 0; i < action_count; ++i) { 628 switch (actions[i].action) { 629 case FDIO_SPAWN_ACTION_ADD_NS_ENTRY: 630 zx_handle_close(actions[i].ns.handle); 631 break; 632 case FDIO_SPAWN_ACTION_ADD_HANDLE: 633 zx_handle_close(actions[i].h.handle); 634 break; 635 default: 636 break; 637 } 638 } 639 } 640 641 free(flat); 642 643 if (executable_vmo != ZX_HANDLE_INVALID) 644 zx_handle_close(executable_vmo); 645 646 if (launcher != ZX_HANDLE_INVALID) 647 zx_handle_close(launcher); 648 649 if (launcher_request != ZX_HANDLE_INVALID) 650 zx_handle_close(launcher_request); 651 652 if (msg_handles[FDIO_SPAWN_LAUNCH_HANDLE_EXECUTABLE] != ZX_HANDLE_INVALID) 653 zx_handle_close(msg_handles[FDIO_SPAWN_LAUNCH_HANDLE_EXECUTABLE]); 654 655 if (msg_handles[FDIO_SPAWN_LAUNCH_HANDLE_JOB] != ZX_HANDLE_INVALID) 656 zx_handle_close(msg_handles[FDIO_SPAWN_LAUNCH_HANDLE_JOB]); 657 658 return status; 659} 660