// Copyright 2017 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 "cryptohome/dircrypto_util.h"

#include <string>

#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>

extern "C" {
#include <ext2fs/ext2_fs.h>
#include <keyutils.h>
}

#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/files/scoped_file.h>
#include <base/posix/eintr_wrapper.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_util.h>
#include <brillo/secure_blob.h>

// Add missing chromeos specific partition wide drop cache.
#define FS_IOC_DROP_CACHE _IO('f', 129)

namespace dircrypto {

namespace {

constexpr char kKeyType[] = "logon";
constexpr char kKeyNamePrefix[] = "ext4:";
constexpr char kKeyringName[] = "dircrypt";
constexpr char kStatefulPartitionPath[] = "/mnt/stateful_partition";

key_serial_t GetSessionKeyring() {
  key_serial_t keyring =
      keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring", kKeyringName, 0);
  if (keyring == kInvalidKeySerial) {
    PLOG(ERROR) << "keyctl_search failed";
    return kInvalidKeySerial;
  }

  return keyring;
}

key_serial_t KeyReferenceToKeySerial(const brillo::SecureBlob& key_reference) {
  std::string key_name =
      kKeyNamePrefix + base::ToLowerASCII(base::HexEncode(
                           key_reference.data(), key_reference.size()));

  key_serial_t key =
      keyctl_search(GetSessionKeyring(), "logon", key_name.c_str(), 0);
  if (key == kInvalidKeySerial) {
    PLOG(ERROR) << "keyctl_search failed";
    return kInvalidKeySerial;
  }

  return key;
}

base::ScopedFD GetStatefulPartitionScopedFd() {
  base::ScopedFD fd = base::ScopedFD(
      HANDLE_EINTR(open(kStatefulPartitionPath, O_RDONLY | O_DIRECTORY)));

  if (!fd.is_valid())
    PLOG(ERROR) << "Failed to open file descriptor " << kStatefulPartitionPath;

  return fd;
}

bool DropMountCaches(const base::FilePath& dir) {
  base::ScopedFD fd(
      HANDLE_EINTR(open(dir.value().c_str(), O_RDONLY | O_DIRECTORY)));
  if (!fd.is_valid()) {
    PLOG(ERROR) << "Invalid directory: " << dir.value();
    return false;
  }

  if (ioctl(fd.get(), FS_IOC_DROP_CACHE, nullptr) < 0) {
    PLOG(ERROR) << "Failed: drop cache for mount point. Dir:" << dir.value();
    return false;
  }

  return true;
}

void BuildFscryptKeySpec(const KeyReference& key_reference,
                         struct fscrypt_key_specifier* key_spec) {
  switch (key_reference.policy_version) {
    case FSCRYPT_POLICY_V1:
      key_spec->type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR;
      DCHECK_EQ(FSCRYPT_KEY_DESCRIPTOR_SIZE, key_reference.reference.size());
      memcpy(key_spec->u.descriptor, key_reference.reference.char_data(),
             key_reference.reference.size());
      break;
    case FSCRYPT_POLICY_V2:
      key_spec->type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
      break;
    default:
      NOTREACHED() << "Invalid policy version";
  }
}

}  // namespace

// Kernel versions before 5.4 do not support the fscrypt key management ioctls.
// In absence of these ioctls, we fall back to the legacy interface of adding
// removing keys.
namespace legacy {

static bool AddKeyToSessionKeyring(const brillo::SecureBlob& key,
                                   KeyReference* key_reference) {
  if (key.size() > FS_MAX_KEY_SIZE ||
      key_reference->reference.size() != FS_KEY_DESCRIPTOR_SIZE) {
    LOG(ERROR) << "Invalid arguments: key.size() = " << key.size()
               << "key_descriptor.size() = " << key_reference->reference.size();
    return false;
  }
  key_serial_t keyring = GetSessionKeyring();
  if (keyring == kInvalidKeySerial) {
    PLOG(ERROR) << "keyctl_search failed";
    return false;
  }
  struct fscrypt_key fs_key = {};
  fs_key.mode = FS_ENCRYPTION_MODE_AES_256_XTS;
  memcpy(fs_key.raw, key.char_data(), key.size());
  fs_key.size = key.size();
  std::string key_name = kKeyNamePrefix + base::ToLowerASCII(base::HexEncode(
                                              key_reference->reference.data(),
                                              key_reference->reference.size()));
  key_serial_t key_serial = add_key(kKeyType, key_name.c_str(), &fs_key,
                                    sizeof(fscrypt_key), keyring);
  if (key_serial == kInvalidKeySerial) {
    PLOG(ERROR) << "Failed to insert key into keyring";
    return false;
  }

  /* Set the permission on the key.
   * Possessor: (everyone given the key is in a session keyring belonging to
   * init):
   * -- View, Search
   * User: (root)
   * -- View, Search, Write, Setattr
   * Group, Other:
   * -- None
   */
  const key_perm_t kPermissions = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_USR_VIEW |
                                  KEY_USR_WRITE | KEY_USR_SEARCH |
                                  KEY_USR_SETATTR;
  if (keyctl_setperm(key_serial, kPermissions) != 0) {
    PLOG(ERROR) << "Could not change permission on key " << key_serial;
    return false;
  }
  return true;
}

static bool UnlinkSessionKey(const KeyReference& key_reference) {
  key_serial_t keyring = GetSessionKeyring();
  key_serial_t key = KeyReferenceToKeySerial(key_reference.reference);

  if (key == kInvalidKeySerial || keyring == kInvalidKeySerial)
    return false;

  if (keyctl_unlink(key, keyring) == -1) {
    PLOG(ERROR) << "Failed to unlink the key";
    return false;
  }
  return true;
}

static bool InvalidateSessionKey(const KeyReference& key_reference,
                                 const base::FilePath& mount_path) {
  // First, attempt to selectively drop caches for mount point.
  // This can fail if the directory does not support the operation or if
  // the process does not have the correct capabilities (CAP_SYS_ADMIN).
  if (!DropMountCaches(mount_path)) {
    LOG(ERROR) << "Failed to drop cache for user mount.";
    // Use drop_caches to drop all clear cache. Otherwise, cached decrypted data
    // will stay visible. This should invalidate the key provided no one touches
    // the encrypted directories while this function is running.
    constexpr char kData = '3';
    if (base::WriteFile(base::FilePath("/proc/sys/vm/drop_caches"), &kData,
                        sizeof(kData)) != sizeof(kData)) {
      LOG(ERROR) << "Failed to drop all caches.";
      return false;
    }
  }

  // At this point, the key should be invalidated, but try to invalidate it just
  // in case.
  // If the key was already invaldated, this should fail with ENOKEY.
  key_serial_t keyring = GetSessionKeyring();
  key_serial_t key = KeyReferenceToKeySerial(key_reference.reference);

  if (key == kInvalidKeySerial || keyring == kInvalidKeySerial)
    return false;

  if (keyctl_invalidate(key) == 0) {
    LOG(ERROR) << "We ended up invalidating key " << key;
  } else if (errno != ENOKEY) {
    PLOG(ERROR) << "Failed to invalidate key" << key;
  }
  return true;
}

static bool RemoveSessionKey(const KeyReference& key_reference,
                             const base::FilePath& dir) {
  // Unlink the key.
  // NOTE: Even after this, the key will still stay valid as long as the
  // encrypted contents are on the page cache.
  if (!UnlinkSessionKey(key_reference)) {
    LOG(ERROR) << "Failed to unlink the key.";
  }
  // Run Sync() to make all dirty cache clear.
  sync();

  return InvalidateSessionKey(key_reference, dir);
}

}  // namespace legacy

// CheckFscryptKeyIoctlSupport is used to decide whether:
// (1) The filesystem-level keyring is supported.
// (2) Whether fscrypt v2 encryption policies can be used.
bool CheckFscryptKeyIoctlSupport() {
  base::ScopedFD fd = GetStatefulPartitionScopedFd();
  if (!fd.is_valid()) {
    PLOG(ERROR) << "Failed to open stateful partition";
    return false;
  }

  errno = 0;
  bool ret = false;

  ioctl(fd.get(), FS_IOC_ADD_ENCRYPTION_KEY, nullptr);
  if (errno != EOPNOTSUPP && errno != ENOTTY)
    ret = true;

  if (!ret)
    VLOG(3) << "fscrypt v2 encryption policies not supported; "
            << "falling back to v1 encryption policies.";

  return ret;
}

bool SetDirectoryKey(const base::FilePath& dir,
                     const KeyReference& key_reference) {
  base::ScopedFD fd(
      HANDLE_EINTR(open(dir.value().c_str(), O_RDONLY | O_DIRECTORY)));
  if (!fd.is_valid()) {
    PLOG(ERROR) << "Fscrypt: Invalid directory " << dir.value();
    return false;
  }

  union {
    struct fscrypt_policy_v1 v1;
    struct fscrypt_policy_v2 v2;
  } policy;

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

  switch (key_reference.policy_version) {
    case FSCRYPT_POLICY_V1:
      DCHECK_EQ(static_cast<size_t>(FSCRYPT_KEY_DESCRIPTOR_SIZE),
                key_reference.reference.size());
      policy.v1.version = FSCRYPT_POLICY_V1;
      policy.v1.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
      policy.v1.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
      policy.v1.flags = 0;
      memcpy(policy.v1.master_key_descriptor, key_reference.reference.data(),
             key_reference.reference.size());
      break;
    case FSCRYPT_POLICY_V2:
      DCHECK_EQ(static_cast<size_t>(FSCRYPT_KEY_IDENTIFIER_SIZE),
                key_reference.reference.size());
      policy.v2.version = FSCRYPT_POLICY_V2;
      policy.v2.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
      policy.v2.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
      policy.v2.flags = FSCRYPT_POLICY_FLAGS_PAD_16;
      memcpy(policy.v2.master_key_identifier, key_reference.reference.data(),
             key_reference.reference.size());
      break;
    default:
      NOTREACHED() << "Invalid encryption policy version";
  }

  if (ioctl(fd.get(), FS_IOC_SET_ENCRYPTION_POLICY, &policy) < 0) {
    PLOG(ERROR) << "Failed to set the encryption policy of " << dir.value();
    return false;
  }
  return true;
}

static int GetDirectoryPolicy(const base::FilePath& dir,
                              struct fscrypt_get_policy_ex_arg* arg) {
  base::ScopedFD fd(
      HANDLE_EINTR(open(dir.value().c_str(), O_RDONLY | O_DIRECTORY)));
  if (!fd.is_valid()) {
    PLOG(ERROR) << "Fscrypt: Invalid directory " << dir.value();
    errno = EINVAL;
    return -1;
  }

