-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add enterprise policy for Bruschetta beta
This covers the MVP requirement to validate downloaded VM images while leaving a path to add more policy controls later. Since this is an unreleased policy, it will only be applied to stable and beta devices if enabled via the EnableExperimentalPolicies policy. Bug: b:231900967 Change-Id: I8b3270d4581caa806ca4b4fa3fb1916d08ac3aa1 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4022696 Reviewed-by: Dominic Battré <battre@chromium.org> Commit-Queue: Fergus Dall <sidereal@google.com> Reviewed-by: Alexander Hendrich <hendrich@chromium.org> Cr-Commit-Position: refs/heads/main@{#1073399}
- Loading branch information
1 parent
142546e
commit 54a6a43
Showing
13 changed files
with
1,143 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
263 changes: 263 additions & 0 deletions
263
chrome/browser/ash/bruschetta/bruschetta_policy_handler.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,263 @@ | ||
// Copyright 2022 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "chrome/browser/ash/bruschetta/bruschetta_policy_handler.h" | ||
|
||
#include "base/strings/string_number_conversions.h" | ||
#include "base/values.h" | ||
#include "build/build_config.h" | ||
#include "chrome/browser/ash/bruschetta/bruschetta_pref_names.h" | ||
#include "components/policy/core/browser/policy_error_map.h" | ||
#include "components/policy/core/common/policy_map.h" | ||
#include "components/policy/core/common/schema.h" | ||
#include "components/policy/policy_constants.h" | ||
#include "components/prefs/pref_value_map.h" | ||
#include "components/strings/grit/components_strings.h" | ||
#include "crypto/sha2.h" | ||
#include "url/gurl.h" | ||
|
||
namespace bruschetta { | ||
|
||
namespace { | ||
|
||
#if defined(ARCH_CPU_X86_64) | ||
const char kPolicyImageKeyArchSpecific[] = "installer_image_x86_64"; | ||
const char kPolicyPflashKeyArchSpecific[] = "uefi_pflash_x86_64"; | ||
const char kPolicyUefiKeyArchSpecific[] = "uefi_image_x86_64"; | ||
|
||
constexpr policy::PolicyMap::MessageType kUninstallableErrorLevel = | ||
policy::PolicyMap::MessageType::kError; | ||
#else | ||
const char kPolicyImageKeyArchSpecific[] = ""; | ||
const char kPolicyPflashKeyArchSpecific[] = ""; | ||
const char kPolicyUefiKeyArchSpecific[] = ""; | ||
|
||
constexpr policy::PolicyMap::MessageType kUninstallableErrorLevel = | ||
policy::PolicyMap::MessageType::kInfo; | ||
#endif | ||
|
||
prefs::PolicyEnabledState EnabledStrToEnum(const std::string& str) { | ||
if (str == "RUN_ALLOWED") { | ||
return prefs::PolicyEnabledState::RUN_ALLOWED; | ||
} | ||
if (str == "INSTALL_ALLOWED") { | ||
return prefs::PolicyEnabledState::INSTALL_ALLOWED; | ||
} | ||
|
||
return prefs::PolicyEnabledState::BLOCKED; | ||
} | ||
|
||
prefs::PolicyUpdateAction UpdateActionStrToEnum(const std::string& str) { | ||
if (str == "NONE") { | ||
return prefs::PolicyUpdateAction::NONE; | ||
} | ||
if (str == "FORCE_SHUTDOWN_ALWAYS") { | ||
return prefs::PolicyUpdateAction::FORCE_SHUTDOWN_ALWAYS; | ||
} | ||
|
||
return prefs::PolicyUpdateAction::FORCE_SHUTDOWN_IF_MORE_RESTRICTED; | ||
} | ||
|
||
} // namespace | ||
|
||
BruschettaPolicyHandler::BruschettaPolicyHandler(policy::Schema schema) | ||
: policy::SimpleSchemaValidatingPolicyHandler( | ||
policy::key::kBruschettaVMConfiguration, | ||
prefs::kBruschettaVMConfiguration, | ||
schema, | ||
policy::SchemaOnErrorStrategy::SCHEMA_ALLOW_UNKNOWN, | ||
policy::SimpleSchemaValidatingPolicyHandler::RECOMMENDED_PROHIBITED, | ||
policy::SimpleSchemaValidatingPolicyHandler::MANDATORY_ALLOWED) {} | ||
|
||
BruschettaPolicyHandler::~BruschettaPolicyHandler() = default; | ||
|
||
bool BruschettaPolicyHandler::CheckDownloadableObject( | ||
policy::PolicyErrorMap* errors, | ||
const std::string& id, | ||
const std::string& key, | ||
const base::Value::Dict& dict) { | ||
bool retval = true; | ||
|
||
const auto* url_str = dict.FindString(prefs::kPolicyURLKey); | ||
if (!GURL(*url_str).is_valid()) { | ||
errors->AddError(policy_name(), IDS_POLICY_INVALID_URL_ERROR, | ||
policy::PolicyErrorPath{id, key, prefs::kPolicyURLKey}); | ||
retval = false; | ||
} | ||
|
||
std::vector<uint8_t> hash_bytes; | ||
const auto* hash_str = dict.FindString(prefs::kPolicyHashKey); | ||
if (!base::HexStringToBytes(*hash_str, &hash_bytes) || | ||
hash_bytes.size() != crypto::kSHA256Length) { | ||
errors->AddError(policy_name(), IDS_POLICY_INVALID_HASH_ERROR, | ||
policy::PolicyErrorPath{id, key, prefs::kPolicyHashKey}); | ||
retval = false; | ||
} | ||
|
||
return retval; | ||
} | ||
|
||
bool BruschettaPolicyHandler::CheckPolicySettings( | ||
const policy::PolicyMap& policies, | ||
policy::PolicyErrorMap* errors) { | ||
// Delegate to our super-class, which checks the JSON schema. | ||
if (!policy::SimpleSchemaValidatingPolicyHandler::CheckPolicySettings( | ||
policies, errors)) { | ||
return false; | ||
} | ||
|
||
// Aside from outright schema violations we never reject a policy, we only | ||
// downgrade configs from installable to runnable. This minimizes the damage | ||
// caused by misconfigurations. | ||
|
||
downgraded_by_error_.clear(); | ||
const base::Value* value = | ||
policies.GetValue(policy_name(), base::Value::Type::DICT); | ||
|
||
if (!value) { | ||
return true; | ||
} | ||
|
||
for (const auto outer_config : value->GetDict()) { | ||
const std::string& id = outer_config.first; | ||
const base::Value::Dict& config = outer_config.second.GetDict(); | ||
|
||
bool valid_config = true; | ||
|
||
const auto* installer_image = config.FindDict(kPolicyImageKeyArchSpecific); | ||
if (installer_image) { | ||
if (!CheckDownloadableObject(errors, id, kPolicyImageKeyArchSpecific, | ||
*installer_image)) { | ||
valid_config = false; | ||
} | ||
} | ||
|
||
const auto* uefi_image = config.FindDict(kPolicyUefiKeyArchSpecific); | ||
if (uefi_image) { | ||
if (!CheckDownloadableObject(errors, id, kPolicyUefiKeyArchSpecific, | ||
*uefi_image)) { | ||
valid_config = false; | ||
} | ||
} | ||
|
||
const auto* pflash = config.FindDict(kPolicyPflashKeyArchSpecific); | ||
if (pflash) { | ||
if (!CheckDownloadableObject(errors, id, kPolicyPflashKeyArchSpecific, | ||
*pflash)) { | ||
valid_config = false; | ||
} | ||
} | ||
|
||
if (EnabledStrToEnum(*config.FindString(prefs::kPolicyEnabledKey)) == | ||
prefs::PolicyEnabledState::INSTALL_ALLOWED) { | ||
if (!installer_image || !uefi_image) { | ||
// This is an error on x86_64, since that's currently our *only* | ||
// supported architecture so this definitely indicates a | ||
// misconfiguration, but we also leave an informational level message | ||
// for arm devices to be helpful. | ||
errors->AddError(policy_name(), | ||
IDS_POLICY_BRUSCHETTA_UNINSTALLABLE_ERROR, | ||
policy::PolicyErrorPath{id}, kUninstallableErrorLevel); | ||
} | ||
|
||
if (!installer_image || !uefi_image || !valid_config) { | ||
downgraded_by_error_.insert(id); | ||
} | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
void BruschettaPolicyHandler::ApplyPolicySettings( | ||
const policy::PolicyMap& policies, | ||
PrefValueMap* prefs) { | ||
const base::Value* value = | ||
policies.GetValue(policy_name(), base::Value::Type::DICT); | ||
if (!value) | ||
return; | ||
|
||
// We can mostly skip error checking here because by this point the policy has | ||
// already been checked against the schema. | ||
|
||
base::Value::Dict pref; | ||
|
||
for (const auto outer_config : value->GetDict()) { | ||
const std::string& id = outer_config.first; | ||
const base::Value::Dict& config = outer_config.second.GetDict(); | ||
|
||
base::Value::Dict pref_config; | ||
bool installable; | ||
|
||
{ | ||
pref_config.Set(prefs::kPolicyNameKey, | ||
*config.FindString(prefs::kPolicyNameKey)); | ||
} | ||
|
||
{ | ||
auto policy_enabled = | ||
EnabledStrToEnum(*config.FindString(prefs::kPolicyEnabledKey)); | ||
if (downgraded_by_error_.contains(id)) { | ||
policy_enabled = | ||
std::min(policy_enabled, prefs::PolicyEnabledState::RUN_ALLOWED); | ||
} | ||
pref_config.Set(prefs::kPolicyEnabledKey, | ||
static_cast<int>(policy_enabled)); | ||
installable = | ||
(policy_enabled == prefs::PolicyEnabledState::INSTALL_ALLOWED); | ||
} | ||
|
||
{ | ||
const auto* installer_image = | ||
config.FindDict(kPolicyImageKeyArchSpecific); | ||
if (installer_image && installable) { | ||
pref_config.Set(prefs::kPolicyImageKey, installer_image->Clone()); | ||
} | ||
} | ||
|
||
{ | ||
const auto* uefi_image = config.FindDict(kPolicyUefiKeyArchSpecific); | ||
if (uefi_image && installable) { | ||
pref_config.Set(prefs::kPolicyUefiKey, uefi_image->Clone()); | ||
} | ||
} | ||
|
||
{ | ||
const auto* pflash = config.FindDict(kPolicyPflashKeyArchSpecific); | ||
if (pflash && installable) { | ||
pref_config.Set(prefs::kPolicyPflashKey, pflash->Clone()); | ||
} | ||
} | ||
|
||
{ | ||
const auto* vtpm = config.FindDict(prefs::kPolicyVTPMKey); | ||
bool vtpm_enabled = false; | ||
prefs::PolicyUpdateAction vtpm_update_action = | ||
prefs::PolicyUpdateAction::FORCE_SHUTDOWN_IF_MORE_RESTRICTED; | ||
if (vtpm) { | ||
vtpm_enabled = *vtpm->FindBool(prefs::kPolicyVTPMEnabledKey); | ||
|
||
const auto* vtpm_update_action_str = | ||
vtpm->FindString(prefs::kPolicyVTPMUpdateActionKey); | ||
if (vtpm_update_action_str) { | ||
vtpm_update_action = UpdateActionStrToEnum(*vtpm_update_action_str); | ||
} | ||
} | ||
|
||
base::Value::Dict pref_vtpm; | ||
pref_vtpm.Set(prefs::kPolicyVTPMEnabledKey, vtpm_enabled); | ||
pref_vtpm.Set(prefs::kPolicyVTPMUpdateActionKey, | ||
static_cast<int>(vtpm_update_action)); | ||
|
||
pref_config.Set(prefs::kPolicyVTPMKey, std::move(pref_vtpm)); | ||
} | ||
|
||
pref.Set(id, std::move(pref_config)); | ||
} | ||
|
||
prefs->SetValue(prefs::kBruschettaVMConfiguration, | ||
base::Value(std::move(pref))); | ||
} | ||
|
||
} // namespace bruschetta |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// Copyright 2022 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef CHROME_BROWSER_ASH_BRUSCHETTA_BRUSCHETTA_POLICY_HANDLER_H_ | ||
#define CHROME_BROWSER_ASH_BRUSCHETTA_BRUSCHETTA_POLICY_HANDLER_H_ | ||
|
||
#include "components/policy/core/browser/configuration_policy_handler.h" | ||
|
||
namespace bruschetta { | ||
|
||
// BruschettaPolicyHandler is responsible for mapping the | ||
// BruschettaVMConfiguration enterprise policy into chrome preferences. Because | ||
// we do non-trivial mapping we have our own subclass. Right now we: | ||
// - Fill in optional policies values with their default (e.g. vtpm) | ||
// - Map the appropriate architecture specific downloads to the corresponding | ||
// generic keys ("installer_image_x86_64" to "installer_image" and so on) | ||
// - Replace string-enumerations with numeric values defined in | ||
// bruschetta_pref_names.h | ||
// - Reduce the enable level if necessary to match what we can actually offer | ||
// i.e. we don't mark a config as installable if we can't actually install it. | ||
// | ||
// For concrete examples, see //chrome/test/data/policy/policy_test_cases.json | ||
class BruschettaPolicyHandler | ||
: public policy::SimpleSchemaValidatingPolicyHandler { | ||
public: | ||
explicit BruschettaPolicyHandler(policy::Schema schema); | ||
~BruschettaPolicyHandler() override; | ||
|
||
// ConfigurationPolicyHandler: | ||
bool CheckPolicySettings(const policy::PolicyMap& policies, | ||
policy::PolicyErrorMap* errors) override; | ||
void ApplyPolicySettings(const policy::PolicyMap& policies, | ||
PrefValueMap* prefs) override; | ||
|
||
private: | ||
bool CheckDownloadableObject(policy::PolicyErrorMap* errors, | ||
const std::string& id, | ||
const std::string& key, | ||
const base::Value::Dict& dict); | ||
|
||
// The set of configurations that have been downgraded from installable to | ||
// runnable due to an error in their config. Filled by CheckPolicySettings and | ||
// used by ApplyPolicySettings. | ||
base::flat_set<std::string> downgraded_by_error_; | ||
}; | ||
|
||
} // namespace bruschetta | ||
|
||
#endif // CHROME_BROWSER_ASH_BRUSCHETTA_BRUSCHETTA_POLICY_HANDLER_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// Copyright 2022 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "chrome/browser/ash/bruschetta/bruschetta_pref_names.h" | ||
|
||
#include "components/prefs/pref_registry_simple.h" | ||
|
||
namespace bruschetta::prefs { | ||
|
||
const char kBruschettaVMConfiguration[] = "bruschetta.vm_configuration"; | ||
|
||
const char kPolicyNameKey[] = "name"; | ||
const char kPolicyEnabledKey[] = "enabled_state"; | ||
const char kPolicyImageKey[] = "installer_image"; | ||
const char kPolicyPflashKey[] = "uefi_pflash"; | ||
const char kPolicyUefiKey[] = "uefi_image"; | ||
const char kPolicyURLKey[] = "url"; | ||
const char kPolicyHashKey[] = "hash"; | ||
const char kPolicyVTPMKey[] = "vtpm"; | ||
const char kPolicyVTPMEnabledKey[] = "enabled"; | ||
const char kPolicyVTPMUpdateActionKey[] = "policy_update_action"; | ||
|
||
void RegisterProfilePrefs(PrefRegistrySimple* registry) { | ||
registry->RegisterDictionaryPref(kBruschettaVMConfiguration); | ||
} | ||
|
||
} // namespace bruschetta::prefs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Copyright 2022 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef CHROME_BROWSER_ASH_BRUSCHETTA_BRUSCHETTA_PREF_NAMES_H_ | ||
#define CHROME_BROWSER_ASH_BRUSCHETTA_BRUSCHETTA_PREF_NAMES_H_ | ||
|
||
class PrefRegistrySimple; | ||
|
||
namespace bruschetta::prefs { | ||
|
||
// Mapped pref for the enterprise policy BruschettaVMConfiguration. | ||
extern const char kBruschettaVMConfiguration[]; | ||
extern const char kPolicyNameKey[]; | ||
extern const char kPolicyEnabledKey[]; | ||
extern const char kPolicyImageKey[]; | ||
extern const char kPolicyPflashKey[]; | ||
extern const char kPolicyUefiKey[]; | ||
extern const char kPolicyURLKey[]; | ||
extern const char kPolicyHashKey[]; | ||
extern const char kPolicyVTPMKey[]; | ||
extern const char kPolicyVTPMEnabledKey[]; | ||
extern const char kPolicyVTPMUpdateActionKey[]; | ||
|
||
enum class PolicyEnabledState { | ||
BLOCKED = 0, | ||
RUN_ALLOWED = 1, | ||
INSTALL_ALLOWED = 2, | ||
}; | ||
|
||
enum class PolicyUpdateAction { | ||
NONE = 0, | ||
FORCE_SHUTDOWN_IF_MORE_RESTRICTED = 1, | ||
FORCE_SHUTDOWN_ALWAYS = 2, | ||
}; | ||
|
||
void RegisterProfilePrefs(PrefRegistrySimple* registry); | ||
|
||
} // namespace bruschetta::prefs | ||
|
||
#endif // CHROME_BROWSER_ASH_BRUSCHETTA_BRUSCHETTA_PREF_NAMES_H_ |
Oops, something went wrong.