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

  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) {
    PLOG(ERROR) << "keyctl_search failed";
    return false;
  }

  if (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 invalidated, this should fail with ENOKEY.
  key_serial_t key = KeyReferenceToKeySerial(key_reference.reference);
  if (key == kInvalidKeySerial) {
    if (errno != ENOKEY) {
      PLOG(ERROR) << "Failed to find key to invalidate";
    }
    return true;
  }

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