  int err = 0;
  // FS_IOC_GET_ENCRYPTION_POLICY only supports v1 policies.
  if (CheckFscryptKeyIoctlSupport())
    err = ioctl(fd.get(), FS_IOC_GET_ENCRYPTION_POLICY_EX, arg);
  else
    err = ioctl(fd.get(), FS_IOC_GET_ENCRYPTION_POLICY, &(arg->policy.v1));

  return err;
}

int GetDirectoryPolicyVersion(const base::FilePath& dir) {
  struct fscrypt_get_policy_ex_arg arg = {};
  memset(&arg, 0, sizeof(arg));
  arg.policy_size = sizeof(arg.policy);

  if (GetDirectoryPolicy(dir, &arg) < 0)
    return -1;

  return arg.policy.version;
}

KeyState GetDirectoryKeyState(const base::FilePath& dir) {
  struct fscrypt_get_policy_ex_arg arg = {};
  memset(&arg, 0, sizeof(arg));
  arg.policy_size = sizeof(arg.policy);

  if (GetDirectoryPolicy(dir, &arg) < 0) {
    switch (errno) {
      case ENODATA:
      case ENOENT:
        return KeyState::NO_KEY;
      case ENOTTY:
      case EOPNOTSUPP:
        return KeyState::NOT_SUPPORTED;
      default:
        PLOG(ERROR) << "Failed to get the encryption policy of " << dir.value();
        return KeyState::UNKNOWN;
    }
  }
  return KeyState::ENCRYPTED;
}

static bool AddFscryptKey(const brillo::SecureBlob& key,
                          KeyReference* key_reference) {
  brillo::SecureBlob add_key_arg(sizeof(struct fscrypt_add_key_arg) +
                                 key.size());
  struct fscrypt_add_key_arg* arg =
      (struct fscrypt_add_key_arg*)add_key_arg.data();

  BuildFscryptKeySpec(*key_reference, &(arg->key_spec));

  arg->raw_size = key.size();
  memcpy(arg->raw, key.char_data(), key.size());

  base::ScopedFD fd = GetStatefulPartitionScopedFd();
  if (!fd.is_valid())
    return false;

  if (ioctl(fd.get(), FS_IOC_ADD_ENCRYPTION_KEY, arg) < 0) {
    PLOG(ERROR) << "Failed to add encryption key";
    return false;
  }

  // For v2 policies, store the returned key identifier in the key reference.
  if (key_reference->policy_version == FSCRYPT_POLICY_V2) {
    key_reference->reference.resize(FSCRYPT_KEY_IDENTIFIER_SIZE);
    memcpy(key_reference->reference.char_data(), arg->key_spec.u.identifier,
           FSCRYPT_KEY_IDENTIFIER_SIZE);
  }

  return true;
}

static bool RemoveFscryptKey(const KeyReference& key_reference) {
  struct fscrypt_remove_key_arg arg;
  memset(&arg, 0, sizeof(fscrypt_remove_key_arg));

  BuildFscryptKeySpec(key_reference, &arg.key_spec);

  // Set the identifier for v2 policies.
  if (key_reference.policy_version == FSCRYPT_POLICY_V2) {
    memcpy(arg.key_spec.u.identifier, key_reference.reference.char_data(),
           FSCRYPT_KEY_IDENTIFIER_SIZE);
  }

  auto fd = GetStatefulPartitionScopedFd();
  if (!fd.is_valid())
    return false;

  if (ioctl(fd.get(), FS_IOC_REMOVE_ENCRYPTION_KEY, &arg) < 0) {
    PLOG(ERROR) << "Failed to add encryption key";
    return false;
  }

  // Check removal status flags if there are files still open after removing the
  // encryption key.
  if (arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS) {
    LOG(ERROR) << "Failed to remove fscrypt key: still used by other users.";
  } else if (arg.removal_status_flags &
             FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY) {
    LOG(ERROR)
        << "Some files are still in use after removing encryption key; these "
           "files were not locked.";
  }

  return true;
}

bool AddDirectoryKey(const brillo::SecureBlob& key,
                     KeyReference* key_reference) {
  return CheckFscryptKeyIoctlSupport()
             ? AddFscryptKey(key, key_reference)
             : legacy::AddKeyToSessionKeyring(key, key_reference);
}

bool RemoveDirectoryKey(const KeyReference& key_reference,
                        const base::FilePath& dir) {
  // If the key reference is empty (eg. after a crash), create
  // the key reference from the policy set on the directory.
  KeyReference ref;
  if (key_reference.reference.size() == 0) {
    struct fscrypt_get_policy_ex_arg arg;
    memset(&arg, 0, sizeof(fscrypt_get_policy_ex_arg));
    arg.policy_size = sizeof(arg.policy);

    LOG(INFO)
        << "Empty key reference; attempting to get policy from directory.";
    if (GetDirectoryPolicy(dir, &arg) < 0) {
      LOG(ERROR) << "Failed to get fscrypt policy from directory " << dir;
      return false;
    }

    switch (arg.policy.version) {
      case FSCRYPT_POLICY_V1:
        ref.reference.resize(FSCRYPT_KEY_DESCRIPTOR_SIZE);
        memcpy(ref.reference.char_data(), arg.policy.v1.master_key_descriptor,
               FSCRYPT_KEY_DESCRIPTOR_SIZE);
        ref.policy_version = FSCRYPT_POLICY_V1;
        break;
      case FSCRYPT_POLICY_V2:
        ref.reference.resize(FSCRYPT_KEY_IDENTIFIER_SIZE);
        memcpy(ref.reference.char_data(), arg.policy.v2.master_key_identifier,
               FSCRYPT_KEY_IDENTIFIER_SIZE);
        ref.policy_version = FSCRYPT_POLICY_V2;
        break;
      default:
        NOTREACHED() << "Invalid encryption policy version: "
                     << arg.policy.version;
        return false;
    }
  } else {
    ref = key_reference;
  }

  return CheckFscryptKeyIoctlSupport() ? RemoveFscryptKey(ref)
                                       : legacy::RemoveSessionKey(ref, dir);
}

}  // namespace dircrypto
