Add exposure criteria to WebRTC stat members.

Recent WebRTC stats spec changes have added restrictions on what stats
are available to JavaScript. This is done to reduce that fingerprinting
surface of WebRTC getStats. For example, stats exposing hardware
capabilities have requirements that must be met by the browser. See [1]
for more details.

This CL adds the types and the enumerations. Stats with these
restrictions should not be added until Chromium has implemented
filtering based on the stat type.

[1] https://w3c.github.io/webrtc-stats/#limiting-exposure-of-hardware-capabilities

Bug: webrtc:14546
Change-Id: I6dae5d4921c7a2bc828a4fc8f7d68e0c59f3be82
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/279043
Commit-Queue: Evan Shrubsole <eshr@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38381}
This commit is contained in:
Evan Shrubsole
2022-10-12 15:11:14 +00:00
committed by WebRTC LUCI CQ
parent 036b3fdea2
commit 6c733eed8e
3 changed files with 167 additions and 6 deletions

View File

@ -215,6 +215,17 @@ enum class NonStandardGroupId {
kRtcStatsRelativePacketArrivalDelay,
};
// Certain stat members should only be exposed to the JavaScript API in
// certain circumstances as to avoid passive fingerprinting.
enum class StatExposureCriteria : uint8_t {
// The stat should always be exposed. This is the default.
kAlways,
// The stat exposes hardware capabilities and thus should has limited exposure
// to JavaScript. The requirements for exposure are written in the spec at
// https://w3c.github.io/webrtc-stats/#limiting-exposure-of-hardware-capabilities.
kHardwareCapability,
};
// Interface for `RTCStats` members, which have a name and a value of a type
// defined in a subclass. Only the types listed in `Type` are supported, these
// are implemented by `RTCStatsMember<T>`. The value of a member may be
@ -256,6 +267,12 @@ class RTCStatsMemberInterface {
// Non-standard stats members can have group IDs in order to be exposed in
// JavaScript through experiments. Standardized stats have no group IDs.
virtual std::vector<NonStandardGroupId> group_ids() const { return {}; }
// The conditions for exposing the statistic to JavaScript. Stats with
// criteria that is not kAlways has some restriction and should be filtered
// in accordance to the spec.
virtual StatExposureCriteria exposure_criteria() const {
return StatExposureCriteria::kAlways;
}
// Type and value comparator. The names are not compared. These operators are
// exposed for testing.
bool operator==(const RTCStatsMemberInterface& other) const {
@ -295,16 +312,21 @@ template <typename T>
class RTCStatsMember : public RTCStatsMemberInterface {
public:
explicit RTCStatsMember(const char* name)
: RTCStatsMemberInterface(name, /*is_defined=*/false), value_() {}
: RTCStatsMemberInterface(name,
/*is_defined=*/false),
value_() {}
RTCStatsMember(const char* name, const T& value)
: RTCStatsMemberInterface(name, /*is_defined=*/true), value_(value) {}
: RTCStatsMemberInterface(name,
/*is_defined=*/true),
value_(value) {}
RTCStatsMember(const char* name, T&& value)
: RTCStatsMemberInterface(name, /*is_defined=*/true),
: RTCStatsMemberInterface(name,
/*is_defined=*/true),
value_(std::move(value)) {}
explicit RTCStatsMember(const RTCStatsMember<T>& other)
RTCStatsMember(const RTCStatsMember<T>& other)
: RTCStatsMemberInterface(other.name_, other.is_defined_),
value_(other.value_) {}
explicit RTCStatsMember(RTCStatsMember<T>&& other)
RTCStatsMember(RTCStatsMember<T>&& other)
: RTCStatsMemberInterface(other.name_, other.is_defined_),
value_(std::move(other.value_)) {}
@ -358,7 +380,9 @@ class RTCStatsMember : public RTCStatsMemberInterface {
protected:
bool IsEqual(const RTCStatsMemberInterface& other) const override {
if (type() != other.type() || is_standardized() != other.is_standardized())
if (type() != other.type() ||
is_standardized() != other.is_standardized() ||
exposure_criteria() != other.exposure_criteria())
return false;
const RTCStatsMember<T>& other_t =
static_cast<const RTCStatsMember<T>&>(other);
@ -411,6 +435,81 @@ WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<std::string>);
WEBRTC_DECLARE_RTCSTATSMEMBER(rtc_stats_internal::MapStringUint64);
WEBRTC_DECLARE_RTCSTATSMEMBER(rtc_stats_internal::MapStringDouble);
// For stats with restricted exposure.
template <typename T, StatExposureCriteria E>
class RTCRestrictedStatsMember : public RTCStatsMember<T> {
public:
explicit RTCRestrictedStatsMember(const char* name)
: RTCStatsMember<T>(name) {}
RTCRestrictedStatsMember(const char* name, const T& value)
: RTCStatsMember<T>(name, value) {}
RTCRestrictedStatsMember(const char* name, T&& value)
: RTCStatsMember<T>(name, std::move(value)) {}
RTCRestrictedStatsMember(const RTCRestrictedStatsMember<T, E>& other)
: RTCStatsMember<T>(other) {}
RTCRestrictedStatsMember(RTCRestrictedStatsMember<T, E>&& other)
: RTCStatsMember<T>(std::move(other)) {}
StatExposureCriteria exposure_criteria() const override { return E; }
T& operator=(const T& value) { return RTCStatsMember<T>::operator=(value); }
T& operator=(const T&& value) {
return RTCStatsMember<T>::operator=(std::move(value));
}
private:
static_assert(E != StatExposureCriteria::kAlways,
"kAlways is the default exposure criteria. Use "
"RTCStatMember<T> instead.");
};
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<bool, StatExposureCriteria::kHardwareCapability>;
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<int32_t,
StatExposureCriteria::kHardwareCapability>;
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<uint32_t,
StatExposureCriteria::kHardwareCapability>;
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<int64_t,
StatExposureCriteria::kHardwareCapability>;
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<uint64_t,
StatExposureCriteria::kHardwareCapability>;
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<double, StatExposureCriteria::kHardwareCapability>;
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::string,
StatExposureCriteria::kHardwareCapability>;
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::vector<bool>,
StatExposureCriteria::kHardwareCapability>;
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::vector<int32_t>,
StatExposureCriteria::kHardwareCapability>;
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::vector<uint32_t>,
StatExposureCriteria::kHardwareCapability>;
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::vector<int64_t>,
StatExposureCriteria::kHardwareCapability>;
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::vector<uint64_t>,
StatExposureCriteria::kHardwareCapability>;
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::vector<double>,
StatExposureCriteria::kHardwareCapability>;
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::vector<std::string>,
StatExposureCriteria::kHardwareCapability>;
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::map<std::string, uint64_t>,
StatExposureCriteria::kHardwareCapability>;
extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::map<std::string, double>,
StatExposureCriteria::kHardwareCapability>;
// Using inheritance just so that it's obvious from the member's declaration
// whether it's standardized or not.
template <typename T>

View File

@ -289,6 +289,54 @@ WEBRTC_DEFINE_RTCSTATSMEMBER(rtc_stats_internal::MapStringDouble,
MapToString(value_),
MapToStringAsDouble(value_));
// Restricted members that expose hardware capabilites.
template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<bool, StatExposureCriteria::kHardwareCapability>;
template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<int32_t,
StatExposureCriteria::kHardwareCapability>;
template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<uint32_t,
StatExposureCriteria::kHardwareCapability>;
template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<int64_t,
StatExposureCriteria::kHardwareCapability>;
template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<uint64_t,
StatExposureCriteria::kHardwareCapability>;
template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<double, StatExposureCriteria::kHardwareCapability>;
template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::string,
StatExposureCriteria::kHardwareCapability>;
template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::vector<bool>,
StatExposureCriteria::kHardwareCapability>;
template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::vector<int32_t>,
StatExposureCriteria::kHardwareCapability>;
template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::vector<uint32_t>,
StatExposureCriteria::kHardwareCapability>;
template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::vector<int64_t>,
StatExposureCriteria::kHardwareCapability>;
template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::vector<uint64_t>,
StatExposureCriteria::kHardwareCapability>;
template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::vector<double>,
StatExposureCriteria::kHardwareCapability>;
template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::vector<std::string>,
StatExposureCriteria::kHardwareCapability>;
template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::map<std::string, uint64_t>,
StatExposureCriteria::kHardwareCapability>;
template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
RTCRestrictedStatsMember<std::map<std::string, double>,
StatExposureCriteria::kHardwareCapability>;
template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT)
RTCNonStandardStatsMember<bool>;
template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT)

View File

@ -503,6 +503,20 @@ TEST(RTCStatsTest, ValueToString) {
EXPECT_EQ("{bar:0.25,foo:0.5}", stats.m_map_string_double.ValueToString());
}
TEST(RTCStatsTest, RestrictedStatsTest) {
RTCStatsMember<bool> unrestricted("unrestricted");
EXPECT_EQ(unrestricted.exposure_criteria(), StatExposureCriteria::kAlways);
RTCRestrictedStatsMember<bool, StatExposureCriteria::kHardwareCapability>
restricted("restricted");
EXPECT_EQ(restricted.exposure_criteria(),
StatExposureCriteria::kHardwareCapability);
unrestricted = true;
restricted = true;
EXPECT_NE(unrestricted, restricted)
<< "These can not be equal as they have different exposure criteria.";
}
TEST(RTCStatsTest, NonStandardGroupId) {
auto group_id = NonStandardGroupId::kGroupIdForTesting;
RTCNonStandardStatsMember<int32_t> with_group_id("stat", {group_id});