blob: b7def356861c4b982359d875a51b96885a2968b2 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/renderer_host/runtime_feature_state_controller_impl.h"
#include "content/browser/bad_message.h"
#include "content/browser/runtime_feature_state/runtime_feature_state_document_data.h"
#include "third_party/blink/public/common/origin_trials/origin_trials.h"
#include "third_party/blink/public/common/origin_trials/trial_token_result.h"
#include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
#include "third_party/blink/public/mojom/runtime_feature_state/runtime_feature_state.mojom.h"
#include "third_party/blink/public/mojom/runtime_feature_state/runtime_feature_state_controller.mojom.h"
namespace content {
RuntimeFeatureStateControllerImpl::RuntimeFeatureStateControllerImpl(
RenderFrameHost& host,
mojo::PendingReceiver<blink::mojom::RuntimeFeatureStateController> receiver)
: receiver_(this, std::move(receiver)), render_frame_host_(host) {}
RuntimeFeatureStateControllerImpl::~RuntimeFeatureStateControllerImpl() =
default;
void RuntimeFeatureStateControllerImpl::ApplyFeatureDiffForOriginTrial(
base::flat_map<::blink::mojom::RuntimeFeatureState,
::blink::mojom::FeatureValuePtr> modified_features) {
// Perform security checks by ensuring the following:
base::flat_map<::blink::mojom::RuntimeFeatureState, bool>
validated_features{};
for (const auto& feature_pair : modified_features) {
// Ensure the tokens we received are valid for this feature and origin.
// TODO(https://crbug.com/1410784): add support for third-party Origin
// Trials in the token validation process.
std::string feature_name;
blink::TrialTokenValidator validator;
bool are_tokens_valid = true;
for (const auto& token : feature_pair.second->tokens) {
blink::TrialTokenResult result = validator.ValidateTokenAndTrial(
token, render_frame_host_->GetLastCommittedOrigin(),
base::Time::Now());
if (result.Status() != blink::OriginTrialTokenStatus::kSuccess) {
are_tokens_valid = false;
} else {
// All tokens should contain the same feature name. Store that name for
// later validation checks.
if (feature_name.empty()) {
feature_name = result.ParsedToken()->feature_name();
} else {
DCHECK(feature_name == result.ParsedToken()->feature_name());
}
}
}
// We can add a feature to the RuntimeFeatureStateReadContext if:
// 1. All of the tokens for the given feature were validated.
// 2. The feature we received is an origin trial feature.
// 3. The feature we received is expected in the browser process.
if (are_tokens_valid) {
// TODO(https://crbug.com/1410784): Since 3p tokens are not currently
// supported, we cannot assume that invalid tokens are a sign of a
// compromised renderer.
if (blink::origin_trials::IsTrialValid(feature_name) &&
blink::origin_trials::IsTrialEnabledForBrowserProcessReadWriteAccess(
feature_name)) {
validated_features[feature_pair.first] =
feature_pair.second->is_enabled;
} else {
// The renderer is compromised so we terminate it.
bad_message::ReceivedBadMessage(
render_frame_host_->GetProcess(),
bad_message::RFSCI_BROWSER_VALIDATION_BAD_ORIGIN_TRIAL_TOKEN);
}
}
}
// Apply the diff changes to the mutable RuntimeFeatureStateReadContext.
RuntimeFeatureStateDocumentData* document_data =
RuntimeFeatureStateDocumentData::GetForCurrentDocument(
&*render_frame_host_);
document_data
->GetMutableRuntimeFeatureStateReadContext(
base::PassKey<RuntimeFeatureStateControllerImpl>())
.ApplyFeatureChange(validated_features);
}
} // namespace content