TEST(spawn, posix_spawnp) {
  ExecTestHelper eth;
  eth.SetArgs({"true", nullptr});
  pid_t pid;
  ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), nullptr, nullptr, eth.GetArgs(), nullptr));
  AssertChildExited(pid, 0);
}
TEST(spawn, posix_spawn_file_actions) {
  int fds[2];
  ASSERT_NE(-1, pipe(fds));

  posix_spawn_file_actions_t fa;
  ASSERT_EQ(0, posix_spawn_file_actions_init(&fa));

  ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[0]));
  ASSERT_EQ(0, posix_spawn_file_actions_adddup2(&fa, fds[1], 1));
  ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[1]));
  // Check that close(2) failures are ignored by closing the same fd again.
  ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[1]));
  ASSERT_EQ(0, posix_spawn_file_actions_addopen(&fa, 56, "/proc/version", O_RDONLY, 0));

  ExecTestHelper eth;
  eth.SetArgs({"ls", "-l", "/proc/self/fd", nullptr});
  pid_t pid;
  ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), &fa, nullptr, eth.GetArgs(), eth.GetEnv()));
  ASSERT_EQ(0, posix_spawn_file_actions_destroy(&fa));

  ASSERT_EQ(0, close(fds[1]));
  std::string content;
  ASSERT_TRUE(android::base::ReadFdToString(fds[0], &content));
  ASSERT_EQ(0, close(fds[0]));

  AssertChildExited(pid, 0);

  // We'll know the dup2 worked if we see any ls(1) output in our pipe.
  // The open we can check manually...
  bool open_to_fd_56_worked = false;
  for (const auto& line : android::base::Split(content, "\n")) {
    if (line.find(" 56 -> /proc/version") != std::string::npos) open_to_fd_56_worked = true;
  }
  ASSERT_TRUE(open_to_fd_56_worked);
}
TEST(spawn, posix_spawnp_not_found) {
  ExecTestHelper eth;
  eth.SetArgs({"does-not-exist", nullptr});
  pid_t pid;
  ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), nullptr, nullptr, eth.GetArgs(), nullptr));
  AssertChildExited(pid, 127);
}
Exemple #4
0
TEST(dl, exec_without_ld_preload) {
#if defined(__BIONIC__)
  std::string helper = get_testlib_root() +
      "/ld_preload_test_helper/ld_preload_test_helper";
  chmod(helper.c_str(), 0755);
  ExecTestHelper eth;
  eth.SetArgs({ helper.c_str(), nullptr });
  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, "12345");
#endif
}
Exemple #5
0
TEST(dl, preinit_system_calls) {
#if defined(__BIONIC__)
  std::string helper = get_testlib_root() +
      "/preinit_syscall_test_helper/preinit_syscall_test_helper";
  chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
  ExecTestHelper eth;
  eth.SetArgs({ helper.c_str(), nullptr });
  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, nullptr);
#endif
}
Exemple #6
0
// ld_config_test_helper must fail because it is depending on a lib which is not
// in the search path
//
// Call sequence is...
// _helper -- (get_value_from_lib()) -->
//     _lib1.so -- (get_value_from_another_lib()) -->
//       _lib2.so (returns 12345)
// The two libs are in ns2/ subdir.
TEST(dl, exec_without_ld_config_file) {
#if defined(__BIONIC__)
  std::string error_message = "CANNOT LINK EXECUTABLE \"" + get_testlib_root() + "/ld_config_test_helper/ld_config_test_helper\": library \"ld_config_test_helper_lib1.so\" not found\n";
  std::string helper = get_testlib_root() +
      "/ld_config_test_helper/ld_config_test_helper";
  chmod(helper.c_str(), 0755);
  ExecTestHelper eth;
  eth.SetArgs({ helper.c_str(), nullptr });
  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, EXIT_FAILURE, error_message.c_str());
