// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "vm_tools/seneschal/service.h"

#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <limits.h>
#include <mntent.h>
#include <signal.h>
#include <stdint.h>
#include <sys/mount.h>
#include <sys/signalfd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>

#include <linux/vm_sockets.h>  // needs to come after sys/socket.h

#include <algorithm>
#include <string>
#include <utility>
#include <vector>

#include <base/bind.h>
#include <base/bind_helpers.h>
#include <base/files/file_enumerator.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/files/scoped_file.h>
#include <base/location.h>
#include <base/logging.h>
#include <base/stl_util.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_piece.h>
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <base/threading/thread_task_runner_handle.h>
#include <base/time/time.h>
#include <brillo/file_utils.h>
#include <chromeos/dbus/service_constants.h>
#include <chromeos/libminijail.h>
#include <chromeos/scoped_minijail.h>
#include <seneschal/proto_bindings/seneschal_service.pb.h>

using std::string;

namespace vm_tools {
namespace seneschal {
namespace {
// Path to the runtime directory where we will create server jails.
constexpr char kRuntimeDir[] = "/run/seneschal";

// The chronos uid and gid.  These are used for file system access.
constexpr uid_t kChronosUid = 1000;
constexpr gid_t kChronosGid = 1000;

// Access to android files requires android-everybody gid.
constexpr gid_t kAndroidEverybodyGid = 665357;
constexpr gid_t kSupplementaryGroups[] = {kAndroidEverybodyGid};

// The gid of the chronos-access group.
constexpr gid_t kChronosAccessGid = 1001;

// The uid used for authenticating with DBus.
constexpr uid_t kDbusAuthUid = 20115;

// How long we should wait for a server process to exit.
constexpr base::TimeDelta kServerExitTimeout = base::TimeDelta::FromSeconds(2);

// Path to the 9p server.
constexpr char kServerPath[] = "/usr/bin/9s";
constexpr char kServerRoot[] = "/fsroot";
constexpr char kSeccompPolicyPath[] = "/usr/share/policy/9s-seccomp.policy";

// `mkdir -p`, essentially.  Reimplement all of base::CreateDirectory because
// we want mode 0755 instead of mode 0700.
bool MkdirRecursively(const base::FilePath& full_path) {
  if (!full_path.IsAbsolute()) {
    LOG(INFO) << "Relative paths are not supported: " << full_path.value();
    return false;
  }

  // Collect a list of all parent directories.
  std::vector<std::string> components;
  full_path.GetComponents(&components);
  DCHECK(!components.empty());

  base::ScopedFD fd(open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW));
  if (!fd.is_valid())
    return false;

