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 <unittest/unittest.h> 6 7#include <fcntl.h> 8#include <lib/fdio/io.h> 9#include <lib/fdio/spawn.h> 10#include <lib/fdio/util.h> 11#include <lib/zx/channel.h> 12#include <lib/zx/job.h> 13#include <lib/zx/process.h> 14#include <lib/zx/socket.h> 15#include <stdlib.h> 16#include <unistd.h> 17#include <zircon/limits.h> 18#include <zircon/processargs.h> 19#include <zircon/syscalls/policy.h> 20 21static constexpr char kSpawnChild[] = "/boot/bin/spawn-child"; 22static constexpr char kSpawnLauncher[] = "/boot/bin/spawn-launcher"; 23 24static bool has_fd(int fd) { 25 zx_handle_t handles[FDIO_MAX_HANDLES]; 26 uint32_t ids[FDIO_MAX_HANDLES]; 27 zx_status_t status = fdio_clone_fd(fd, fd + 50, handles, ids); 28 if (status > 0) { 29 size_t n = static_cast<size_t>(status); 30 zx_handle_close_many(handles, n); 31 return true; 32 } 33 return false; 34} 35 36static int64_t join(const zx::process& process) { 37 zx_status_t status = process.wait_one(ZX_TASK_TERMINATED, zx::time::infinite(), nullptr); 38 ASSERT_EQ(ZX_OK, status); 39 zx_info_process_t proc_info{}; 40 status = process.get_info(ZX_INFO_PROCESS, &proc_info, sizeof(proc_info), nullptr, nullptr); 41 ASSERT_EQ(ZX_OK, status); 42 return proc_info.return_code; 43} 44 45static bool spawn_control_test(void) { 46 BEGIN_TEST; 47 48 zx_status_t status; 49 zx::process process; 50 51 { 52 const char* argv[] = {kSpawnChild, nullptr}; 53 status = fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 54 kSpawnChild, argv, process.reset_and_get_address()); 55 ASSERT_EQ(ZX_OK, status); 56 EXPECT_EQ(43, join(process)); 57 } 58 59 { 60 const char* argv[] = {kSpawnChild, "--argc", nullptr}; 61 status = fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 62 kSpawnChild, argv, process.reset_and_get_address()); 63 ASSERT_EQ(ZX_OK, status); 64 EXPECT_EQ(2, join(process)); 65 } 66 67 { 68 const char* argv[] = {kSpawnChild, "--argc", "three", "four", "five", nullptr}; 69 status = fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 70 kSpawnChild, argv, process.reset_and_get_address()); 71 ASSERT_EQ(ZX_OK, status); 72 EXPECT_EQ(5, join(process)); 73 } 74 75 END_TEST; 76} 77 78static bool spawn_launcher_test(void) { 79 BEGIN_TEST; 80 81 zx_status_t status; 82 zx::process process; 83 const char* argv[] = {kSpawnLauncher, kSpawnChild, nullptr}; 84 85 // Check that we can spawn the lancher process in a job and that the 86 // launcher process can launch the child. 87 { 88 zx::job job; 89 ASSERT_EQ(ZX_OK, zx::job::create(*zx::job::default_job(), 0, &job)); 90 91 status = fdio_spawn(job.get(), FDIO_SPAWN_CLONE_ALL, kSpawnLauncher, 92 argv, process.reset_and_get_address()); 93 ASSERT_EQ(ZX_OK, status); 94 EXPECT_EQ(43, join(process)); 95 ASSERT_EQ(ZX_OK, job.kill()); 96 } 97 98 // Check that setting |ZX_POL_NEW_PROCESS| to |ZX_POL_ACTION_DENY| prevents 99 // the launcher from launching the child. 100 { 101 zx::job job; 102 ASSERT_EQ(ZX_OK, zx::job::create(*zx::job::default_job(), 0, &job)); 103 zx_policy_basic_t policy = { 104 .condition = ZX_POL_NEW_PROCESS, 105 .policy = ZX_POL_ACTION_DENY, 106 }; 107 ASSERT_EQ(ZX_OK, job.set_policy(ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC, &policy, 1)); 108 109 status = fdio_spawn(job.get(), FDIO_SPAWN_CLONE_ALL, kSpawnLauncher, 110 argv, process.reset_and_get_address()); 111 ASSERT_EQ(ZX_OK, status); 112 EXPECT_EQ(401, join(process)); 113 ASSERT_EQ(ZX_OK, job.kill()); 114 } 115 116 END_TEST; 117} 118 119static bool spawn_invalid_args_test(void) { 120 BEGIN_TEST; 121 122 zx_status_t status; 123 zx::process process; 124 125 const char* argv[] = {kSpawnChild, nullptr}; 126 127 status = fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 128 "/bogus/not/a/file", argv, process.reset_and_get_address()); 129 ASSERT_EQ(ZX_ERR_IO, status); 130 131 status = fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 132 kSpawnChild, NULL, process.reset_and_get_address()); 133 ASSERT_EQ(ZX_ERR_INVALID_ARGS, status); 134 135 status = fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 136 kSpawnChild, argv + 1, process.reset_and_get_address()); 137 ASSERT_EQ(ZX_ERR_INVALID_ARGS, status); 138 139 END_TEST; 140} 141 142static bool spawn_flags_test(void) { 143 BEGIN_TEST; 144 145 zx_status_t status; 146 zx::process process; 147 148 { 149 // We can't actually launch a process without FDIO_SPAWN_CLONE_LDSVC 150 // because we can't load the PT_INTERP. 151 const char* argv[] = {kSpawnChild, "--flags", "none", nullptr}; 152 status = fdio_spawn(ZX_HANDLE_INVALID, 0, kSpawnChild, argv, 153 process.reset_and_get_address()); 154 ASSERT_EQ(ZX_ERR_INVALID_ARGS, status); 155 EXPECT_FALSE(process.is_valid()); 156 } 157 158 { 159 const char* argv[] = {kSpawnChild, "--flags", "none", nullptr}; 160 status = fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_LDSVC, 161 kSpawnChild, argv, process.reset_and_get_address()); 162 ASSERT_EQ(ZX_OK, status); 163 EXPECT_EQ(51, join(process)); 164 } 165 166 { 167 const char* argv[] = {kSpawnChild, "--flags", "job", nullptr}; 168 status = fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC, 169 kSpawnChild, argv, process.reset_and_get_address()); 170 ASSERT_EQ(ZX_OK, status); 171 EXPECT_EQ(52, join(process)); 172 } 173 174 { 175 const char* argv[] = {kSpawnChild, "--flags", "namespace", nullptr}; 176 status = fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE, 177 kSpawnChild, argv, process.reset_and_get_address()); 178 ASSERT_EQ(ZX_OK, status); 179 EXPECT_EQ(53, join(process)); 180 } 181 182 { 183 const char* argv[] = {kSpawnChild, "--flags", "stdio", nullptr}; 184 status = fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_STDIO, 185 kSpawnChild, argv, process.reset_and_get_address()); 186 ASSERT_EQ(ZX_OK, status); 187 EXPECT_EQ(54, join(process)); 188 } 189 190 { 191 const char* argv[] = {kSpawnChild, "--flags", "environ", nullptr}; 192 status = fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_ENVIRON, 193 kSpawnChild, argv, process.reset_and_get_address()); 194 ASSERT_EQ(ZX_OK, status); 195 EXPECT_EQ(55, join(process)); 196 } 197 198 { 199 const char* argv[] = {kSpawnChild, "--flags", "all", nullptr}; 200 status = fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 201 kSpawnChild, argv, process.reset_and_get_address()); 202 ASSERT_EQ(ZX_OK, status); 203 EXPECT_EQ(56, join(process)); 204 } 205 206 END_TEST; 207} 208 209static bool spawn_environ_test(void) { 210 BEGIN_TEST; 211 212 zx_status_t status; 213 zx::process process; 214 215 setenv("SPAWN_TEST_PARENT", "1", 1); 216 217 { 218 const char* argv[] = {kSpawnChild, "--env", "empty", nullptr}; 219 const char* env[] = {nullptr}; 220 status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_LDSVC, 221 kSpawnChild, argv, env, 0, nullptr, 222 process.reset_and_get_address(), nullptr); 223 ASSERT_EQ(ZX_OK, status); 224 EXPECT_EQ(61, join(process)); 225 } 226 227 { 228 const char* argv[] = {kSpawnChild, "--env", "one", nullptr}; 229 const char* env[] = {"SPAWN_TEST_CHILD=1", nullptr}; 230 status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_LDSVC, 231 kSpawnChild, argv, env, 0, nullptr, 232 process.reset_and_get_address(), nullptr); 233 ASSERT_EQ(ZX_OK, status); 234 EXPECT_EQ(62, join(process)); 235 } 236 237 { 238 const char* argv[] = {kSpawnChild, "--env", "one", nullptr}; 239 const char* env[] = {"SPAWN_TEST_CHILD=1", nullptr}; 240 status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 241 kSpawnChild, argv, env, 0, nullptr, 242 process.reset_and_get_address(), nullptr); 243 ASSERT_EQ(ZX_OK, status); 244 EXPECT_EQ(62, join(process)); 245 } 246 247 { 248 const char* argv[] = {kSpawnChild, "--env", "two", nullptr}; 249 const char* env[] = {"SPAWN_TEST_CHILD=1", "SPAWN_TEST_CHILD2=1", nullptr}; 250 status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 251 kSpawnChild, argv, env, 0, nullptr, 252 process.reset_and_get_address(), nullptr); 253 ASSERT_EQ(ZX_OK, status); 254 EXPECT_EQ(63, join(process)); 255 } 256 257 { 258 const char* argv[] = {kSpawnChild, "--env", "clone", nullptr}; 259 status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 260 kSpawnChild, argv, nullptr, 0, nullptr, 261 process.reset_and_get_address(), nullptr); 262 ASSERT_EQ(ZX_OK, status); 263 EXPECT_EQ(64, join(process)); 264 } 265 266 unsetenv("SPAWN_TEST_PARENT"); 267 268 END_TEST; 269} 270 271static bool spawn_actions_fd_test(void) { 272 BEGIN_TEST; 273 274 zx_status_t status; 275 zx::process process; 276 277 { 278 const char* argv[] = {nullptr}; 279 status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 280 kSpawnChild, argv, nullptr, 0, nullptr, 281 process.reset_and_get_address(), nullptr); 282 ASSERT_EQ(ZX_ERR_INVALID_ARGS, status); 283 } 284 285 { 286 fdio_spawn_action_t action; 287 action.action = FDIO_SPAWN_ACTION_SET_NAME; 288 action.name.data = "spawn-child-name"; 289 290 const char* argv[] = {nullptr}; 291 status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 292 kSpawnChild, argv, nullptr, 1, &action, 293 process.reset_and_get_address(), nullptr); 294 ASSERT_EQ(ZX_OK, status); 295 EXPECT_EQ(42, join(process)); 296 297 char name[ZX_MAX_NAME_LEN]; 298 ASSERT_EQ(ZX_OK, process.get_property(ZX_PROP_NAME, name, sizeof(name))); 299 EXPECT_TRUE(!strcmp("spawn-child-name", name)); 300 } 301 302 { 303 zx_handle_t socket = ZX_HANDLE_INVALID; 304 uint32_t type; 305 int fd = fdio_pipe_half(&socket, &type); 306 ASSERT_GE(fd, 0); 307 308 fdio_spawn_action_t action; 309 action.action = FDIO_SPAWN_ACTION_CLONE_FD; 310 action.fd.local_fd = fd; 311 action.fd.target_fd = 21; 312 313 const char* argv[] = {kSpawnChild, "--action", "clone-fd", nullptr}; 314 status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 315 kSpawnChild, argv, nullptr, 1, &action, 316 process.reset_and_get_address(), nullptr); 317 ASSERT_EQ(ZX_OK, status); 318 EXPECT_EQ(71, join(process)); 319 EXPECT_TRUE(has_fd(fd)); 320 close(fd); 321 zx_handle_close(socket); 322 } 323 324 { 325 zx::socket socket; 326 uint32_t type; 327 int fd = fdio_pipe_half(socket.reset_and_get_address(), &type); 328 ASSERT_GE(fd, 0); 329 330 fdio_spawn_action_t action; 331 action.action = FDIO_SPAWN_ACTION_TRANSFER_FD; 332 action.fd.local_fd = fd; 333 action.fd.target_fd = 21; 334 335 const char* argv[] = {kSpawnChild, "--action", "transfer-fd", nullptr}; 336 status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 337 kSpawnChild, argv, nullptr, 1, &action, 338 process.reset_and_get_address(), nullptr); 339 ASSERT_EQ(ZX_OK, status); 340 EXPECT_EQ(72, join(process)); 341 EXPECT_FALSE(has_fd(fd)); 342 } 343 344 { 345 zx::socket socket; 346 uint32_t type; 347 int fd = fdio_pipe_half(socket.reset_and_get_address(), &type); 348 ASSERT_GE(fd, 0); 349 350 fdio_spawn_action_t actions[2]; 351 actions[0].action = FDIO_SPAWN_ACTION_CLONE_FD; 352 actions[0].fd.local_fd = fd; 353 actions[0].fd.target_fd = 21; 354 actions[1].action = FDIO_SPAWN_ACTION_TRANSFER_FD; 355 actions[1].fd.local_fd = fd; 356 actions[1].fd.target_fd = 22; 357 358 const char* argv[] = {kSpawnChild, "--action", "clone-and-transfer-fd", nullptr}; 359 status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 360 kSpawnChild, argv, nullptr, 2, actions, 361 process.reset_and_get_address(), nullptr); 362 ASSERT_EQ(ZX_OK, status); 363 EXPECT_EQ(73, join(process)); 364 EXPECT_FALSE(has_fd(fd)); 365 } 366 367 END_TEST; 368} 369 370static bool spawn_actions_ns_test(void) { 371 BEGIN_TEST; 372 373 zx_status_t status; 374 zx::process process; 375 376 { 377 zx::channel h1, h2; 378 ASSERT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2)); 379 380 fdio_spawn_action_t action; 381 action.action = FDIO_SPAWN_ACTION_ADD_NS_ENTRY; 382 action.ns.prefix = "/foo/bar/baz"; 383 action.ns.handle = h1.release(); 384 385 const char* argv[] = {kSpawnChild, "--action", "ns-entry", nullptr}; 386 status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 387 kSpawnChild, argv, nullptr, 1, &action, 388 process.reset_and_get_address(), nullptr); 389 ASSERT_EQ(ZX_OK, status); 390 EXPECT_EQ(74, join(process)); 391 } 392 393 END_TEST; 394} 395 396static bool spawn_actions_h_test(void) { 397 BEGIN_TEST; 398 399 zx_status_t status; 400 zx::process process; 401 402 { 403 zx::channel h1, h2; 404 ASSERT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2)); 405 406 fdio_spawn_action_t action; 407 action.action = FDIO_SPAWN_ACTION_ADD_HANDLE; 408 action.h.id = PA_USER0; 409 action.h.handle = h1.release(); 410 411 const char* argv[] = {kSpawnChild, "--action", "add-handle", nullptr}; 412 status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 413 kSpawnChild, argv, nullptr, 1, &action, 414 process.reset_and_get_address(), nullptr); 415 ASSERT_EQ(ZX_OK, status); 416 EXPECT_EQ(75, join(process)); 417 } 418 419 END_TEST; 420} 421 422static bool spawn_actions_name_test(void) { 423 BEGIN_TEST; 424 425 zx_status_t status; 426 zx::process process; 427 428 { 429 fdio_spawn_action_t actions[2]; 430 actions[0].action = FDIO_SPAWN_ACTION_SET_NAME; 431 actions[0].name.data = "proc-name-0"; 432 actions[1].action = FDIO_SPAWN_ACTION_SET_NAME; 433 actions[1].name.data = "proc-name-1"; 434 435 const char* argv[] = {kSpawnChild, nullptr}; 436 status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 437 kSpawnChild, argv, nullptr, 2, actions, 438 process.reset_and_get_address(), nullptr); 439 ASSERT_EQ(ZX_OK, status); 440 EXPECT_EQ(43, join(process)); 441 char name[ZX_MAX_NAME_LEN]; 442 ASSERT_EQ(ZX_OK, process.get_property(ZX_PROP_NAME, name, sizeof(name))); 443 EXPECT_EQ(0, strcmp(name, "proc-name-1")); 444 } 445 446 END_TEST; 447} 448 449static bool spawn_errors_test(void) { 450 BEGIN_TEST; 451 452 zx_status_t status; 453 zx::process process; 454 char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; 455 const char* argv[] = {kSpawnChild, nullptr}; 456 457 ASSERT_EQ(ZX_ERR_INVALID_ARGS, 458 fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, kSpawnChild, 459 nullptr, process.reset_and_get_address())); 460 461 ASSERT_EQ(ZX_ERR_INVALID_ARGS, 462 fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, kSpawnChild, 463 argv, nullptr, 1, nullptr, process.reset_and_get_address(), nullptr)); 464 465 { 466 fdio_spawn_action_t action; 467 action.action = FDIO_SPAWN_ACTION_ADD_NS_ENTRY; 468 action.ns.prefix = "/foo/bar/baz"; 469 action.ns.handle = ZX_HANDLE_INVALID; 470 471 ASSERT_EQ(ZX_ERR_INVALID_ARGS, 472 fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, kSpawnChild, 473 argv, nullptr, 1, &action, process.reset_and_get_address(), nullptr)); 474 } 475 476 { 477 fdio_spawn_action_t action; 478 action.action = FDIO_SPAWN_ACTION_ADD_HANDLE; 479 action.h.id = PA_USER0; 480 action.h.handle = ZX_HANDLE_INVALID; 481 482 ASSERT_EQ(ZX_ERR_INVALID_ARGS, 483 fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, kSpawnChild, 484 argv, nullptr, 1, &action, process.reset_and_get_address(), nullptr)); 485 } 486 487 { 488 fdio_spawn_action_t action; 489 action.action = FDIO_SPAWN_ACTION_SET_NAME; 490 action.name.data = nullptr; 491 492 ASSERT_EQ(ZX_ERR_INVALID_ARGS, 493 fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, kSpawnChild, 494 argv, nullptr, 1, &action, process.reset_and_get_address(), nullptr)); 495 } 496 497 { 498 const char* empty_argv[] = {nullptr}; 499 ASSERT_EQ(ZX_ERR_INVALID_ARGS, 500 fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, kSpawnChild, 501 empty_argv, process.reset_and_get_address())); 502 } 503 504 ASSERT_EQ(ZX_ERR_IO, 505 fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, "/bogus/path", 506 argv, nullptr, 0, nullptr, process.reset_and_get_address(), err_msg)); 507 EXPECT_TRUE(strstr(err_msg, "/bogus/path") != nullptr); 508 509 { 510 zx::job job; 511 ASSERT_EQ(ZX_OK, zx::job::default_job()->duplicate(0, &job)); 512 ASSERT_EQ(ZX_ERR_ACCESS_DENIED, 513 fdio_spawn(job.get(), FDIO_SPAWN_CLONE_ALL, kSpawnChild, 514 argv, process.reset_and_get_address())); 515 } 516 517 { 518 ASSERT_EQ(30, dup2(0, 30)); 519 ASSERT_EQ(0, close(0)); 520 status = fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 521 kSpawnChild, argv, process.reset_and_get_address()); 522 ASSERT_EQ(ZX_OK, status); 523 EXPECT_EQ(43, join(process)); 524 ASSERT_EQ(0, dup2(30, 0)); 525 ASSERT_EQ(0, close(30)); 526 } 527 528 { 529 zx::channel h1, h2; 530 ASSERT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2)); 531 532 ASSERT_EQ(30, dup2(0, 30)); 533 ASSERT_EQ(0, close(0)); 534 fdio_t* io = fdio_service_create(h1.release()); 535 ASSERT_EQ(0, fdio_bind_to_fd(io, 0, 0)); 536 status = fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 537 kSpawnChild, argv, process.reset_and_get_address()); 538 ASSERT_EQ(ZX_ERR_NOT_SUPPORTED, status); 539 ASSERT_EQ(0, close(0)); 540 ASSERT_EQ(0, dup2(30, 0)); 541 ASSERT_EQ(0, close(30)); 542 } 543 544 { 545 zx::channel h1, h2; 546 ASSERT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2)); 547 548 fdio_t* io = fdio_service_create(h1.release()); 549 int fd = fdio_bind_to_fd(io, -1, 0); 550 ASSERT_GE(fd, 3); 551 552 fdio_spawn_action_t action; 553 action.action = FDIO_SPAWN_ACTION_CLONE_FD; 554 action.fd.local_fd = fd; 555 action.fd.target_fd = 21; 556 557 status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 558 kSpawnChild, argv, nullptr, 1, &action, process.reset_and_get_address(), nullptr); 559 ASSERT_EQ(ZX_ERR_NOT_SUPPORTED, status); 560 ASSERT_EQ(0, close(fd)); 561 } 562 563 { 564 zx::channel h1, h2; 565 ASSERT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2)); 566 567 fdio_t* io = fdio_service_create(h1.release()); 568 int fd = fdio_bind_to_fd(io, -1, 0); 569 ASSERT_GE(fd, 3); 570 571 fdio_spawn_action_t action; 572 action.action = FDIO_SPAWN_ACTION_TRANSFER_FD; 573 action.fd.local_fd = fd; 574 action.fd.target_fd = 21; 575 576 status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 577 kSpawnChild, argv, nullptr, 1, &action, process.reset_and_get_address(), nullptr); 578 ASSERT_EQ(ZX_ERR_NOT_SUPPORTED, status); 579 ASSERT_EQ(-1, close(fd)); 580 } 581 582 END_TEST; 583} 584 585static bool spawn_vmo_test(void) { 586 BEGIN_TEST; 587 588 zx_status_t status; 589 zx::process process; 590 591 { 592 int fd = open(kSpawnChild, O_RDONLY); 593 ASSERT_GE(fd, 0); 594 zx_handle_t vmo; 595 ASSERT_EQ(ZX_OK, fdio_get_vmo_clone(fd, &vmo)); 596 close(fd); 597 598 const char* argv[] = {kSpawnChild, nullptr}; 599 status = fdio_spawn_vmo(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, 600 vmo, argv, nullptr, 0, nullptr, 601 process.reset_and_get_address(), nullptr); 602 ASSERT_EQ(ZX_OK, status); 603 EXPECT_EQ(43, join(process)); 604 } 605 606 END_TEST; 607} 608 609BEGIN_TEST_CASE(spawn_tests) 610RUN_TEST(spawn_control_test) 611RUN_TEST(spawn_launcher_test) 612RUN_TEST(spawn_invalid_args_test) 613RUN_TEST(spawn_flags_test) 614RUN_TEST(spawn_environ_test) 615RUN_TEST(spawn_actions_fd_test) 616RUN_TEST(spawn_actions_ns_test) 617RUN_TEST(spawn_actions_h_test) 618RUN_TEST(spawn_actions_name_test) 619RUN_TEST(spawn_errors_test) 620RUN_TEST(spawn_vmo_test) 621END_TEST_CASE(spawn_tests) 622 623int main(int argc, char** argv) { 624 return unittest_run_all_tests(argc, argv) ? 0 : -1; 625} 626