#endif
}
TEST(spawn, signal_stress) {
  // Ensure that posix_spawn doesn't restore the caller's signal mask in the
  // child without first defaulting any caught signals (http://b/68707996).
  static pid_t parent = getpid();

  setpgid(0, 0);
  signal(SIGRTMIN, SIG_IGN);

  pid_t pid = fork();
  ASSERT_NE(-1, pid);

  if (pid == 0) {
    for (size_t i = 0; i < 1024; ++i) {
      kill(0, SIGRTMIN);
      usleep(10);
    }
    _exit(99);
  }

  // We test both with and without attributes, because they used to be
  // different codepaths. We also test with an empty `sigdefault` set.
  posix_spawnattr_t attr1;
  posix_spawnattr_init(&attr1);

  sigset_t empty_mask = {};
  posix_spawnattr_t attr2;
  posix_spawnattr_init(&attr2);
  posix_spawnattr_setflags(&attr2, POSIX_SPAWN_SETSIGDEF);
  posix_spawnattr_setsigdefault(&attr2, &empty_mask);

  posix_spawnattr_t* attrs[] = { nullptr, &attr1, &attr2 };

  // We use a real-time signal because that's a tricky case for LP32
  // because our sigset_t was too small.
  ScopedSignalHandler ssh(SIGRTMIN, [](int) { ASSERT_EQ(getpid(), parent); });

  const size_t pid_count = 128;
  pid_t spawned_pids[pid_count];

  ExecTestHelper eth;
  eth.SetArgs({"true", nullptr});
  for (size_t i = 0; i < pid_count; ++i) {
    pid_t spawned_pid;
    ASSERT_EQ(0, posix_spawn(&spawned_pid, "true", nullptr, attrs[i % 3], eth.GetArgs(), nullptr));
    spawned_pids[i] = spawned_pid;
  }

  for (pid_t spawned_pid : spawned_pids) {
    ASSERT_EQ(spawned_pid, TEMP_FAILURE_RETRY(waitpid(spawned_pid, nullptr, 0)));
  }

  AssertChildExited(pid, 99);
}
Exemple #8
0
TEST(dl, exec_linker) {
#if defined(__BIONIC__)
#if defined(__LP64__)
  static constexpr const char* kPathToLinker = "/system/bin/linker64";
#else
  static constexpr const char* kPathToLinker = "/system/bin/linker";
#endif
  ExecTestHelper eth;
  std::string expected_output = std::string("This is ") + kPathToLinker +
                                ", the helper program for dynamic executables.\n";
  eth.SetArgs( { kPathToLinker, nullptr });
  eth.Run([&]() { execve(kPathToLinker, eth.GetArgs(), eth.GetEnv()); }, 0, expected_output.c_str());
#endif
}
static void CatFileToString(posix_spawnattr_t* sa, const char* path, std::string* content) {
  int fds[2];
  ASSERT_NE(-1, pipe(fds));

  posix_spawn_file_actions_t fa;
  ASSERT_EQ(0, posix_spawn_file_actions_init(&fa));
  ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[0]));
  ASSERT_EQ(0, posix_spawn_file_actions_adddup2(&fa, fds[1], 1));
  ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[1]));

  ExecTestHelper eth;
  eth.SetArgs({"cat", path, nullptr});
  pid_t pid;
  ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), &fa, sa, eth.GetArgs(), nullptr));
  ASSERT_EQ(0, posix_spawn_file_actions_destroy(&fa));

  ASSERT_EQ(0, close(fds[1]));
  ASSERT_TRUE(android::base::ReadFdToString(fds[0], content));
  ASSERT_EQ(0, close(fds[0]));
  AssertChildExited(pid, 0);
}
Exemple #10
0
// ensures that LD_CONFIG_FILE env var does not work for production builds.
// The test input is the same as exec_with_ld_config_file, but it must fail in
// this case.
TEST(dl, disable_ld_config_file) {
#if defined(__BIONIC__)
  if (getuid() == 0) {
    // when executed from the shell (e.g. not as part of CTS), skip the test.
    // This test is only for CTS.
    return;
  }
  if (is_debuggable_build()) {
    // Skip the test for non production devices
    return;
  }

  std::string error_message = "CANNOT LINK EXECUTABLE \"" + get_testlib_root() + "/ld_config_test_helper/ld_config_test_helper\": library \"ld_config_test_helper_lib1.so\" not found\n";
  std::string helper = get_testlib_root() +
      "/ld_config_test_helper/ld_config_test_helper";
  TemporaryFile config_file;
  create_ld_config_file(config_file.filename);
  std::string env = std::string("LD_CONFIG_FILE=") + config_file.filename;
  chmod(helper.c_str(), 0755);
  ExecTestHelper eth;
  eth.SetArgs({ helper.c_str(), nullptr });
  eth.SetEnv({ env.c_str(), nullptr });
  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, EXIT_FAILURE, error_message.c_str());
#endif
}
TEST(spawn, posix_spawn_environment) {
  ExecTestHelper eth;
  eth.SetArgs({"sh", "-c", "exit $posix_spawn_environment_test", nullptr});
  eth.SetEnv({"posix_spawn_environment_test=66", nullptr});
  pid_t pid;
  ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), nullptr, nullptr, eth.GetArgs(), eth.GetEnv()));
  AssertChildExited(pid, 66);
}
Exemple #12
0
TEST(dl, exec_with_ld_preload) {
#if defined(__BIONIC__)
  std::string helper = get_testlib_root() +
      "/ld_preload_test_helper/ld_preload_test_helper";
  std::string env = std::string("LD_PRELOAD=") + get_testlib_root() + "/ld_preload_test_helper_lib2.so";
  chmod(helper.c_str(), 0755);
  ExecTestHelper eth;
  eth.SetArgs({ helper.c_str(), nullptr });
  eth.SetEnv({ env.c_str(), nullptr });
  // ld_preload_test_helper calls get_value_from_lib() and returns the value.
  // The symbol is defined by two libs: ld_preload_test_helper_lib.so and
  // ld_preloaded_lib.so. The former is DT_NEEDED and the latter is LD_PRELOADED
  // via this execution. The main executable is linked to the LD_PRELOADED lib
  // and the value given from the lib is returned.
  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, "54321");
#endif
}
Exemple #13
0
// _lib1.so and _lib2.so are now searchable by having another namespace 'ns2'
// whose search paths include the 'ns2/' subdir.
TEST(dl, exec_with_ld_config_file) {
#if defined(__BIONIC__)
  if (!is_debuggable_build()) {
    // LD_CONFIG_FILE is not supported on user build
    return;
  }
  std::string helper = get_testlib_root() +
      "/ld_config_test_helper/ld_config_test_helper";
  TemporaryFile config_file;
  create_ld_config_file(config_file.filename);
  std::string env = std::string("LD_CONFIG_FILE=") + config_file.filename;
  chmod(helper.c_str(), 0755);
  ExecTestHelper eth;
  eth.SetArgs({ helper.c_str(), nullptr });
  eth.SetEnv({ env.c_str(), nullptr });
  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, "12345");
#endif
}