blob: 346bef6466aaa8e5c9a3fb5be353ea2d7cc825f1 [file] [log] [blame]
// Copyright 2018 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/mock_platform.h"
#include "cryptohome/projectid_config.h"
#include "cryptohome/storage/arc_disk_quota.h"
#include "cryptohome/storage/mock_homedirs.h"
#include <memory>
#include <string>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <sys/quota.h>
#include <sys/types.h>
using ::testing::_;
using ::testing::DoAll;
using ::testing::Ne;
using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::SetArrayArgument;
namespace cryptohome {
namespace {
constexpr char kDev[] = "/dev/mmcblk0p1";
} // namespace
class ArcDiskQuotaTest : public ::testing::Test {
public:
ArcDiskQuotaTest()
: arc_disk_quota_(&homedirs_, &platform_, base::FilePath(kArcDiskHome)) {}
ArcDiskQuotaTest(const ArcDiskQuotaTest&) = delete;
ArcDiskQuotaTest& operator=(const ArcDiskQuotaTest&) = delete;
~ArcDiskQuotaTest() override {}
protected:
MockHomeDirs homedirs_;
MockPlatform platform_;
ArcDiskQuota arc_disk_quota_;
static const uid_t kAndroidUidStart = ArcDiskQuota::kAndroidUidStart;
static const uid_t kAndroidUidEnd = ArcDiskQuota::kAndroidUidEnd;
static const gid_t kAndroidGidStart = ArcDiskQuota::kAndroidGidStart;
static const gid_t kAndroidGidEnd = ArcDiskQuota::kAndroidGidEnd;
static const uid_t kValidAndroidUid = (kAndroidUidStart + kAndroidUidEnd) / 2;
static const gid_t kValidAndroidGid = (kAndroidGidStart + kAndroidGidEnd) / 2;
static const int kValidAndroidProjectId =
(kProjectIdForAndroidFilesStart + kProjectIdForAndroidFilesEnd) / 2;
static constexpr char kObfuscatedUsername[] = "cafef00d";
};
TEST_F(ArcDiskQuotaTest, QuotaIsSupported) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(0));
// Exactly 1 Android user.
EXPECT_CALL(homedirs_, GetUnmountedAndroidDataCount()).WillOnce(Return(0));
arc_disk_quota_.Initialize();
EXPECT_EQ(true, arc_disk_quota_.IsQuotaSupported());
}
TEST_F(ArcDiskQuotaTest, QuotaIsNotSupported_NoDevice) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(""), Return(false)));
arc_disk_quota_.Initialize();
EXPECT_EQ(false, arc_disk_quota_.IsQuotaSupported());
}
TEST_F(ArcDiskQuotaTest, QuotaIsNotSupported_NoQuotaMountedDevice) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(-1));
arc_disk_quota_.Initialize();
EXPECT_EQ(false, arc_disk_quota_.IsQuotaSupported());
}
TEST_F(ArcDiskQuotaTest, QuotaIsNotSupported_MultipleAndroidUser) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(0));
// Multiple Android users.
EXPECT_CALL(homedirs_, GetUnmountedAndroidDataCount()).WillOnce(Return(2));
arc_disk_quota_.Initialize();
EXPECT_EQ(false, arc_disk_quota_.IsQuotaSupported());
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForUid_Succeeds) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(0));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(
base::FilePath(kDev),
kValidAndroidUid + kArcContainerShiftUid))
.WillOnce(Return(5));
arc_disk_quota_.Initialize();
EXPECT_EQ(5, arc_disk_quota_.GetCurrentSpaceForUid(kValidAndroidUid));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForUid_UidTooSmall) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(0));
arc_disk_quota_.Initialize();
EXPECT_EQ(-1, arc_disk_quota_.GetCurrentSpaceForUid(kAndroidUidStart - 1));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForUid_UidTooLarge) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(0));
arc_disk_quota_.Initialize();
EXPECT_EQ(-1, arc_disk_quota_.GetCurrentSpaceForUid(kAndroidUidEnd + 1));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForUid_NoDevice) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(""), Return(false)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(_, _)).Times(0);
arc_disk_quota_.Initialize();
EXPECT_EQ(-1, arc_disk_quota_.GetCurrentSpaceForUid(kValidAndroidUid));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForUid_NoQuotaMountedDevice) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(-1));
EXPECT_CALL(platform_,
GetQuotaCurrentSpaceForUid(Ne(base::FilePath(kDev)), Ne(0)))
.Times(0);
arc_disk_quota_.Initialize();
EXPECT_EQ(-1, arc_disk_quota_.GetCurrentSpaceForUid(kValidAndroidUid));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForUid_QuotactlFails) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(0));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(
base::FilePath(kDev),
kValidAndroidUid + kArcContainerShiftUid))
.WillOnce(Return(-1));
arc_disk_quota_.Initialize();
EXPECT_EQ(-1, arc_disk_quota_.GetCurrentSpaceForUid(kValidAndroidUid));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForGid_Succeeds) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(0));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForGid(
base::FilePath(kDev),
kValidAndroidGid + kArcContainerShiftGid))
.WillOnce(Return(5));
arc_disk_quota_.Initialize();
EXPECT_EQ(5, arc_disk_quota_.GetCurrentSpaceForGid(kValidAndroidGid));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForGid_GidTooSmall) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(0));
arc_disk_quota_.Initialize();
EXPECT_EQ(-1, arc_disk_quota_.GetCurrentSpaceForGid(kAndroidGidStart - 1));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForGid_GidTooLarge) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(0));
arc_disk_quota_.Initialize();
EXPECT_EQ(-1, arc_disk_quota_.GetCurrentSpaceForGid(kAndroidGidEnd + 1));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForGid_NoDevice) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(""), Return(false)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForGid(_, _)).Times(0);
arc_disk_quota_.Initialize();
EXPECT_EQ(-1, arc_disk_quota_.GetCurrentSpaceForGid(kValidAndroidGid));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForGid_NoQuotaMountedDevice) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(-1));
EXPECT_CALL(platform_,
GetQuotaCurrentSpaceForUid(Ne(base::FilePath(kDev)), Ne(0)))
.Times(0);
arc_disk_quota_.Initialize();
EXPECT_EQ(-1, arc_disk_quota_.GetCurrentSpaceForGid(kValidAndroidGid));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForGid_QuotactlFails) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(0));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForGid(
base::FilePath(kDev),
kValidAndroidGid + kArcContainerShiftGid))
.WillOnce(Return(-1));
arc_disk_quota_.Initialize();
EXPECT_EQ(-1, arc_disk_quota_.GetCurrentSpaceForGid(kValidAndroidGid));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForProjectId_Succeeds) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(0));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForProjectId(
base::FilePath(kDev), kValidAndroidProjectId))
.WillOnce(Return(5));
arc_disk_quota_.Initialize();
EXPECT_EQ(
5, arc_disk_quota_.GetCurrentSpaceForProjectId(kValidAndroidProjectId));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForProjectId_IdTooSmall) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(0));
arc_disk_quota_.Initialize();
EXPECT_EQ(-1, arc_disk_quota_.GetCurrentSpaceForProjectId(
kProjectIdForAndroidFilesStart - 1));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForProjectId_IdTooLarge) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(0));
arc_disk_quota_.Initialize();
EXPECT_EQ(-1, arc_disk_quota_.GetCurrentSpaceForProjectId(
kProjectIdForAndroidFilesEnd + 1));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForProjectId_NoDevice) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(""), Return(false)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForProjectId(_, _)).Times(0);
arc_disk_quota_.Initialize();
EXPECT_EQ(
-1, arc_disk_quota_.GetCurrentSpaceForProjectId(kValidAndroidProjectId));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForProjectId_NoQuotaMountedDevice) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(-1));
EXPECT_CALL(platform_,
GetQuotaCurrentSpaceForUid(Ne(base::FilePath(kDev)), Ne(0)))
.Times(0);
arc_disk_quota_.Initialize();
EXPECT_EQ(
-1, arc_disk_quota_.GetCurrentSpaceForProjectId(kValidAndroidProjectId));
}
TEST_F(ArcDiskQuotaTest, GetCurrentSpaceForProjectId_QuotactlFails) {
EXPECT_CALL(platform_, FindFilesystemDevice(base::FilePath(kArcDiskHome), _))
.WillOnce(DoAll(SetArgPointee<1>(kDev), Return(true)));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForUid(base::FilePath(kDev), 0))
.WillOnce(Return(0));
EXPECT_CALL(platform_, GetQuotaCurrentSpaceForProjectId(
base::FilePath(kDev), kValidAndroidProjectId))
.WillOnce(Return(-1));
arc_disk_quota_.Initialize();
EXPECT_EQ(
-1, arc_disk_quota_.GetCurrentSpaceForProjectId(kValidAndroidProjectId));
}
TEST_F(ArcDiskQuotaTest, SetProjectId_Succeeds) {
constexpr int kProjectId = kValidAndroidProjectId;
const auto kParentPath = SetProjectIdAllowedPathType::PATH_DOWNLOADS;
const auto kChildPath = base::FilePath("test.png");
const base::FilePath kExpectedPath =
base::FilePath("/home/user/cafef00d/Downloads/test.png");
EXPECT_CALL(homedirs_, CryptohomeExists(kObfuscatedUsername))
.WillOnce(Return(true));
EXPECT_CALL(platform_, SetQuotaProjectId(kProjectId, kExpectedPath))
.WillOnce(Return(true));
EXPECT_TRUE(arc_disk_quota_.SetProjectId(kProjectId, kParentPath, kChildPath,
kObfuscatedUsername));
}
TEST_F(ArcDiskQuotaTest, SetProjectId_IdOutOfAllowedRange) {
constexpr int kProjectId = kProjectIdForAndroidFilesEnd + 1;
const auto kParentPath = SetProjectIdAllowedPathType::PATH_DOWNLOADS;
const auto kChildPath = base::FilePath("test.png");
EXPECT_CALL(homedirs_, CryptohomeExists(_)).Times(0);
EXPECT_CALL(platform_, SetQuotaProjectId(kProjectId, _)).Times(0);
EXPECT_FALSE(arc_disk_quota_.SetProjectId(kProjectId, kParentPath, kChildPath,
kObfuscatedUsername));
}
TEST_F(ArcDiskQuotaTest, SetProjectId_InvalidPath) {
constexpr int kProjectId = kValidAndroidProjectId;
const auto kParentPath = SetProjectIdAllowedPathType::PATH_DOWNLOADS;
// Child path contains ".."
const auto kChildPath = base::FilePath("/../test.png");
EXPECT_CALL(homedirs_, CryptohomeExists(_)).Times(0);
EXPECT_CALL(platform_, SetQuotaProjectId(kProjectId, _)).Times(0);
EXPECT_FALSE(arc_disk_quota_.SetProjectId(kProjectId, kParentPath, kChildPath,
kObfuscatedUsername));
}
TEST_F(ArcDiskQuotaTest, SetProjectId_InvalidParentPathType) {
constexpr int kProjectId = kValidAndroidProjectId;
const auto kInvalidParentPath = static_cast<SetProjectIdAllowedPathType>(3);
const auto kChildPath = base::FilePath("test.png");
EXPECT_CALL(homedirs_, CryptohomeExists(kObfuscatedUsername))
.WillOnce(Return(true));
EXPECT_CALL(platform_, SetQuotaProjectId(kProjectId, _)).Times(0);
EXPECT_FALSE(arc_disk_quota_.SetProjectId(kProjectId, kInvalidParentPath,
kChildPath, kObfuscatedUsername));
}
TEST_F(ArcDiskQuotaTest, SetProjectId_CryptohomeNotExist) {
constexpr int kProjectId = kValidAndroidProjectId;
const auto kParentPath = SetProjectIdAllowedPathType::PATH_DOWNLOADS;
const auto kChildPath = base::FilePath("test.png");
const auto kInvalidObfuscatedUsername = "deadbeef";
EXPECT_CALL(homedirs_, CryptohomeExists(kInvalidObfuscatedUsername))
.WillOnce(Return(false));
EXPECT_CALL(platform_, SetQuotaProjectId(kProjectId, _)).Times(0);
EXPECT_FALSE(arc_disk_quota_.SetProjectId(kProjectId, kParentPath, kChildPath,
kInvalidObfuscatedUsername));
}
TEST_F(ArcDiskQuotaTest, SetProjectId_IoctlFails) {
constexpr int kProjectId = kValidAndroidProjectId;
const auto kParentPath = SetProjectIdAllowedPathType::PATH_DOWNLOADS;
const auto kChildPath = base::FilePath("test.png");
EXPECT_CALL(homedirs_, CryptohomeExists(kObfuscatedUsername))
.WillOnce(Return(true));
EXPECT_CALL(platform_, SetQuotaProjectId(kProjectId, _))
.WillOnce(Return(false));
EXPECT_FALSE(arc_disk_quota_.SetProjectId(kProjectId, kParentPath, kChildPath,
kObfuscatedUsername));
}
} // namespace cryptohome