Exemple #1
0
pid_t do_proc_open_helper(int afdt_fd) {
  std::string cmd, cwd;
  std::vector<std::string> env;
  std::vector<int> pvals;
  lwp_read(afdt_fd, cmd, cwd, env, pvals);

  std::vector<int> pkeys;
  for (int i = 0; i < pvals.size(); i++) {
    int fd = recv_fd(afdt_fd);
    if (fd < 0) {
      lwp_write(afdt_fd, "error", (int32_t)EPROTO);
      close_fds(pkeys);
      return -1;
    }
    pkeys.push_back(fd);
  }

  // indicate error if an empty command was received
  if (cmd.length() == 0) {
    lwp_write(afdt_fd, "error", (int32_t)ENOENT);
    return -1;
  }

  // now ready to start the child process
  pid_t child = fork();
  if (child == 0) {
    mprotect_1g_pages(PROT_READ);
    Process::OOMScoreAdj(1000);
    for (int i = 0; i < pvals.size(); i++) {
      dup2(pkeys[i], pvals[i]);
    }
    if (!cwd.empty() && chdir(cwd.c_str())) {
      // non-zero for error
      // chdir failed, the working directory remains unchanged
    }
    if (!env.empty()) {
      char **envp = build_envp(env);
      execle("/bin/sh", "sh", "-c", cmd.c_str(), nullptr, envp);
      free(envp);
    } else {
      execl("/bin/sh", "sh", "-c", cmd.c_str(), nullptr);
    }
    _Exit(HPHP_EXIT_FAILURE);
  }

  if (child > 0) {
    // successfully created the child process
    lwp_write(afdt_fd, "success", child);
  } else {
    // failed creating the child process
    lwp_write(afdt_fd, "error", errno);
  }

  close_fds(pkeys);
  return child;
}
Exemple #2
0
void HHVM_FUNCTION(pcntl_exec,
                   const String& path,
                   const Array& args /* = null_array */,
                   const Array& envs /* = null_array */) {
  if (RuntimeOption::WhitelistExec && !check_cmd(path.data())) {
    return;
  }
  if (Repo::prefork()) {
    raise_error("execing is disallowed in multi-threaded mode");
    return;
  }

  // build argumnent list
  std::vector<String> sargs; // holding those char *
  int size = args.size();
  char **argv = (char **)malloc((size + 2) * sizeof(char *));
  *argv = (char *)path.data();
  int i = 1;
  if (size) {
    sargs.reserve(size);
    for (ArrayIter iter(args); iter; ++iter, ++i) {
      String arg = iter.second().toString();
      sargs.push_back(arg);
      *(argv + i) = (char *)arg.data();
    }
  }
  *(argv + i) = NULL;

  // build environment pair list
  std::vector<String> senvs; // holding those char *
  char **envp = build_envp(envs, senvs);
  if (execve(path.c_str(), argv, envp) == -1) {
    raise_warning("Error has occurred: (errno %d) %s",
                    errno, folly::errnoStr(errno).c_str());
  }

  free(envp);
  free(argv);
}
Exemple #3
0
static void do_proc_open(FILE *fin, FILE *fout, int afdt_fd) {
  char cmd[BUFFER_SIZE];
  read_buf(fin, cmd);
  if (strlen(cmd) == 0) {
    fprintf(fout, "error\n%d\n", ENOENT);
    fflush(fout);
    return;
  }

  char cwd[BUFFER_SIZE];
  read_buf(fin, cwd);

  char buf[BUFFER_SIZE];
  int env_size = 0;
  std::vector<std::string> env;
  read_buf(fin, buf);
  sscanf(buf, "%d", &env_size);
  for (int i = 0; i < env_size; i++) {
    read_buf(fin, buf);
    env.push_back(buf);
  }

  int pipe_size = 0;
  read_buf(fin, buf);
  sscanf(buf, "%d", &pipe_size);
  std::vector<int> pvals;
  for (int i = 0; i < pipe_size; i++) {
    int fd_value;
    read_buf(fin, buf);
    sscanf(buf, "%d", &fd_value);
    pvals.push_back(fd_value);
  }

  std::vector<int> pkeys;
  for (int i = 0; i < pipe_size; i++) {
    int fd = recv_fd(afdt_fd);
    if (fd < 0) {
      fprintf(fout, "error\n%d\n", EPROTO);
      fflush(fout);
      close_fds(pkeys);
      return;
    }
    pkeys.push_back(fd);
  }

  // now ready to start the child process
  pid_t child = fork();
  if (child == 0) {
    for (int i = 0; i < pipe_size; i++) {
      dup2(pkeys[i], pvals[i]);
    }
    if (strlen(cwd) > 0 && chdir(cwd)) {
      // non-zero for error
      // chdir failed, the working directory remains unchanged
    }
    if (!env.empty()) {
      char **envp = build_envp(env);
      execle("/bin/sh", "sh", "-c", cmd, nullptr, envp);
      free(envp);
    } else {
      execl("/bin/sh", "sh", "-c", cmd, nullptr);
    }
    _exit(127);
  } else if (child > 0) {
    // successfully created the child process
    fprintf(fout, "%" PRId64 "\n", (int64_t)child);
    fflush(fout);
  } else {
    // failed creating the child process
    fprintf(fout, "error\n%d\n", errno);
    fflush(fout);
  }

  close_fds(pkeys);
}
Exemple #4
0
static void do_proc_open(int afdt_fd) {
  std::string cmd;
  lwp_read(afdt_fd, cmd);

  std::string cwd;
  lwp_read(afdt_fd, cwd);

  std::string buf;
  int env_size = 0;
  std::vector<std::string> env;
  lwp_read_int32(afdt_fd, env_size);
  for (int i = 0; i < env_size; i++) {
    lwp_read(afdt_fd, buf);
    env.push_back(buf);
  }

  int pipe_size = 0;
  lwp_read_int32(afdt_fd, pipe_size);
  std::vector<int> pvals;
  for (int i = 0; i < pipe_size; i++) {
    int fd_value;
    lwp_read_int32(afdt_fd, fd_value);
    pvals.push_back(fd_value);
  }

  std::vector<int> pkeys;
  for (int i = 0; i < pipe_size; i++) {
    int fd = recv_fd(afdt_fd);
    if (fd < 0) {
      lwp_write(afdt_fd, "error");
      lwp_write_int32(afdt_fd, EPROTO);
      close_fds(pkeys);
      return;
    }
    pkeys.push_back(fd);
  }

  // indicate error if an empty command was received
  if (cmd.length() == 0) {
    lwp_write(afdt_fd, "error");
    lwp_write_int32(afdt_fd, ENOENT);
    return;
  }

  // now ready to start the child process
  pid_t child = fork();
  if (child == 0) {
    for (int i = 0; i < pipe_size; i++) {
      dup2(pkeys[i], pvals[i]);
    }
    if (!cwd.empty() && chdir(cwd.c_str())) {
      // non-zero for error
      // chdir failed, the working directory remains unchanged
    }
    if (!env.empty()) {
      char **envp = build_envp(env);
      execle("/bin/sh", "sh", "-c", cmd.c_str(), nullptr, envp);
      free(envp);
    } else {
      execl("/bin/sh", "sh", "-c", cmd.c_str(), nullptr);
    }
    _Exit(HPHP_EXIT_FAILURE);
  } else if (child > 0) {
    // successfully created the child process
    lwp_write(afdt_fd, "success");
    lwp_write_int64(afdt_fd, (int64_t)child);
  } else {
    // failed creating the child process
    lwp_write(afdt_fd, "error");
    lwp_write_int32(afdt_fd, errno);
  }

  close_fds(pkeys);
}
Variant HHVM_FUNCTION(proc_open,
                      const String& cmd,
                      const Array& descriptorspec,
                      VRefParam pipesParam,
                      const String& cwd /* = null_string */,
                      const Variant& env /* = null_variant */,
                      const Variant& other_options /* = null_variant */) {
  if (RuntimeOption::WhitelistExec && !check_cmd(cmd.data())) {
    return false;
  }
  if (cmd.size() != strlen(cmd.c_str())) {
    raise_warning("NULL byte detected. Possible attack");
    return false;
  }
  Variant pipes(pipesParam, Variant::WithRefBind{});

  std::vector<DescriptorItem> items;

  std::string scwd = "";
  if (!cwd.empty()) {
    scwd = cwd.c_str();
  } else if (!g_context->getCwd().empty()) {
    scwd = g_context->getCwd().c_str();
  }

  Array enva;

  if (env.isNull()) {
    // Build out an environment that conceptually matches what we'd
    // see if we were to iterate the environment and call getenv()
    // for each name.

    // Env vars defined in the hdf file go in first
    for (const auto& envvar : RuntimeOption::EnvVariables) {
      enva.set(String(envvar.first), String(envvar.second));
    }

    // global environment overrides the hdf
    for (char **env = environ; env && *env; env++) {
      char *p = strchr(*env, '=');
      if (p) {
        String name(*env, p - *env, CopyString);
        String val(p + 1, CopyString);
        enva.set(name, val);
      }
    }

    // and then any putenv() changes take precedence
    for (ArrayIter iter(g_context->getEnvs()); iter; ++iter) {
      enva.set(iter.first(), iter.second());
    }
  } else {
    enva = env.toArray();
  }

  pid_t child;

  if (LightProcess::Available()) {
    // light process available
    // there is no need to do any locking, because the forking is delegated
    // to the light process
    if (!pre_proc_open(descriptorspec, items)) return false;
    const int item_size = items.size();
    std::vector<int> created;
    created.reserve(item_size);
    std::vector<int> intended;
    intended.reserve(item_size);
    for (int i = 0; i < item_size; i++) {
      const auto& item = items[i];
      created.push_back(item.childend);
      intended.push_back(item.index);
    }

    std::vector<std::string> envs;
    for (ArrayIter iter(enva); iter; ++iter) {
      StringBuffer nvpair;
      nvpair.append(iter.first().toString());
      nvpair.append('=');
      nvpair.append(iter.second().toString());
      std::string tmp = nvpair.detach().c_str();
      if (tmp.find('\n') == std::string::npos) {
        envs.push_back(tmp);
      }
    }

    child = LightProcess::proc_open(cmd.c_str(), created, intended,
                                    scwd.c_str(), envs);
    assert(child);
    return post_proc_open(cmd, pipes, enva, items, child);
  } else {
    /* the unix way */
    Lock lock(DescriptorItem::s_mutex);
    if (!pre_proc_open(descriptorspec, items)) return false;
    child = fork();
    if (child) {
      // the parent process
      return post_proc_open(cmd, pipes, enva, items, child);
    }
  }

  assert(child == 0);
  /* this is the child process */

  /* close those descriptors that we just opened for the parent stuff,
   * dup new descriptors into required descriptors and close the original
   * cruft */
  for (auto& item : items) {
    item.dupChild();
  }
  if (scwd.length() > 0 && chdir(scwd.c_str())) {
    // chdir failed, the working directory remains unchanged
  }
  std::vector<String> senvs; // holding those char *
  char **envp = build_envp(enva, senvs);
  execle("/bin/sh", "sh", "-c", cmd.data(), NULL, envp);
  free(envp);
  _exit(127);
}
Exemple #6
0
Variant HHVM_FUNCTION(proc_open,
                      const String& cmd,
                      const Array& descriptorspec,
                      VRefParam pipesParam,
                      const Variant& cwd /* = uninit_variant */,
                      const Variant& env /* = uninit_variant */,
                      const Variant& other_options /* = uninit_variant */) {
  if (RuntimeOption::WhitelistExec && !check_cmd(cmd.data())) {
    return false;
  }
  if (cmd.size() != strlen(cmd.c_str())) {
    raise_warning("NULL byte detected. Possible attack");
    return false;
  }
  Variant pipes(pipesParam, Variant::WithRefBind{});

  std::vector<DescriptorItem> items;

  std::string scwd = "";
  if (!cwd.isNull() && cwd.isString() && !cwd.asCStrRef().empty()) {
    scwd = cwd.asCStrRef().c_str();
  } else if (!g_context->getCwd().empty()) {
    scwd = g_context->getCwd().c_str();
  }

  Array enva;

  if (env.isNull()) {
    if (is_cli_mode()) {
      enva = cli_env();
    } else {
      // Build out an environment that conceptually matches what we'd
      // see if we were to iterate the environment and call getenv()
      // for each name.

      // Env vars defined in the hdf file go in first
      for (const auto& envvar : RuntimeOption::EnvVariables) {
        enva.set(String(envvar.first), String(envvar.second));
      }

      // global environment overrides the hdf
      for (char **env = environ; env && *env; env++) {
        char *p = strchr(*env, '=');
        if (p) {
          String name(*env, p - *env, CopyString);
          String val(p + 1, CopyString);
          enva.set(name, val);
        }
      }
    }

    // and then any putenv() changes take precedence
    for (ArrayIter iter(g_context->getEnvs()); iter; ++iter) {
      enva.set(iter.first(), iter.second());
    }
  } else {
    enva = env.toArray();
  }


#ifdef _WIN32
  PROCESS_INFORMATION pi;
  HANDLE childHandle;
  STARTUPINFO si;
  BOOL newprocok;
  SECURITY_ATTRIBUTES security;
  DWORD dwCreateFlags = 0;
  char *command_with_cmd;
  UINT old_error_mode;
  char cur_cwd[MAXPATHLEN];
  bool suppress_errors = false;
  bool bypass_shell = false;

  if (!other_options.isNull() && other_options.isArray()) {
    auto arr = other_options.asCArrRef();
    if (arr.exists(String("suppress_errors", CopyString), true)) {
      auto v = arr[String("suppress_errors", CopyString)];
      if ((v.isBoolean() && v.asBooleanVal()) ||
          (v.isInteger() && v.asInt64Val())) {
        suppress_errors = true;
      }
    }

    if (arr.exists(String("bypass_shell", CopyString), true)) {
      auto v = arr[String("bypass_shell", CopyString)];
      if ((v.isBoolean() && v.asBooleanVal()) ||
          (v.isInteger() && v.asInt64Val())) {
        bypass_shell = true;
      }
    }
  }

  /* we use this to allow the child to inherit handles */
  memset(&security, 0, sizeof(security));
  security.nLength = sizeof(security);
  security.bInheritHandle = true;
  security.lpSecurityDescriptor = nullptr;

  memset(&si, 0, sizeof(si));
  si.cb = sizeof(si);
  si.dwFlags = STARTF_USESTDHANDLES;

  si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
  si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  si.hStdError = GetStdHandle(STD_ERROR_HANDLE);

  if (!pre_proc_open(descriptorspec, items)) return false;
  /* redirect stdin/stdout/stderr if requested */
  for (size_t i = 0; i < items.size(); i++) {
    switch (items[i].index) {
      case 0:
        si.hStdInput = items[i].childend;
        break;
      case 1:
        si.hStdOutput = items[i].childend;
        break;
      case 2:
        si.hStdError = items[i].childend;
        break;
    }
  }


  memset(&pi, 0, sizeof(pi));

  if (suppress_errors) {
    old_error_mode = SetErrorMode(
      SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
  }

  dwCreateFlags = NORMAL_PRIORITY_CLASS;
  if (!RuntimeOption::ServerExecutionMode()) {
    dwCreateFlags |= CREATE_NO_WINDOW;
  }

  char *envp = build_envp(enva);
  if (bypass_shell) {
    newprocok = CreateProcess(
      nullptr,
      strdup(cmd.c_str()),
      &security,
      &security,
      TRUE,
      dwCreateFlags,
      envp,
      scwd.c_str(),
      &si,
      &pi);
  } else {
    std::string command_with = "cmd.exe /c ";
    command_with += cmd.toCppString();

    newprocok = CreateProcess(
      nullptr,
      strdup(command_with.c_str()),
      &security,
      &security,
      TRUE,
      dwCreateFlags,
      envp,
      scwd.c_str(),
      &si,
      &pi);
  }
  free(envp);

  if (suppress_errors) {
    SetErrorMode(old_error_mode);
  }

  if (newprocok == FALSE) {
    DWORD dw = GetLastError();
    char* msg;
    FormatMessageA(
      FORMAT_MESSAGE_ALLOCATE_BUFFER
        | FORMAT_MESSAGE_FROM_SYSTEM
        | FORMAT_MESSAGE_IGNORE_INSERTS,
      nullptr,
      dw,
      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
      (LPSTR)&msg,
      0,
      nullptr);

    /* clean up all the descriptors */
    for (size_t i = 0; i < items.size(); i++) {
      CloseHandle(items[i].childend);
      if (items[i].parentend) {
        CloseHandle(items[i].parentend);
      }
    }
    raise_warning("CreateProcess failed, error code - %u: %s", dw, msg);
    LocalFree(msg);
    return false;
  }

  childHandle = pi.hProcess;
  DWORD child = pi.dwProcessId;
  CloseHandle(pi.hThread);
  return post_proc_open(cmd, pipes, enva, items, (pid_t)child, childHandle);
#else
  pid_t child;

  if (LightProcess::Available()) {
    // light process available
    // there is no need to do any locking, because the forking is delegated
    // to the light process
    if (!pre_proc_open(descriptorspec, items)) return false;
    const int item_size = items.size();
    std::vector<int> created;
    created.reserve(item_size);
    std::vector<int> intended;
    intended.reserve(item_size);
    for (int i = 0; i < item_size; i++) {
      const auto& item = items[i];
      created.push_back(item.childend);
      intended.push_back(item.index);
    }

    std::vector<std::string> envs;
    for (ArrayIter iter(enva); iter; ++iter) {
      StringBuffer nvpair;
      nvpair.append(iter.first().toString());
      nvpair.append('=');
      nvpair.append(iter.second().toString());
      std::string tmp = nvpair.detach().c_str();
      if (tmp.find('\n') == std::string::npos) {
        envs.push_back(tmp);
      }
    }

    child = LightProcess::proc_open(cmd.c_str(), created, intended,
                                    scwd.c_str(), envs);
    assert(child);
    return post_proc_open(cmd, pipes, enva, items, child);
  } else {
    /* the unix way */
    Lock lock(DescriptorItem::s_mutex);
    if (!pre_proc_open(descriptorspec, items)) return false;
    child = fork();
    if (child) {
      // the parent process
      return post_proc_open(cmd, pipes, enva, items, child);
    }
  }

  assert(child == 0);
  /* this is the child process */

  /* close those descriptors that we just opened for the parent stuff,
   * dup new descriptors into required descriptors and close the original
   * cruft */
  for (auto& item : items) {
    item.dupChild();
  }
  if (scwd.length() > 0 && chdir(scwd.c_str())) {
    // chdir failed, the working directory remains unchanged
  }
  std::vector<String> senvs; // holding those char *
  char **envp = build_envp(enva, senvs);
  execle("/bin/sh", "sh", "-c", cmd.data(), nullptr, envp);
  free(envp);
  _exit(127);
#endif
}