[go: nahoru, domu]

blob: 5fa264d69b17b0a0498dae0d6b7afa0170267268 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <grp.h>
#include <pwd.h>
#include <sys/stat.h>
#include <string>
#include <vector>
#include "base/command_line.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/ash/login/test/session_manager_state_waiter.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/chromeos/crosier/ash_integration_test.h"
#include "chrome/test/base/chromeos/crosier/chromeos_integration_login_mixin.h"
namespace {
// Returns the Posix file permissions for a file at `path`. The file is assumed
// to exist.
int GetFilePermissions(const base::FilePath& path) {
int mode = 0;
CHECK(base::GetPosixFilePermissions(path, &mode));
return mode;
}
// Returns the owner of the file at `path`. The file is assumed to exist.
std::string GetFileOwner(const base::FilePath& path) {
struct stat info;
int rv = stat(path.MaybeAsASCII().c_str(), &info);
CHECK_EQ(rv, 0);
// Look up the owner in the passwd database.
struct passwd* file_owner = getpwuid(info.st_uid);
CHECK(file_owner);
return file_owner->pw_name;
}
// Returns the group of the file at `path`. The file is assumed to exist.
std::string GetFileGroup(const base::FilePath& path) {
struct stat info;
int rv = stat(path.MaybeAsASCII().c_str(), &info);
CHECK_EQ(rv, 0);
// Look up the file's group in the group database.
struct group* file_group = getgrgid(info.st_gid);
CHECK(file_group);
return file_group->gr_name;
}
class SecurityFilesIntegrationTest : public AshIntegrationTest {
public:
SecurityFilesIntegrationTest() {
// Keep test running after dismissing login screen.
set_exit_when_last_browser_closes(false);
login_mixin().SetMode(ChromeOSIntegrationLoginMixin::Mode::kTestLogin);
}
~SecurityFilesIntegrationTest() override = default;
// AshIntegrationTest:
void SetUpCommandLine(base::CommandLine* command_line) override {
AshIntegrationTest::SetUpCommandLine(command_line);
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kUserDataDir, "/home/chronos");
}
};
IN_PROC_BROWSER_TEST_F(SecurityFilesIntegrationTest, UserFilesLoggedIn) {
login_mixin().Login();
ash::test::WaitForPrimaryUserSessionStart();
EXPECT_TRUE(login_mixin().IsCryptohomeMounted());
base::ScopedAllowBlockingForTesting allow_blocking;
// Validate /home/chronos.
base::FilePath home_chronos("/home/chronos");
ASSERT_TRUE(base::PathExists(home_chronos));
EXPECT_EQ(GetFilePermissions(home_chronos), 0755);
EXPECT_EQ(GetFileOwner(home_chronos), "chronos");
// Validate /home/chronos/user.
base::FilePath home_chronos_user("/home/chronos/user");
ASSERT_TRUE(base::PathExists(home_chronos_user));
EXPECT_FALSE(GetFilePermissions(home_chronos_user) &
base::FILE_PERMISSION_WRITE_BY_OTHERS);
EXPECT_EQ(GetFileOwner(home_chronos_user), "chronos");
// There is at least one directory matching "u-*".
base::FileEnumerator enumerator(home_chronos, /*recursive=*/false,
base::FileEnumerator::DIRECTORIES, "u-*");
int count = 0;
enumerator.ForEach([&count](const base::FilePath& item) {
count++;
EXPECT_FALSE(GetFilePermissions(item) &
base::FILE_PERMISSION_WRITE_BY_OTHERS);
});
EXPECT_GT(count, 0);
// Validate contents of /home/chronos.
base::FileEnumerator enumerator2(
home_chronos, /*recursive=*/false,
base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES, "*");
enumerator2.ForEach([](const base::FilePath& item) {
// /home/chronos/crash is not other writable.
if (item == base::FilePath("/home/chronos/crash")) {
EXPECT_FALSE(GetFilePermissions(item) &
base::FILE_PERMISSION_WRITE_BY_OTHERS);
return;
}
// All other subdirectories and files are not group writable and not other
// writable.
constexpr int banned = base::FILE_PERMISSION_WRITE_BY_GROUP |
base::FILE_PERMISSION_WRITE_BY_OTHERS;
EXPECT_FALSE(GetFilePermissions(item) & banned) << item.MaybeAsASCII();
});
// Validate Downloads.
base::FilePath downloads("/home/chronos/user/MyFiles/Downloads");
ASSERT_TRUE(base::PathExists(downloads));
EXPECT_EQ(GetFilePermissions(downloads), 0750);
EXPECT_EQ(GetFileOwner(downloads), "chronos");
EXPECT_EQ(GetFileGroup(downloads), "chronos-access");
}
} // namespace