// 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