  // Iterate through the parents and create the missing ones. '+ 1' is for
  // skipping "/".
  for (std::vector<std::string>::const_iterator i = components.begin() + 1;
       i != components.end(); ++i) {
    // Try to create the directory. Note that Chromium's MkdirRecursively() uses
    // 0700, but we use 0755.
    if (mkdirat(fd.get(), i->c_str(), 0755) != 0) {
      if (errno != EEXIST) {
        PLOG(ERROR) << "Failed to mkdirat " << *i
                    << ": full_path=" << full_path.value();
        return false;
      }

      // The path already exists. Make sure that the path is a directory.
      struct stat st;
      if (fstatat(fd.get(), i->c_str(), &st, AT_SYMLINK_NOFOLLOW) != 0) {
        PLOG(ERROR) << "Failed to fstatat " << *i
                    << ": full_path=" << full_path.value();
        return false;
      }
      if (!S_ISDIR(st.st_mode)) {
        LOG(ERROR) << *i << " is not a directory: st_mode=" << st.st_mode
                   << ", full_path=" << full_path.value();
        return false;
      }
    }

    // Updates the FD so it refers to the new directory created or checked
    // above.
    const int new_fd =
        openat(fd.get(), i->c_str(), O_RDONLY | O_NOFOLLOW | O_NONBLOCK, 0);
    if (new_fd < 0) {
      PLOG(ERROR) << "Failed to openat " << *i
                  << ": full_path=" << full_path.value();
      return false;
    }
    fd.reset(new_fd);
    continue;
  }
  return true;
}

// Passes |method_call| to |handler| and passes the response to
// |response_sender|. If |handler| returns NULL, an empty response is created
// and sent.
void HandleSynchronousDBusMethodCall(
    base::Callback<std::unique_ptr<dbus::Response>(dbus::MethodCall*)> handler,
    dbus::MethodCall* method_call,
    dbus::ExportedObject::ResponseSender response_sender) {
  std::unique_ptr<dbus::Response> response = handler.Run(method_call);
  if (!response)
    response = dbus::Response::FromMethodCall(method_call);
  response_sender.Run(std::move(response));
}

}  // namespace

Service::ServerInfo::ServerInfo(pid_t pid, base::FilePath root_dir)
    : pid_(pid) {
  CHECK(root_dir_.Set(root_dir));
}

Service::ServerInfo::ServerInfo(Service::ServerInfo&& other)
    : pid_(other.pid_) {
  CHECK(root_dir_.Set(other.root_dir_.Take()));
}

Service::ServerInfo& Service::ServerInfo::operator=(
    Service::ServerInfo&& other) {
  // Self assignment check is required.
  if (this != &other) {
    pid_ = other.pid_;
    CHECK(root_dir_.Set(other.root_dir_.Take()));
  }

  return *this;
}

Service::ServerInfo::~ServerInfo() {
  if (!root_dir_.IsValid()) {
    // Nothing to see here.
    return;
  }

  // Clean up the mounts so that we can delete the temporary directory.  An
  // error in any of these operations means that we cannot safely delete the
  // directory.  Instead the directory will get cleaned up when seneschal exits
  // as this will delete the mount namespace and all the mounts in it.
  string contents;
  if (!base::ReadFileToString(base::FilePath("/proc/self/mounts"), &contents)) {
    PLOG(ERROR) << "Unable to read contents of /proc/self/mounts; not deleting "
                << "runtime directory";
    root_dir_.Take();
    return;
  }

  std::vector<string> mounts;
  for (base::StringPiece line : base::SplitStringPiece(
           contents, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
    std::vector<base::StringPiece> mount_data = base::SplitStringPiece(
        line, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
    if (mount_data.size() < 6) {
      LOG(ERROR) << "Invalid mount data: " << line;
      root_dir_.Take();
      return;
    }

    // The mount point is the second column.
    if (root_dir_.GetPath().IsParent(base::FilePath(mount_data[1]))) {
      mounts.emplace_back(mount_data[1].as_string());
    }
  }

  // Now unmount everything in reverse order.
  for (auto iter = mounts.rbegin(), end = mounts.rend(); iter != end; ++iter) {
    if (umount(iter->c_str()) != 0) {
      PLOG(ERROR) << "Unable to unmount path; not deleting runtime directory";
      root_dir_.Take();
      return;
    }
  }
}

// static
std::unique_ptr<Service> Service::Create(base::Closure quit_closure) {
  std::unique_ptr<Service> service(new Service(std::move(quit_closure)));

  if (!service->Init()) {
    service.reset();
  }

  return service;
}

Service::Service(base::Closure quit_closure)
    : next_server_handle_(1),
      quit_closure_(std::move(quit_closure)),
      weak_factory_(this) {}

bool Service::Init() {
  // Set up the dbus service.
  dbus::Bus::Options opts;
  opts.bus_type = dbus::Bus::SYSTEM;
  bus_ = new dbus::Bus(std::move(opts));

  // When authenticating with DBus a client process that wants to connect to
  // the system dbus daemon sends an authentication request with its current
  // effective uid.  The dbus daemon then uses SO_PEERCRED to verify that the
  // uid of the client process matches what it claims to be.  Normally this is
  // fine but when the client process runs inside a user namespace it thinks it
  // has uid 0 inside the namespace while the dbus daemon, which runs outside
  // the namespace, thinks it has some other uid.  To deal with this we
  // temprarily change our effective uid to match the effective uid outside the
  // user namespace and then change it back once we have authenticated with the
  // dbus daemon.
  if (seteuid(kDbusAuthUid) != 0) {
    PLOG(ERROR) << "Unable to change effective uid to " << kDbusAuthUid;
    return false;
  }

  if (!bus_->Connect()) {
    LOG(ERROR) << "Failed to connect to system bus";
    return false;
  }

  if (seteuid(0) != 0) {
    PLOG(ERROR) << "Unable to change effective uid back to 0";
    return false;
  }

  // Add chronos-access to our list of supplementary groups.  This is needed so
  // that we can access the user's files in the /home directory.
  gid_t list[NGROUPS_MAX] = {};
  int count = getgroups(NGROUPS_MAX, list);
  if (count < 0) {
    PLOG(ERROR) << "Failed to get supplementary groups";
    return false;
  }
  CHECK_LT(count, NGROUPS_MAX);

  list[count++] = kChronosAccessGid;
  if (setgroups(count, list) != 0) {
    PLOG(ERROR) << "Failed to add chronos-access to supplementary groups";
    return false;
  }

  exported_object_ =
      bus_->GetExportedObject(dbus::ObjectPath(kSeneschalServicePath));
  if (!exported_object_) {
    LOG(ERROR) << "Failed to export " << kSeneschalServicePath << " object";
    return false;
  }

  using ServiceMethod =
      std::unique_ptr<dbus::Response> (Service::*)(dbus::MethodCall*);
  const std::map<const char*, ServiceMethod> kServiceMethods = {
      {kStartServerMethod, &Service::StartServer},
      {kStopServerMethod, &Service::StopServer},
      {kSharePathMethod, &Service::SharePath},
      {kUnsharePathMethod, &Service::UnsharePath},
  };

  for (const auto& iter : kServiceMethods) {
    bool ret = exported_object_->ExportMethodAndBlock(
        kSeneschalInterface, iter.first,
        base::Bind(&HandleSynchronousDBusMethodCall,
                   base::Bind(iter.second, base::Unretained(this))));
    if (!ret) {
      LOG(ERROR) << "Failed to export method " << iter.first;
      return false;
    }
  }

  if (!bus_->RequestOwnershipAndBlock(kSeneschalServiceName,
                                      dbus::Bus::REQUIRE_PRIMARY)) {
    LOG(ERROR) << "Failed to take ownership of " << kSeneschalServiceName;
    return false;
  }

  // Set up the signalfd for receiving SIGCHLD and SIGTERM.
  sigset_t mask;
  sigemptyset(&mask);
  sigaddset(&mask, SIGCHLD);
  sigaddset(&mask, SIGTERM);

  signal_fd_.reset(signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC));
  if (!signal_fd_.is_valid()) {
    PLOG(ERROR) << "Failed to create signalfd";
    return false;
  }

  watcher_ = base::FileDescriptorWatcher::WatchReadable(
      signal_fd_.get(),
      base::BindRepeating(&Service::OnSignalReadable, base::Unretained(this)));
  if (!watcher_) {
    LOG(ERROR) << "Failed to watch signalfd";
    return false;
  }

  // Now block signals from the normal signal handling path so that we will get
  // them via the signalfd.
  if (sigprocmask(SIG_BLOCK, &mask, nullptr) < 0) {
    PLOG(ERROR) << "Failed to block signals via sigprocmask";
    return false;
  }

  return true;
}

void Service::OnSignalReadable() {
  struct signalfd_siginfo siginfo;
  if (read(signal_fd_.get(), &siginfo, sizeof(siginfo)) != sizeof(siginfo)) {
    PLOG(ERROR) << "Failed to read from signalfd";
    return;
  }

  if (siginfo.ssi_signo == SIGCHLD) {
    HandleChildExit();
  } else if (siginfo.ssi_signo == SIGTERM) {
    HandleSigterm();
  } else {
    LOG(ERROR) << "Received unknown signal from signal fd: "
               << strsignal(siginfo.ssi_signo);
  }
}

void Service::HandleChildExit() {
  // We can't just rely on the information in the siginfo structure because
  // more than one child may have exited but only one SIGCHLD will be
  // generated.
  while (true) {
    int status;
    pid_t pid = waitpid(-1, &status, WNOHANG);
    if (pid <= 0) {
      if (pid == -1 && errno != ECHILD) {
        PLOG(ERROR) << "Unable to reap child processes";
      }
      break;
    }

    if (WIFEXITED(status)) {
      LOG(INFO) << "Process " << pid << " exited with status "
                << WEXITSTATUS(status);
    } else if (WIFSIGNALED(status)) {
      LOG(INFO) << "Process " << pid << " killed by signal " << WTERMSIG(status)
                << (WCOREDUMP(status) ? " (core dumped)" : "");
    } else {
      LOG(WARNING) << "Unknown exit status " << status << " for process "
                   << pid;
    }

    // See if this is a process we launched.
    for (const auto& pair : servers_) {
      if (pid == pair.second.pid()) {
        servers_.erase(pair.first);
        break;
      }
    }
  }
}

void Service::HandleSigterm() {
  LOG(INFO) << "Shutting down due to SIGTERM";

  // Close our connection to the bus.
  bus_->ShutdownAndBlock();

  // Stop the message loop.
  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure_);
}

// Handles a request to start a new 9p server.
std::unique_ptr<dbus::Response> Service::StartServer(
    dbus::MethodCall* method_call) {
  LOG(INFO) << "Received request to start new 9p server";

  std::unique_ptr<dbus::Response> dbus_response(
      dbus::Response::FromMethodCall(method_call));

  dbus::MessageReader reader(method_call);
  dbus::MessageWriter writer(dbus_response.get());

  StartServerRequest request;
  StartServerResponse response;

  if (!reader.PopArrayOfBytesAsProto(&request)) {
    LOG(ERROR) << "Unable to parse StartServerRequest from message";
    response.set_failure_reason("Unable to parse protobuf");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  base::ScopedTempDir root_dir;
  if (!root_dir.CreateUniqueTempDirUnderPath(base::FilePath(kRuntimeDir))) {
    LOG(ERROR) << "Unable to create working dir for server";
    response.set_failure_reason("Unable to create working dir for server");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Make sure the child process has permission to read the contents.
  if (chmod(root_dir.GetPath().value().c_str(), 0755) != 0) {
    PLOG(ERROR) << "Failed to change permissions for "
                << root_dir.GetPath().value();
    response.set_failure_reason(
        "Failed to change permissions for server's working dir");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Create the directory that the server will serve to clients.  Offset the
  // root path by 1 because Append wants relative paths.
  base::FilePath client_root = root_dir.GetPath().Append(&kServerRoot[1]);
  if (mkdir(client_root.value().c_str(), 0755) != 0) {
    PLOG(ERROR) << "Unable to create server root dir";
    response.set_failure_reason("Unable to create server root dir");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Get the listening address and any extra command line options.
  std::vector<string> args = {kServerPath, "-r", kServerRoot};

  for (const auto& idmap : request.uid_maps()) {
    args.emplace_back("--uid_map");
    args.emplace_back(
        base::StringPrintf("%u:%u", idmap.server(), idmap.client()));
  }

  for (const auto& idmap : request.gid_maps()) {
    args.emplace_back("--gid_map");
    args.emplace_back(
        base::StringPrintf("%u:%u", idmap.server(), idmap.client()));
  }

  base::ScopedFD listen_fd;
  bool valid_address = false;
  switch (request.listen_address_case()) {
    case StartServerRequest::kVsock: {
      const VsockAddress& addr = request.vsock();
      if (addr.accept_cid() < 3) {
        LOG(ERROR) << "Missing or invalid accept_cid field in vsock address: "
                   << addr.accept_cid();
        break;
      }

      args.emplace_back("--accept_cid");
      args.emplace_back(std::to_string(addr.accept_cid()));
      args.emplace_back(string("vsock:") + std::to_string(addr.port()));
      valid_address = true;
      break;
    }
    case StartServerRequest::kFd: {
      if (!reader.PopFileDescriptor(&listen_fd)) {
        LOG(ERROR) << "No fd found in incoming message";
        break;
      }

      // Clear close-on-exec as this FD needs to be passed to 9s.
      int flags = fcntl(listen_fd.get(), F_GETFD);
      if (flags == -1) {
        PLOG(ERROR) << "Failed to get flags for passed fd";
        break;
      }
      if (fcntl(listen_fd.get(), F_SETFD, flags & ~FD_CLOEXEC) == -1) {
        PLOG(ERROR) << "Failed to clear close-on-exec flag for fd";
        break;
      }

      args.emplace_back(base::StringPrintf("unix-fd:%d", listen_fd.get()));
      valid_address = true;
      break;
    }
    case StartServerRequest::kUnixAddr:
    case StartServerRequest::kNet:
      LOG(ERROR) << "Listen address not implemented: "
                 << request.listen_address_case();
      break;
    case StartServerRequest::LISTEN_ADDRESS_NOT_SET:
      LOG(ERROR) << "Listen address not set";
      break;
    default:
      LOG(ERROR) << "Unknown listen address: " << request.listen_address_case();
      break;
  }

  if (!valid_address) {
    LOG(ERROR) << "Unable to create listening address";
    response.set_failure_reason("Unable to create listening address");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  std::vector<const char*> argv(args.size());
  std::transform(args.begin(), args.end(), argv.begin(),
                 [](const string& arg) -> const char* { return arg.c_str(); });
  argv.emplace_back(nullptr);

  ScopedMinijail jail(minijail_new());
  if (!jail) {
    LOG(ERROR) << "Unable to create minijail";
    response.set_failure_reason("Unable to create minijail");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Set up a new mount namespace but allow bind mounts from the parent
  // namespace to propagate into the server's namespace.
  minijail_namespace_vfs(jail.get());
  minijail_remount_mode(jail.get(), MS_SLAVE);

  // Since we are going to be in a user namespace all bind mounts have to use
  // MS_REC.
  constexpr struct {
    const char* src;
    bool writable;
  } bind_mounts[] = {
      {
          .src = "/proc",
          .writable = false,
      },
      {
          .src = "/dev/null",
          .writable = true,
      },
      {
          .src = "/dev/log",
          .writable = true,
      },
  };

  for (const auto& bind_mount : bind_mounts) {
    int flags = MS_BIND | MS_REC;
    if (!bind_mount.writable) {
      flags |= MS_RDONLY;
    }

    int ret = minijail_mount(jail.get(), bind_mount.src, bind_mount.src, "bind",
                             flags);
    if (ret < 0) {
      LOG(ERROR) << "Failed to bind mount " << bind_mount.src << ": "
                 << strerror(-ret);
      response.set_failure_reason("Unable to set up server jail");
      writer.AppendProtoAsArrayOfBytes(response);
      return dbus_response;
    }
  }

  // Add android-everybody for access to android files.
  minijail_set_supplementary_gids(jail.get(), base::size(kSupplementaryGroups),
                                  kSupplementaryGroups);
  minijail_change_uid(jail.get(), kChronosUid);
  minijail_change_gid(jail.get(), kChronosGid);

  // The process can only see what is in its root directory.
  int ret =
      minijail_enter_pivot_root(jail.get(), root_dir.GetPath().value().c_str());
  if (ret < 0) {
    LOG(ERROR) << "Unable to configure pivot_root: " << strerror(-ret);
    response.set_failure_reason("Unable to configure pivot_root");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // We will manage this process's lifetime.
  minijail_run_as_init(jail.get());

  // It doesn't need any caps or any new privileges.
  minijail_use_caps(jail.get(), 0);
  minijail_no_new_privs(jail.get());

  // Use a seccomp filter.
  minijail_log_seccomp_filter_failures(jail.get());
  minijail_parse_seccomp_filters(jail.get(), kSeccompPolicyPath);
  minijail_use_seccomp_filter(jail.get());

  // Reset the signal mask since we block SIGCHLD and SIGTERM in this process
  // for signalfd.
  minijail_reset_signal_mask(jail.get());
  minijail_reset_signal_handlers(jail.get());

  // Launch the server.
  pid_t child_pid = 0;
  ret = minijail_run_pid(jail.get(), kServerPath,
                         const_cast<char* const*>(argv.data()), &child_pid);
  if (ret < 0) {
    LOG(ERROR) << "Unable to spawn server process: " << strerror(-ret);
    response.set_failure_reason("Unable to spawn server");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // We're done.
  LOG(INFO) << "Started server on " << root_dir.GetPath().value();

  uint32_t handle = next_server_handle_++;
  servers_.emplace(handle, ServerInfo(child_pid, root_dir.Take()));

  response.set_success(true);
  response.set_handle(handle);
  writer.AppendProtoAsArrayOfBytes(response);
  return dbus_response;
}

// Handles a request to stop a running 9p server.
std::unique_ptr<dbus::Response> Service::StopServer(
    dbus::MethodCall* method_call) {
  LOG(INFO) << "Received request to stop server";

  std::unique_ptr<dbus::Response> dbus_response(
      dbus::Response::FromMethodCall(method_call));

  dbus::MessageReader reader(method_call);
  dbus::MessageWriter writer(dbus_response.get());

  StopServerRequest request;
  StopServerResponse response;

  if (!reader.PopArrayOfBytesAsProto(&request)) {
    LOG(ERROR) << "Unable to parse StopServerRequest from message";
    response.set_failure_reason("Unable to parse protobuf");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  const auto& iter = servers_.find(request.handle());
  if (iter == servers_.end()) {
    // The server is gone.  Nothing left to do here.
    response.set_success(true);
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Otherwise we send the process a SIGTERM and report success while lazily
  // ensuring the server will exit.  This works because we don't reuse handles
  // (unless we somehow spawn ~4 billion servers in ~2 seconds).
  if (kill(iter->second.pid(), SIGTERM) != 0 && errno != ESRCH) {
    PLOG(ERROR) << "Unable to send SIGTERM to child process";
    response.set_failure_reason("Unable to send signal to child process");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
      FROM_HERE,
      base::Bind(&Service::KillServer, weak_factory_.GetWeakPtr(),
                 request.handle()),
      kServerExitTimeout);

  response.set_success(true);
  writer.AppendProtoAsArrayOfBytes(response);
  return dbus_response;
}

// Handles a request to share a path with a running server.
std::unique_ptr<dbus::Response> Service::SharePath(
    dbus::MethodCall* method_call) {
  LOG(INFO) << "Received request to share path with server";

  std::unique_ptr<dbus::Response> dbus_response(
      dbus::Response::FromMethodCall(method_call));

  dbus::MessageReader reader(method_call);
  dbus::MessageWriter writer(dbus_response.get());

  SharePathRequest request;
  SharePathResponse response;

  if (!reader.PopArrayOfBytesAsProto(&request)) {
    LOG(ERROR) << "Unable to parse SharePathRequest from message";
    response.set_failure_reason("Unable to parse protobuf");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  const auto& iter = servers_.find(request.handle());
  if (iter == servers_.end()) {
    LOG(ERROR) << "Requested server does not exist";
    response.set_failure_reason("Requested server does not exist");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Validate path.
  base::FilePath path(request.shared_path().path());
  if (path.IsAbsolute() || path.ReferencesParent() ||
      path.BaseName().value() == ".") {
    LOG(ERROR) << "Requested path references parent, is absolute, or ends "
               << "with ./";
    response.set_failure_reason(
        "Path must be relative and cannot reference parent components nor end "
        "with \".\"");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Validate owner_id.
  base::FilePath owner_id(request.owner_id());
  bool owner_id_required =
      request.storage_location() == SharePathRequest::DOWNLOADS ||
      request.storage_location() == SharePathRequest::MY_FILES ||
      request.storage_location() == SharePathRequest::LINUX_FILES;
  if (owner_id.ReferencesParent() || owner_id.BaseName() != owner_id ||
      (owner_id_required && owner_id.value().size() == 0)) {
    LOG(ERROR) << "owner_id references parent, or is "
                  "more than 1 component, or is required and not populated";
    response.set_failure_reason("owner_id must be a single valid component");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Validate drivefs_mount_name.
  base::FilePath drivefs_mount_name(request.drivefs_mount_name());
  bool drivefs_mount_name_required =
      request.storage_location() == SharePathRequest::DRIVEFS_MY_DRIVE ||
      request.storage_location() == SharePathRequest::DRIVEFS_TEAM_DRIVES ||
      request.storage_location() == SharePathRequest::DRIVEFS_COMPUTERS;
  if (drivefs_mount_name.ReferencesParent() ||
      drivefs_mount_name.BaseName() != drivefs_mount_name ||
      (drivefs_mount_name_required &&
       !base::StartsWith(drivefs_mount_name.value(), "drivefs-",
                         base::CompareCase::SENSITIVE))) {
    LOG(ERROR) << "drivefs_mount_name references parent, or is "
                  "more than 1 component, or is required and not populated";
    response.set_failure_reason(
        "drivefs_mount_name must be a single valid component");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Build the source and destination directories.
  base::FilePath src;
  base::FilePath dst =
      iter->second.root_dir().GetPath().Append(&kServerRoot[1]);

  // Used later to strip out the prefix from the destination so that we return
  // the relative path to the shared target.
  const size_t prefix_len = dst.value().size() + 1;

  switch (request.storage_location()) {
    case SharePathRequest::DOWNLOADS:
      src = base::FilePath("/home/user/").Append(owner_id).Append("Downloads");
      dst = dst.Append("MyFiles").Append("Downloads");
      break;
    case SharePathRequest::DRIVEFS_MY_DRIVE:
      src = base::FilePath("/media/fuse/")
                .Append(drivefs_mount_name)
                .Append("root");
      dst = dst.Append("GoogleDrive").Append("MyDrive");
      break;
    case SharePathRequest::DRIVEFS_TEAM_DRIVES:
      src = base::FilePath("/media/fuse/")
                .Append(drivefs_mount_name)
                .Append("team_drives");
      dst = dst.Append("GoogleDrive").Append("SharedDrives");
      break;
    case SharePathRequest::DRIVEFS_COMPUTERS:
      src = base::FilePath("/media/fuse/")
                .Append(drivefs_mount_name)
                .Append("Computers");
      dst = dst.Append("GoogleDrive").Append("Computers");
      break;
    // Note: DriveFs .Trash directory must not ever be shared since it would
    // allow linux apps to make permanent deletes to Drive.
    case SharePathRequest::REMOVABLE:
      src = base::FilePath("/media/removable");
      dst = dst.Append("removable");
      break;
    case SharePathRequest::MY_FILES:
      src = base::FilePath("/home/user/").Append(owner_id).Append("MyFiles");
      dst = dst.Append("MyFiles");
      break;
    case SharePathRequest::PLAY_FILES:
      src = base::FilePath("/run/arc/sdcard/write/emulated/0");
      dst = dst.Append("PlayFiles");
      break;
    case SharePathRequest::LINUX_FILES:
      src = base::FilePath("/media/fuse/")
                .Append(base::JoinString(
                    {"crostini", owner_id.value(), "termina", "penguin"}, "_"));
      dst = dst.Append("LinuxFiles");
      break;
    case SharePathRequest::FONTS:
      src = base::FilePath("/usr/share/fonts");
      dst = dst.Append("fonts");
      break;
    case SharePathRequest::ARCHIVE:
      src = base::FilePath("/media/archive");
      dst = dst.Append("archive");
      break;
    default:
      LOG(ERROR) << "Unknown storage location: " << request.storage_location();
      response.set_failure_reason("Unknown storage location");
      writer.AppendProtoAsArrayOfBytes(response);
      return dbus_response;
  }

  // Get the remaining path.

  src = src.Append(path);
  if (!base::PathExists(src)) {
    LOG(ERROR) << "Requested path does not exist";
    response.set_failure_reason("Requested path does not exist");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  base::ScopedFD src_fd(brillo::OpenSafely(src, O_RDONLY | O_CLOEXEC, 0600));
  if (!src_fd.is_valid()) {
    LOG(ERROR) << "Requested path may contain symlinks or point to a "
               << "non-regular file or directory";
    response.set_failure_reason(
        "Requested path may contain symlinks or point to a non-regular "
        "file/directory");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  dst = dst.Append(path);
  // The destination directory may already exist either because one of its
  // children was shared and it was automatically created or one of its parents
  // was shared and it's already visible.
  if (!base::PathExists(dst)) {
    // First create everything up to the basename.
    if (!MkdirRecursively(dst.DirName())) {
      response.set_failure_reason(
          "Failed to create parent directory for destination");
      writer.AppendProtoAsArrayOfBytes(response);
      return dbus_response;
    }

    // Then create a file or directory, as necessary.
    struct stat info;
    if (fstat(src_fd.get(), &info) != 0) {
      PLOG(ERROR) << "Unable to stat source path";
      response.set_failure_reason("Unable to stat source path");
      writer.AppendProtoAsArrayOfBytes(response);
      return dbus_response;
    }

    if (S_ISDIR(info.st_mode)) {
      if (mkdir(dst.value().c_str(), 0700) != 0 && errno != EEXIST) {
        PLOG(ERROR) << "Unable to create destination directory";
        response.set_failure_reason("Unable to create destination directory");
        writer.AppendProtoAsArrayOfBytes(response);
        return dbus_response;
      }
    } else {
      base::ScopedFD file(open(dst.value().c_str(),
                               O_WRONLY | O_CREAT | O_CLOEXEC | O_NONBLOCK,
                               0600));
      if (!file.is_valid()) {
        PLOG(ERROR) << "Unable to create destination file";
        response.set_failure_reason("Unable to create destination file");
        writer.AppendProtoAsArrayOfBytes(response);
        return dbus_response;
      }
    }
  }

  // Do the mount.
  unsigned long flags = MS_BIND | MS_REC;  // NOLINT(runtime/int)
  string proc_path = base::StringPrintf("/proc/self/fd/%d", src_fd.get());
  const char* source = proc_path.c_str();
  const char* target = dst.value().c_str();
  if (mount(source, target, "none", flags, nullptr) != 0) {
    PLOG(ERROR) << "Unable to create bind mount";
    response.set_failure_reason("Unable to create bind mount");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Left out because we do not currently have permissions to change the flags
  // of a mount, even if it reduces privilege.  Thanks, Torvalds.
  // We cannot specify `MS_BIND` and `MS_RDONLY` in the same mount call so
  // we have remount the path to make it read-only.
  // if (!request.shared_path().writable()) {
  //   flags |= MS_REMOUNT | MS_RDONLY;
  //   if (mount(source, target, "none", flags, nullptr) != 0) {
  //     PLOG(ERROR) << "Unable to remount read-only";

  //     // Unmount the target so that we don't leak it in a writable state.
  //     // There's not a lot we can do in case of failure here.
  //     umount2(target, MNT_DETACH);
  //     // TODO: also delete the path

  //     response.set_failure_reason("Unable to remount read-only");
  //     writer.AppendProtoAsArrayOfBytes(response);
  //     return dbus_response;
  //   }
  // }

  response.set_success(true);
  response.set_path(dst.value().substr(prefix_len));
  writer.AppendProtoAsArrayOfBytes(response);
  return dbus_response;
}

// Handles a request to unshare a path with a running server.
std::unique_ptr<dbus::Response> Service::UnsharePath(
    dbus::MethodCall* method_call) {
  LOG(INFO) << "Received request to unshare path with server";

  std::unique_ptr<dbus::Response> dbus_response(
      dbus::Response::FromMethodCall(method_call));

  dbus::MessageReader reader(method_call);
  dbus::MessageWriter writer(dbus_response.get());

  UnsharePathRequest request;
  UnsharePathResponse response;

  if (!reader.PopArrayOfBytesAsProto(&request)) {
    LOG(ERROR) << "Unable to parse UnsharePathRequest from message";
    response.set_failure_reason("Unable to parse protobuf");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  const auto& iter = servers_.find(request.handle());
  if (iter == servers_.end()) {
    LOG(ERROR) << "Requested server does not exist";
    response.set_failure_reason("Requested server does not exist");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Validate path.
  base::FilePath path(request.path());
  if (path.empty() || path.IsAbsolute() || path.ReferencesParent() ||
      path.BaseName().value() == ".") {
    LOG(ERROR) << "Requested path is empty, references parent, is absolute, or "
                  "ends with ./";
    response.set_failure_reason(
        "Path must be non-empty, relative, cannot reference parent components, "
        "nor end with \".\"");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  base::FilePath server_root =
      iter->second.root_dir().GetPath().Append(&kServerRoot[1]);
  base::FilePath dst = server_root.Append(path);
  base::FilePath my_files = server_root.Append("MyFiles");
  base::FilePath my_files_downloads = my_files.Append("Downloads");
  // Ensure path exists.
  if (!base::PathExists(dst)) {
    LOG(ERROR) << "Unshare path does not exist";
    response.set_failure_reason("Unshare path does not exist");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // After unmounting, clean up empty directories.  Assume at first that we can
  // delete the topmost directory under server_root, but validate / modify this
  // path to ensure it does not contain any other mount points.  E.g. if
  // dst=<server_root>/MyFiles/a/b1/c/d, then assume we can delete
  // <server_root>/MyFiles, but if another mount exists at or under
  // <server_root>/MyFiles/a/b2, then we only delete from
  // <server_root>/MyFiles/a/b1.
  base::FilePath path_to_delete = server_root;
  std::vector<std::string> server_root_components;
  server_root.GetComponents(&server_root_components);
  size_t path_to_delete_depth = server_root_components.size();
  std::vector<std::string> dst_components;
  dst.GetComponents(&dst_components);

  // Ensure path is listed in /proc/self/mounts and has no parents within
  // server_root.
  bool path_is_mount = false;
  bool path_has_parent_mount = false;
  base::ScopedFILE mountinfo(fopen("/proc/self/mounts", "r"));
  if (!mountinfo) {
    LOG(ERROR) << "Failed to open /proc/self/mounts";
    response.set_failure_reason("Failed to open /proc/self/mounts");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }
  // List of paths to be unmounted includes path and any children.
  std::vector<base::FilePath> mount_points;
  char buf[1024 + 4];
  struct mntent entry;
  while (getmntent_r(mountinfo.get(), &entry, buf, sizeof(buf)) != nullptr) {
    base::FilePath mount_point(entry.mnt_dir);
    if (mount_point == dst) {
      // Mount is dst.  This is expected/required that one entry will match.
      path_is_mount = true;
      mount_points.emplace_back(mount_point);
    } else if (dst.IsParent(mount_point)) {
      // Mount is a child of dst.  This is OK, we will unmount it before
      // unmounting dst.
      mount_points.emplace_back(mount_point);
    } else if (server_root.IsParent(mount_point) && mount_point.IsParent(dst)) {
      // Mount is a parent of dst.  This is an error condition and we will soon
      // fail.
      path_has_parent_mount = true;
    } else {
      // Modify path_to_delete if required so it does not contain mount_point.
      std::vector<std::string> mount_point_components;
      mount_point.GetComponents(&mount_point_components);
      for (size_t i = 0;
           i < dst_components.size() - 1 && i < mount_point_components.size() &&
           dst_components[i] == mount_point_components[i];
           ++i) {
        if (i == path_to_delete_depth) {
          path_to_delete =
              path_to_delete.Append(dst_components[path_to_delete_depth++]);
        }
      }
    }
  }
  // Set path_to_delete to have 1 more component past server_root or any path
  // common with another mount.
  path_to_delete =
      path_to_delete.Append(dst_components[path_to_delete_depth++]);

  if (!path_is_mount) {
    LOG(ERROR) << "Path is not a mount point";
    response.set_failure_reason("Path is not a mount point");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }
  if (path_has_parent_mount) {
    LOG(ERROR) << "Path has a parent mount point";
    response.set_failure_reason("Path has a parent mount point");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // In reverse order, unmount paths.
  for (auto iter = mount_points.rbegin(), end = mount_points.rend();
       iter != end; ++iter) {
    if (umount(iter->value().c_str()) != 0) {
      // When MyFiles is shared, its MyFiles/Downloads mount propagates. It
      // seems that the kernel does not allow us to unmount MyFiles/Downloads
      // with EINVAL, and then also fails to unmount MyFiles with EBUSY even
      // when no files are open.
      if (errno == EINVAL && dst == my_files &&
          iter->value() == my_files_downloads.value()) {
        // Ignore EINVAL when unsharing MyFiles and MyFiles/Downloads fails.
        PLOG(WARNING)
            << "Unmount MyFiles/Downloads failed with EINVAL, ignoring";
        continue;
      } else if (errno == EBUSY && iter->value() == my_files.value()) {
        // If/when unmount MyFiles fails with EBUSY, we retry with MNT_DETACH.
        PLOG(WARNING)
            << "Unmount MyFiles failed with EBUSY, attempting MNT_DETACH";
        if (umount2(iter->value().c_str(), MNT_DETACH) == 0) {
          continue;
        }
      }
      PLOG(ERROR) << "Failed to unmount";
      response.set_failure_reason("Failed to unmount");
      writer.AppendProtoAsArrayOfBytes(response);
      return dbus_response;
    }
  }

  // Remove path_to_delete.  Recursive is required to delete any children mount
  // dirs that were created prior to this path being mounted, and any empty
  // directories that were created for this mount.  Recursive delete is safe
  // since no mounts exist under this directory.
  if (!base::DeleteFile(path_to_delete, true)) {
    LOG(ERROR) << "Delete path failed";
    response.set_failure_reason("Delete path failed");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  response.set_success(true);
  writer.AppendProtoAsArrayOfBytes(response);
  return dbus_response;
}

// Forcibly kills a server if it hasn't already exited.
void Service::KillServer(uint32_t handle) {
  const auto& iter = servers_.find(handle);
  if (iter != servers_.end()) {
    // Kill it with fire.
    if (kill(iter->second.pid(), SIGKILL) != 0) {
      PLOG(ERROR) << "Unable to send SIGKILL to child process";
    }
  }
  // We reap the child process through the normal sigchld handling mechanism.
}

}  // namespace seneschal
}  // namespace vm_tools
