blob: 1a8f771105c31c5c39770f7a8b13d6ecb0cf3203 [file] [log] [blame]
// Copyright (c) 2012 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/stateful_recovery.h"
#include <base/files/file_util.h>
#include <gtest/gtest.h>
#include "cryptohome/mock_platform.h"
#include "cryptohome/mock_service.h"
namespace cryptohome {
using base::FilePath;
using std::ostringstream;
using ::testing::DoAll;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
using ::testing::StrEq;
using ::testing::_;
TEST(StatefulRecovery, ValidRequestV1) {
MockPlatform platform;
MockService service;
std::string flag_content = "1";
EXPECT_CALL(platform,
ReadFileToString(FilePath(StatefulRecovery::kFlagFile), _))
.WillOnce(DoAll(SetArgPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform,
DeleteFile(FilePath(StatefulRecovery::kRecoverDestination), _))
.WillOnce(Return(true));
EXPECT_CALL(platform,
CreateDirectory(FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(false));
EXPECT_CALL(platform, StatVFS(FilePath(StatefulRecovery::kRecoverSource), _))
.WillOnce(Return(true));
EXPECT_CALL(platform,
WriteStringToFile(FilePath(StatefulRecovery::kRecoverBlockUsage), _))
.WillOnce(Return(true));
EXPECT_CALL(platform,
ReportFilesystemDetails(FilePath(StatefulRecovery::kRecoverSource),
FilePath(StatefulRecovery::kRecoverFilesystemDetails)))
.WillOnce(Return(true));
EXPECT_CALL(platform,
Copy(FilePath(StatefulRecovery::kRecoverSource),
FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_TRUE(recovery.Recover());
}
TEST(StatefulRecovery, ValidRequestV1WriteProtected) {
MockPlatform platform;
MockService service;
std::string flag_content = "1";
EXPECT_CALL(platform,
ReadFileToString(FilePath(StatefulRecovery::kFlagFile), _))
.WillOnce(DoAll(SetArgPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform,
DeleteFile(FilePath(StatefulRecovery::kRecoverDestination), _))
.WillOnce(Return(true));
EXPECT_CALL(platform,
CreateDirectory(FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(true));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
TEST(StatefulRecovery, ValidRequestV2) {
MockPlatform platform;
MockService service;
gboolean result = true;
std::string user = "user@example.com";
std::string passkey = "abcd1234";
std::string flag_content = "2\n" + user + "\n" + passkey;
FilePath mount_path("/home/.shadow/hashhashash/mount");
EXPECT_CALL(platform,
ReadFileToString(FilePath(StatefulRecovery::kFlagFile), _))
.WillOnce(DoAll(SetArgPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform,
DeleteFile(FilePath(StatefulRecovery::kRecoverDestination), _))
.WillOnce(Return(true));
EXPECT_CALL(platform,
CreateDirectory(FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
// CopyUserContents
EXPECT_CALL(service, Mount(StrEq(user), StrEq(passkey), false, false,
_, _, _))
.WillOnce(DoAll(SetArgPointee<5>(result), Return(true)));
EXPECT_CALL(service, GetMountPointForUser(StrEq(user), _))
.WillOnce(DoAll(SetArgPointee<1>(mount_path), Return(true)));
EXPECT_CALL(platform,
Copy(mount_path, FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
EXPECT_CALL(service, UnmountForUser(StrEq(user), _, _))
.WillOnce(DoAll(SetArgPointee<1>(result), Return(true)));
EXPECT_CALL(service, IsOwner(_))
.WillOnce(Return(true));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(true));
// CopyPartitionInfo
EXPECT_CALL(platform, StatVFS(FilePath(StatefulRecovery::kRecoverSource), _))
.WillOnce(Return(true));
EXPECT_CALL(platform,
WriteStringToFile(FilePath(StatefulRecovery::kRecoverBlockUsage), _))
.WillOnce(Return(true));
EXPECT_CALL(platform, ReportFilesystemDetails(
FilePath(StatefulRecovery::kRecoverSource),
FilePath(StatefulRecovery::kRecoverFilesystemDetails)))
.WillOnce(Return(true));
// CopyPartitionContents
EXPECT_CALL(platform, Copy(
FilePath(StatefulRecovery::kRecoverSource),
FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_TRUE(recovery.Recover());
}
TEST(StatefulRecovery, ValidRequestV2NotOwner) {
MockPlatform platform;
MockService service;
gboolean result = true;
std::string user = "user@example.com";
std::string passkey = "abcd1234";
std::string flag_content = "2\n" + user + "\n" + passkey;
FilePath mount_path("/home/.shadow/hashhashash/mount");
EXPECT_CALL(platform,
ReadFileToString(FilePath(StatefulRecovery::kFlagFile), _))
.WillOnce(DoAll(SetArgPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform,
DeleteFile(FilePath(StatefulRecovery::kRecoverDestination), _))
.WillOnce(Return(true));
EXPECT_CALL(platform,
CreateDirectory(FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
// CopyUserContents
EXPECT_CALL(service, Mount(StrEq(user), StrEq(passkey), false, false,
_, _, _))
.WillOnce(DoAll(SetArgPointee<5>(result), Return(true)));
EXPECT_CALL(service, GetMountPointForUser(StrEq(user), _))
.WillOnce(DoAll(SetArgPointee<1>(mount_path), Return(true)));
EXPECT_CALL(platform, Copy(
mount_path,
FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
EXPECT_CALL(service, UnmountForUser(StrEq(user), _, _))
.WillOnce(DoAll(SetArgPointee<1>(result), Return(true)));
EXPECT_CALL(service, IsOwner(_))
.WillOnce(Return(false));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(true));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_TRUE(recovery.Recover());
}
TEST(StatefulRecovery, ValidRequestV2BadUser) {
MockPlatform platform;
MockService service;
gboolean result = true;
std::string user = "user@example.com";
std::string passkey = "abcd1234";
std::string flag_content = "2\n" + user + "\n" + passkey;
EXPECT_CALL(platform,
ReadFileToString(FilePath(StatefulRecovery::kFlagFile), _))
.WillOnce(DoAll(SetArgPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform,
DeleteFile(FilePath(StatefulRecovery::kRecoverDestination), _))
.WillOnce(Return(true));
EXPECT_CALL(platform,
CreateDirectory(FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
// CopyUserContents
EXPECT_CALL(service, Mount(StrEq(user), StrEq(passkey), false, false,
_, _, _))
.WillOnce(DoAll(SetArgPointee<5>(result), Return(false)));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(true));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
TEST(StatefulRecovery, ValidRequestV2BadUserNotWriteProtected) {
MockPlatform platform;
MockService service;
gboolean result = true;
std::string user = "user@example.com";
std::string passkey = "abcd1234";
std::string flag_content = "2\n" + user + "\n" + passkey;
FilePath mount_path("/home/.shadow/hashhashash/mount");
EXPECT_CALL(platform,
ReadFileToString(FilePath(StatefulRecovery::kFlagFile), _))
.WillOnce(DoAll(SetArgPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform,
DeleteFile(FilePath(StatefulRecovery::kRecoverDestination), _))
.WillOnce(Return(true));
EXPECT_CALL(platform,
CreateDirectory(FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
// CopyUserContents
EXPECT_CALL(service, Mount(StrEq(user), StrEq(passkey), false, false,
_, _, _))
.WillOnce(DoAll(SetArgPointee<5>(result), Return(false)));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(false));
// CopyPartitionInfo
EXPECT_CALL(platform, StatVFS(FilePath(StatefulRecovery::kRecoverSource), _))
.WillOnce(Return(true));
EXPECT_CALL(platform,
WriteStringToFile(FilePath(StatefulRecovery::kRecoverBlockUsage), _))
.WillOnce(Return(true));
EXPECT_CALL(platform, ReportFilesystemDetails(
FilePath(StatefulRecovery::kRecoverSource),
FilePath(StatefulRecovery::kRecoverFilesystemDetails)))
.WillOnce(Return(true));
// CopyPartitionContents
EXPECT_CALL(platform, Copy(
FilePath(StatefulRecovery::kRecoverSource),
FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_TRUE(recovery.Recover());
}
TEST(StatefulRecovery, ValidRequestV2NotOwnerNotWriteProtected) {
MockPlatform platform;
MockService service;
gboolean result = true;
std::string user = "user@example.com";
std::string passkey = "abcd1234";
std::string flag_content = "2\n" + user + "\n" + passkey;
FilePath mount_path("/home/.shadow/hashhashash/mount");
EXPECT_CALL(platform,
ReadFileToString(FilePath(StatefulRecovery::kFlagFile), _))
.WillOnce(DoAll(SetArgPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform,
DeleteFile(FilePath(StatefulRecovery::kRecoverDestination), _))
.WillOnce(Return(true));
EXPECT_CALL(platform,
CreateDirectory(FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
// CopyUserContents
EXPECT_CALL(service, Mount(StrEq(user), StrEq(passkey), false, false,
_, _, _))
.WillOnce(DoAll(SetArgPointee<5>(result), Return(true)));
EXPECT_CALL(service, GetMountPointForUser(StrEq(user), _))
.WillOnce(DoAll(SetArgPointee<1>(mount_path), Return(true)));
EXPECT_CALL(platform,
Copy(mount_path, FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
EXPECT_CALL(service, UnmountForUser(StrEq(user), _, _))
.WillOnce(DoAll(SetArgPointee<1>(result), Return(true)));
EXPECT_CALL(service, IsOwner(_))
.WillOnce(Return(false));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(false));
// CopyPartitionInfo
EXPECT_CALL(platform, StatVFS(FilePath(StatefulRecovery::kRecoverSource), _))
.WillOnce(Return(true));
EXPECT_CALL(platform, WriteStringToFile(
FilePath(StatefulRecovery::kRecoverBlockUsage), _))
.WillOnce(Return(true));
EXPECT_CALL(platform, ReportFilesystemDetails(
FilePath(StatefulRecovery::kRecoverSource),
FilePath(StatefulRecovery::kRecoverFilesystemDetails)))
.WillOnce(Return(true));
// CopyPartitionContents
EXPECT_CALL(platform, Copy(
FilePath(StatefulRecovery::kRecoverSource),
FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_TRUE(recovery.Recover());
}
TEST(StatefulRecovery, InvalidFlagFileContents) {
MockPlatform platform;
MockService service;
std::string flag_content = "0 hello";
EXPECT_CALL(platform,
ReadFileToString(FilePath(StatefulRecovery::kFlagFile), _))
.WillOnce(DoAll(SetArgPointee<1>(flag_content), Return(true)));
StatefulRecovery recovery(&platform, &service);
EXPECT_FALSE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
TEST(StatefulRecovery, UnreadableFlagFile) {
MockPlatform platform;
MockService service;
EXPECT_CALL(platform,
ReadFileToString(FilePath(StatefulRecovery::kFlagFile), _))
.WillOnce(Return(false));
StatefulRecovery recovery(&platform, &service);
EXPECT_FALSE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
TEST(StatefulRecovery, UncopyableData) {
MockPlatform platform;
MockService service;
std::string flag_content = "1";
EXPECT_CALL(platform,
ReadFileToString(FilePath(StatefulRecovery::kFlagFile), _))
.WillOnce(DoAll(SetArgPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform,
DeleteFile(FilePath(StatefulRecovery::kRecoverDestination), _))
.WillOnce(Return(true));
EXPECT_CALL(platform, CreateDirectory(
FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(false));
EXPECT_CALL(platform, Copy(
FilePath(StatefulRecovery::kRecoverSource),
FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(false));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
TEST(StatefulRecovery, DirectoryCreationFailure) {
MockPlatform platform;
MockService service;
std::string flag_content = "1";
EXPECT_CALL(platform,
ReadFileToString(FilePath(StatefulRecovery::kFlagFile), _))
.WillOnce(DoAll(SetArgPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform,
DeleteFile(FilePath(StatefulRecovery::kRecoverDestination), _))
.WillOnce(Return(true));
EXPECT_CALL(platform, CreateDirectory(
FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(false));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
TEST(StatefulRecovery, StatVFSFailure) {
MockPlatform platform;
MockService service;
std::string flag_content = "1";
EXPECT_CALL(platform,
ReadFileToString(FilePath(StatefulRecovery::kFlagFile), _))
.WillOnce(DoAll(SetArgPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform,
DeleteFile(FilePath(StatefulRecovery::kRecoverDestination), _))
.WillOnce(Return(true));
EXPECT_CALL(platform, CreateDirectory(
FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(false));
EXPECT_CALL(platform, Copy(
FilePath(StatefulRecovery::kRecoverSource),
FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
EXPECT_CALL(platform, StatVFS(FilePath(StatefulRecovery::kRecoverSource), _))
.WillOnce(Return(false));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
TEST(StatefulRecovery, FilesystemDetailsFailure) {
MockPlatform platform;
MockService service;
std::string flag_content = "1";
EXPECT_CALL(platform,
ReadFileToString(FilePath(StatefulRecovery::kFlagFile), _))
.WillOnce(DoAll(SetArgPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform,
DeleteFile(FilePath(StatefulRecovery::kRecoverDestination), _))
.WillOnce(Return(true));
EXPECT_CALL(platform,
CreateDirectory(FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(false));
EXPECT_CALL(platform,
Copy(FilePath(StatefulRecovery::kRecoverSource),
FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(true));
EXPECT_CALL(platform, StatVFS(FilePath(StatefulRecovery::kRecoverSource), _))
.WillOnce(Return(true));
EXPECT_CALL(platform,
WriteStringToFile(FilePath(StatefulRecovery::kRecoverBlockUsage), _))
.WillOnce(Return(true));
EXPECT_CALL(platform, ReportFilesystemDetails(
FilePath(StatefulRecovery::kRecoverSource),
FilePath(StatefulRecovery::kRecoverFilesystemDetails)))
.WillOnce(Return(false));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
TEST(StatefulRecovery, MountsParseOk) {
Platform platform;
FilePath mount_info;
FILE *fp;
std::string device_in = "/dev/pan", device_out, mount_info_contents;
mount_info_contents.append("84 24 0:29 / ");
FilePath filesystem = FilePath("/second/star/to/the/right");
mount_info_contents.append(filesystem.value());
mount_info_contents.append(" rw,nosuid,nodev,noexec,relatime - fairyfs ");
mount_info_contents.append(device_in);
mount_info_contents.append(" rw,ecryp...");
fp = base::CreateAndOpenTemporaryFile(&mount_info);
ASSERT_TRUE(fp != NULL);
EXPECT_EQ(fwrite(mount_info_contents.c_str(),
mount_info_contents.length(), 1, fp), 1);
EXPECT_EQ(fclose(fp), 0);
platform.set_mount_info_path(mount_info);
/* Fails if item is missing. */
EXPECT_FALSE(platform.FindFilesystemDevice(
FilePath("monkey"), &device_out));
/* Works normally. */
device_out.clear();
EXPECT_TRUE(platform.FindFilesystemDevice(filesystem, &device_out));
EXPECT_TRUE(device_out == device_in);
/* Clean up. */
EXPECT_TRUE(base::DeleteFile(mount_info, false));
}
TEST(StatefulRecovery, UsageReportOk) {
Platform platform;
struct statvfs vfs;
/* Reporting on a valid location produces output. */
EXPECT_TRUE(platform.StatVFS(FilePath("/"), &vfs));
EXPECT_NE(vfs.f_blocks, 0);
/* Reporting on an invalid location fails. */
EXPECT_FALSE(platform.StatVFS(FilePath("/this/is/very/wrong"), &vfs));
/* TODO(keescook): mockable tune2fs, since it's not installed in chroot. */
}
TEST(StatefulRecovery, DestinationRecreateFailure) {
MockPlatform platform;
MockService service;
std::string flag_content = "1";
EXPECT_CALL(platform,
ReadFileToString(FilePath(StatefulRecovery::kFlagFile), _))
.WillOnce(DoAll(SetArgPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform,
DeleteFile(FilePath(StatefulRecovery::kRecoverDestination), _))
.WillOnce(Return(true));
EXPECT_CALL(platform,
CreateDirectory(FilePath(StatefulRecovery::kRecoverDestination)))
.WillOnce(Return(false));
EXPECT_CALL(platform,
Copy(_, FilePath(StatefulRecovery::kRecoverDestination)))
.Times(0);
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
} // namespace cryptohome