blob: 7bf6b888b6ae4009303a9300757f3dd011c67a07 [file] [log] [blame] [edit]
// Copyright 2019 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Mounter objects carry out mount(2) and unmount(2) operations for a single
// cryptohome mount.
#ifndef CRYPTOHOME_NAMESPACE_MOUNTER_MOUNTER_H_
#define CRYPTOHOME_NAMESPACE_MOUNTER_MOUNTER_H_
#include <sys/types.h>
#include <string>
#include <unordered_map>
#include <vector>
#include <base/files/file_path.h>
#include <brillo/process/process.h>
#include <brillo/secure_blob.h>
#include <chromeos/dbus/service_constants.h>
#include <libstorage/platform/platform.h>
#include "cryptohome/storage/error.h"
#include "cryptohome/storage/mount_constants.h"
#include "cryptohome/storage/mount_stack.h"
#include "cryptohome/username.h"
namespace cryptohome {
extern const char kDefaultHomeDir[];
extern const char kEphemeralCryptohomeRootContext[];
extern const char kMigrationXattrName[];
extern const char kMigrating[];
extern const char kMigrated[];
class Mounter {
public:
Mounter(bool legacy_mount,
bool bind_mount_downloads,
libstorage::Platform* platform);
Mounter(const Mounter&) = delete;
Mounter& operator=(const Mounter&) = delete;
~Mounter() = default;
// Returns the temporary user path while we're migrating for
// http://crbug.com/224291.
static base::FilePath GetNewUserPath(const Username& username);
// Ensures that root and user mountpoints for the specified user are present.
// Returns false if the mountpoints were not present and could not be created.
bool EnsureUserMountPoints(const Username& username) const;
// Mounts the tracked subdirectories from a separate cache directory. This
// is used by LVM dm-crypt cryptohomes to separate the cache directory.
//
// Parameters
// obfuscated_username - The obfuscated form of the username
bool MountCacheSubdirectories(const ObfuscatedUsername& obfuscated_username,
const base::FilePath& data_directory);
// Sets up the ecryptfs mount.
bool SetUpEcryptfsMount(const ObfuscatedUsername& obfuscated_username,
const std::string& fek_signature,
const std::string& fnek_signature,
const base::FilePath& mount_type);
// Sets up the dircrypto mount.
void SetUpDircryptoMount(const ObfuscatedUsername& obfuscated_username);
// Sets up the dm-crypt mount.
bool SetUpDmcryptMount(const ObfuscatedUsername& obfuscated_username,
const base::FilePath& data_mount_point);
// Carries out eCryptfs/dircrypto mount(2) operations for a regular
// cryptohome.
StorageStatus PerformMount(MountType mount_type,
const Username& username,
const std::string& fek_signature,
const std::string& fnek_signature);
// Carries out dircrypto mount(2) operations for an ephemeral cryptohome.
// Does not clean up on failure.
StorageStatus PerformEphemeralMount(
const Username& username, const base::FilePath& ephemeral_loop_device);
// Unmounts all mount points.
// Relies on ForceUnmount() internally; see the caveat listed for it.
void UnmountAll();
// Returns whether an ephemeral mount operation can be performed.
bool CanPerformEphemeralMount() const;
// Returns whether a mount operation has been performed.
bool MountPerformed() const;
// Returns whether |path| is the destination of an existing mount.
bool IsPathMounted(const base::FilePath& path) const;
// Returns a list of paths that have been mounted as part of the mount.
std::vector<base::FilePath> MountedPaths() const;
private:
// Returns the mounted userhome path (e.g. /home/.shadow/.../mount/user)
//
// Parameters
// obfuscated_username - Obfuscated username field of the credentials.
base::FilePath GetMountedUserHomePath(
const ObfuscatedUsername& obfuscated_username) const;
// Returns the mounted roothome path (e.g. /home/.shadow/.../mount/root)
//
// Parameters
// obfuscated_username - Obfuscated username field of the credentials.
base::FilePath GetMountedRootHomePath(
const ObfuscatedUsername& obfuscated_username) const;
// Mounts a mount point and pushes it to the mount stack.
// Returns true if the mount succeeds, false otherwise.
//
// Parameters
// src - Path to mount from
// dest - Path to mount to
// type - Filesystem type to mount with
// options - Filesystem options to supply
bool MountAndPush(const base::FilePath& src,
const base::FilePath& dest,
const std::string& type,
const std::string& options);
// Binds a mount point, remembering it for later unmounting.
// Returns true if the bind succeeds, false otherwise.
//
// Parameters
// src - Path to bind from
// dest - Path to bind to
// is_shared - bind mount as MS_SHARED
bool BindAndPush(const base::FilePath& src,
const base::FilePath& dest,
libstorage::RemountOption remount =
libstorage::RemountOption::kNoRemount);
// If |bind_mount_downloads_| flag is set, bind mounts |user_home|/Downloads
// to |user_home|/MyFiles/Downloads so Files app can manage MyFiles as user
// volume instead of just Downloads. If the flag is not set, calls
// `MoveDownloadsToMyFiles` to migrate the user's Downloads from
// |user_home|/Downloads to |user_home|/MyFiles/Downloads.
bool HandleMyFilesDownloads(const base::FilePath& user_home);
// Attempts a migration of user's Download directory from
// |user_home|/Downloads to |user_home|/MyFiles/Downloads. Returns true if the
// migration is considered a success or has already occurred and false in all
// other scenarios.
bool MoveDownloadsToMyFiles(const base::FilePath& user_home);
// Copies the skeleton directory to the user's cryptohome.
void CopySkeleton(const base::FilePath& destination) const;
// Ensures that a specified directory exists, with all path components owned
// by libstorage::kRootUid:libstorage::kRootGid.
//
// Parameters
// dir - Directory to check
bool EnsureMountPointPath(const base::FilePath& dir) const;
// Ensures that the |num|th component of |path| is owned by |uid|:|gid| and is
// a directory.
bool EnsurePathComponent(const base::FilePath& path,
uid_t uid,
gid_t gid) const;
// Attempts to unmount a mountpoint. If the unmount fails, logs processes with
// open handles to it and performs a lazy unmount.
//
// Parameters
// src - Path mounted at |dest|
// dest - Mount point to unmount
void ForceUnmount(const base::FilePath& src, const base::FilePath& dest);
using ProbeCounts = std::unordered_map<std::string, int>;
// Moves the `from` item (file or directory) to the `to_dir` directory. The
// `to_dir` destination directory must already exist and be writable. In case
// of name collision in the destination directory, the item is also renamed
// while getting moved. No file content is actually copied by this operation.
// The item is just atomically moved and optionally renamed at the same time.
bool MoveWithConflictResolution(const base::FilePath& from,
const base::FilePath& to_dir,
ProbeCounts& probe_counts) const;
// Moves the contents of the `from_dir` directory to the `to_dir` directory.
// Renames the moved items as needed in case of name collision. The `from_dir`
// and `to_dir` directories must already exist and be writable. If everything
// works well, the `from_dir` directory should be left empty.
void MoveDirectoryContents(const base::FilePath& from_dir,
const base::FilePath& to_dir) const;
// Calls InternalMountDaemonStoreDirectories to bind-mount
// /home/.shadow/$hash/mount/root/$daemon (*)
// to
// /run/daemon-store/$daemon/$hash
// for a hardcoded list of $daemon directories.
bool MountDaemonStoreDirectories(
const base::FilePath& root_home,
const ObfuscatedUsername& obfuscated_username);
// Calls InternalMountDaemonStoreDirectories to bind-mount
// /home/.shadow/$hash/mount/root/.cache/$daemon (*)
// to
// /run/daemon-store-cache/$daemon/$hash
// for a hardcoded list of $daemon directories.
bool MountDaemonStoreCacheDirectories(
const base::FilePath& root_home,
const ObfuscatedUsername& obfuscated_username);
// This can be used to make the Cryptohome mount propagate into the daemon's
// mount namespace. See
// https://chromium.googlesource.com/chromiumos/docs/+/HEAD/sandboxing.md#securely-mounting-cryptohome-daemon-store-folders
// for details.
//
// (*) Path for a regular mount. The path is different for an ephemeral mount.
bool InternalMountDaemonStoreDirectories(
const base::FilePath& root_home,
const ObfuscatedUsername& obfuscated_username,
const char* etc_daemon_store_base_dir,
const char* run_daemon_store_base_dir);
// Sets up bind mounts from |user_home| and |root_home| to
// - /home/chronos/user (see MountLegacyHome()),
// - /home/chronos/u-<user_hash>,
// - /home/user/<user_hash>,
// - /home/root/<user_hash> and
// - /run/daemon-store/$daemon/<user_hash>
// (see MountDaemonStoreDirectories()).
// The parameters have the same meaning as in MountCryptohome resp.
// MountEphemeralCryptohomeInner. Returns true if successful, false otherwise.
bool MountHomesAndDaemonStores(const Username& username,
const ObfuscatedUsername& obfuscated_username,
const base::FilePath& user_home,
const base::FilePath& root_home);
// Mounts the legacy home directory.
// The legacy home directory is from before multiprofile and is mounted at
// /home/chronos/user.
bool MountLegacyHome(const base::FilePath& from);
// Recursively copies directory contents to the destination if the destination
// file does not exist. Sets ownership to |default_user_|.
//
// Parameters
// source - Where to copy files from
// destination - Where to copy files to
void RecursiveCopy(const base::FilePath& source,
const base::FilePath& destination) const;
// Returns true if we think there was at least one successful mount in
// the past.
bool IsFirstMountComplete(
const ObfuscatedUsername& obfuscated_username) const;
bool legacy_mount_ = true;
bool bind_mount_downloads_ = true;
// Stack of mounts (in the mount(2) sense) that have been made.
MountStack stack_;
libstorage::Platform* platform_; // Un-owned.
FRIEND_TEST(MounterTest, MountOrdering);
};
} // namespace cryptohome
#endif // CRYPTOHOME_NAMESPACE_MOUNTER_MOUNTER_H_