Esempio n. 1
0
FILE *LightProcess::LightPopenImpl(const char *cmd, const char *type,
                                   const char *cwd) {
  int id = GetId();
  Lock lock(g_procs[id].m_procMutex);

  auto fout = g_procs[id].m_afdt_fd;
  lwp_write(fout, "popen");
  lwp_write(fout, type);
  lwp_write(fout, cmd);
  lwp_write(fout, cwd ? cwd : "");

  std::string buf;
  auto fin = g_procs[id].m_afdt_fd;
  lwp_read(fin, buf);
  if (buf == "error") {
    return nullptr;
  }

  int64_t fptr = 0;
  lwp_read_int64(fin, fptr);
  if (!fptr) {
    Logger::Error("Light process failed to return the file pointer.");
    return nullptr;
  }

  int fd = recv_fd(fin);
  if (fd < 0) {
    Logger::Error("Light process failed to send the file descriptor.");
    return nullptr;
  }
  FILE *f = fdopen(fd, type);
  g_procs[id].m_popenMap[(int64_t)f] = fptr;

  return f;
}
Esempio n. 2
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;
}
Esempio n. 3
0
static void do_popen(int afdt_fd) {
  std::string buf;
  std::string cwd;

  lwp_read(afdt_fd, buf);
  bool read_only = (buf[0] == 'r');

  lwp_read(afdt_fd, buf);

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

  if (!cwd.empty()) {
    old_cwd = Process::GetCurrentDirectory();
    if (old_cwd != cwd) {
      if (chdir(cwd.c_str())) {
        // Ignore chdir failures, because the compiled version might not
        // have the directory any more.
        Logger::Warning("Light Process failed chdir to %s.", cwd.c_str());
      }
    }
  }

  FILE *f = buf[0] ? ::popen(buf.c_str(), read_only ? "r" : "w") : nullptr;

  if (!old_cwd.empty() && chdir(old_cwd.c_str())) {
    // only here if we can't change the cwd back
  }

  if (f == nullptr) {
    Logger::Error("Light process failed popen: %d (%s).", errno,
                  folly::errnoStr(errno).c_str());
    lwp_write(afdt_fd, "error");
  } else {
    lwp_write(afdt_fd, "success");
    lwp_write_int64(afdt_fd, (int64_t)f);
    int fd = fileno(f);
    send_fd(afdt_fd, fd);
  }
}
Esempio n. 4
0
pid_t LightProcess::proc_open(const char *cmd, const std::vector<int> &created,
                              const std::vector<int> &desired,
                              const char *cwd,
                              const std::vector<std::string> &env) {
  int id = GetId();
  Lock lock(g_procs[id].m_procMutex);
  always_assert(Available());
  always_assert(created.size() == desired.size());

  auto fout = g_procs[id].m_afdt_fd;
  lwp_write(fout, "proc_open");
  lwp_write(fout, cmd);
  lwp_write(fout, cwd ? cwd : "");
  lwp_write_int32(fout, (int)env.size());
  for (unsigned int i = 0; i < env.size(); i++) {
    lwp_write(fout, env[i]);
  }

  lwp_write_int32(fout, (int)created.size());
  for (unsigned int i = 0; i < desired.size(); i++) {
    lwp_write_int32(fout, desired[i]);
  }

  bool error_send = false;
  int save_errno = 0;
  for (unsigned int i = 0; i < created.size(); i++) {
    if (!send_fd(g_procs[id].m_afdt_fd, created[i])) {
      error_send = true;
      save_errno = errno;
      break;
    }
  }

  std::string buf;
  auto fin = g_procs[id].m_afdt_fd;
  lwp_read(fin, buf);
  if (buf == "error") {
    lwp_read_int32(fin, errno);
    if (error_send) {
      // On this error, the receiver side returns dummy errno,
      // use the sender side errno here.
      errno = save_errno;
    }
    return -1;
  }
  always_assert_flog(buf == "success",
                     "Unexpected message from light process: `{}'", buf);
  int64_t pid = -1;
  lwp_read_int64(fin, pid);
  always_assert(pid);
  return (pid_t)pid;
}
Esempio n. 5
0
static void do_change_user(int afdt_fd) {
  std::string uname;
  lwp_read(afdt_fd, uname);
  if (uname.length() > 0) {
    struct passwd *pw = getpwnam(uname.c_str());
    if (pw) {
      if (pw->pw_gid) {
        initgroups(pw->pw_name, pw->pw_gid);
        setgid(pw->pw_gid);
      }
      if (pw->pw_uid) {
        setuid(pw->pw_uid);
      }
    }
  }
}
Esempio n. 6
0
void LightProcess::runShadow() {
  std::string buf;

  pollfd pfd[1];
  pfd[0].fd = m_afdt_fd;
  pfd[0].events = POLLIN;
  try {
    while (true) {
      int ret = poll(pfd, 1, -1);
      if (ret < 0 && errno == EINTR) {
        continue;
      }
      if (pfd[0].revents & POLLHUP) {
        // no more command can come in
        Logger::Error("Lost parent, LightProcess exiting");
        break;
      }
      if (pfd[0].revents & POLLIN) {
        lwp_read(m_afdt_fd, buf);
        if (buf == "exit") {
          Logger::Verbose("LightProcess exiting upon request");
          break;
        } else if (buf == "popen") {
          do_popen(m_afdt_fd);
        } else if (buf == "pclose") {
          do_pclose(m_afdt_fd);
        } else if (buf == "proc_open") {
          do_proc_open(m_afdt_fd);
        } else if (buf == "waitpid") {
          do_waitpid(m_afdt_fd);
        } else if (buf == "change_user") {
          do_change_user(m_afdt_fd);
        } else if (buf[0]) {
          Logger::Info("LightProcess got invalid command: %.20s", buf.c_str());
        }
      }
    }
  } catch (const std::exception& e) {
    Logger::Error("LightProcess exiting due to exception: %s", e.what());
  } catch (...) {
    Logger::Error("LightProcess exiting due to unknown exception");
  }

  ::close(m_afdt_fd);
  _Exit(0);
}
Esempio n. 7
0
static int
list_read(int listt, int elemn)
{
	char	idstr[P_MAXVAL];
	list_t	*list;
	id_info_t *id;

	if (listt == L_LWP)
		return (lwp_read(elemn));

	while (elemn-- > 0) {
		switch (listt) {
			case L_PRC_SI 	: list = &processes;
					break;
			case L_USR_SI 	: list = &users;
					break;
			case L_PRJ_SI 	: list = &projects;
					break;
		}

		if (list->l_head == NULL) { /* first element */
			list->l_head = list->l_tail = id =
					Zalloc(sizeof (id_info_t));
			list->l_count++;
		} else {
			/* a new element */
			id = list->l_tail;
			id->id_next = Zalloc(sizeof (id_info_t));
			id->id_next->id_prev = list->l_tail;
			id->id_next->id_next = NULL;
			list->l_tail = id->id_next;
			id = list->l_tail;
			list->l_count++;
		}
		if (r_element((char *)id, idstr) == -1) {
			list_clear(list);
			return (-1);
		}
	}
	return (0);
}
Esempio n. 8
0
pid_t do_popen_helper(int afdt_fd) {
  std::string mode, buf, cwd;

  lwp_read(afdt_fd, mode, buf, cwd);

  std::string old_cwd;

  if (!cwd.empty()) {
    old_cwd = Process::GetCurrentDirectory();
    if (old_cwd != cwd) {
      if (chdir(cwd.c_str())) {
        // Ignore chdir failures, because the compiled version might not
        // have the directory any more.
        Logger::Warning("Light Process failed chdir to %s.", cwd.c_str());
      }
    }
  }

  pid_t pid;

  auto fd = buf.empty() ? -1 :
    popen_impl(buf.c_str(), mode.c_str(), &pid);

  if (!old_cwd.empty() && chdir(old_cwd.c_str())) {
    // only here if we can't change the cwd back
  }

  if (fd < 0) {
    Logger::Error("Light process failed popen: %d (%s).", errno,
                  folly::errnoStr(errno).c_str());
    lwp_write(afdt_fd, "error");
  } else {
    lwp_write(afdt_fd, "success", pid);
    send_fd(afdt_fd, fd);
    // the fd is now owned by the main process, close our copy
    close(fd);
  }
  return pid;
}
Esempio n. 9
0
void do_waitpid(int afdt_fd) {
  pid_t pid = -1;
  int options = 0;
  int timeout = 0;
  lwp_read(afdt_fd, pid, options, timeout);

  int stat;
  if (timeout > 0) {
    waited = pid;
    signal(SIGALRM, kill_handler);
    alarm(timeout);
  }

  rusage ru;
  int64_t time_us = 0;
  const auto ret = ::wait4(pid, &stat, options, &ru);
  alarm(0); // cancel the previous alarm if not triggered yet
  waited = 0;
  int64_t events[] = { 0, 0, 0 };
  if (ret > 0 && s_trackProcessTimes) {
    time_us = ru2microseconds(ru);
    auto it = s_pidToHCWMap.find(ret);
    if (it == s_pidToHCWMap.end()) {
      throw Exception("pid not in map: %s",
                      folly::errnoStr(errno).c_str());
    }

    auto hcw = std::move(it->second);
    s_pidToHCWMap.erase(it);
    hcw->events = events;
    hcw->barrier.wait();
    pthread_join(hcw->thr, nullptr);
  }

  lwp_write(afdt_fd, ret, errno, stat,
            time_us, events[0], events[1], events[2]);
}
Esempio n. 10
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);
}