mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
Bug 1432429 - Add FuzzyFox class and prefs. r=baku,froydnj
Creates a FuzzyFox class for implementating the core of the step/sleep algorithm. Starts it in nsLayoutStatics::Initialize() Adds the fuzzyfox prefs. Moves the ms2mt macros from TimeStamp_windows.cpp to TimeStamp_windows.h and creates a new public function GetQueryPerformanceFrequencyPerSec() to expose a static variable in the .cpp file. This is necessary to support the macros being usable anywhere. (And we use the macros in FuzzyFox.)
This commit is contained in:
parent
b6d5d5bc06
commit
b83b9c5b11
@ -1197,6 +1197,8 @@ pref("services.sync.prefs.sync.privacy.clearOnShutdown.offlineApps", true);
|
||||
pref("services.sync.prefs.sync.privacy.clearOnShutdown.sessions", true);
|
||||
pref("services.sync.prefs.sync.privacy.clearOnShutdown.siteSettings", true);
|
||||
pref("services.sync.prefs.sync.privacy.donottrackheader.enabled", true);
|
||||
pref("services.sync.prefs.sync.privacy.fuzzyfox.enabled", true);
|
||||
pref("services.sync.prefs.sync.privacy.fuzzyfox.clockgrainus", true);
|
||||
pref("services.sync.prefs.sync.privacy.sanitize.sanitizeOnShutdown", true);
|
||||
pref("services.sync.prefs.sync.privacy.trackingprotection.enabled", true);
|
||||
pref("services.sync.prefs.sync.privacy.trackingprotection.pbmode.enabled", true);
|
||||
|
@ -102,6 +102,7 @@
|
||||
#include "DecoderDoctorLogger.h"
|
||||
#include "MediaDecoder.h"
|
||||
#include "mozilla/ClearSiteData.h"
|
||||
#include "mozilla/Fuzzyfox.h"
|
||||
#include "mozilla/ServoBindings.h"
|
||||
#include "mozilla/StaticPresData.h"
|
||||
#include "mozilla/dom/WebIDLGlobalNameHash.h"
|
||||
@ -284,6 +285,8 @@ nsLayoutStatics::Initialize()
|
||||
|
||||
nsThreadManager::InitializeShutdownObserver();
|
||||
|
||||
mozilla::Fuzzyfox::Start();
|
||||
|
||||
ClearSiteData::Initialize();
|
||||
|
||||
return NS_OK;
|
||||
|
@ -63,26 +63,20 @@ static const DWORD kDefaultTimeIncrement = 156001;
|
||||
// Global variables, not changing at runtime
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The [mt] unit:
|
||||
*
|
||||
* Many values are kept in ticks of the Performance Coutner x 1000,
|
||||
* further just referred as [mt], meaning milli-ticks.
|
||||
*
|
||||
* This is needed to preserve maximum precision of the performance frequency
|
||||
* representation. GetTickCount64 values in milliseconds are multiplied with
|
||||
* frequency per second. Therefor we need to multiply QPC value by 1000 to
|
||||
* have the same units to allow simple arithmentic with both QPC and GTC.
|
||||
*/
|
||||
|
||||
#define ms2mt(x) ((x) * sFrequencyPerSec)
|
||||
#define mt2ms(x) ((x) / sFrequencyPerSec)
|
||||
#define mt2ms_f(x) (double(x) / sFrequencyPerSec)
|
||||
|
||||
// Result of QueryPerformanceFrequency
|
||||
// We use default of 1 for the case we can't use QueryPerformanceCounter
|
||||
// to make mt/ms conversions work despite that.
|
||||
static LONGLONG sFrequencyPerSec = 1;
|
||||
static uint64_t sFrequencyPerSec = 1;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MFBT_API uint64_t
|
||||
GetQueryPerformanceFrequencyPerSec()
|
||||
{
|
||||
return sFrequencyPerSec;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// How much we are tolerant to GTC occasional loose of resoltion.
|
||||
// This number says how many multiples of the minimal GTC resolution
|
||||
|
@ -11,6 +11,24 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* The [mt] unit:
|
||||
*
|
||||
* Many values are kept in ticks of the Performance Counter x 1000,
|
||||
* further just referred as [mt], meaning milli-ticks.
|
||||
*
|
||||
* This is needed to preserve maximum precision of the performance frequency
|
||||
* representation. GetTickCount64 values in milliseconds are multiplied with
|
||||
* frequency per second. Therefore we need to multiply QPC value by 1000 to
|
||||
* have the same units to allow simple arithmentic with both QPC and GTC.
|
||||
*/
|
||||
#define ms2mt(x) ((x) * mozilla::GetQueryPerformanceFrequencyPerSec())
|
||||
#define mt2ms(x) ((x) / mozilla::GetQueryPerformanceFrequencyPerSec())
|
||||
#define mt2ms_f(x) (double(x) / mozilla::GetQueryPerformanceFrequencyPerSec())
|
||||
|
||||
MFBT_API uint64_t
|
||||
GetQueryPerformanceFrequencyPerSec();
|
||||
|
||||
class TimeStamp;
|
||||
|
||||
class TimeStampValue
|
||||
|
382
toolkit/components/fuzzyfox/Fuzzyfox.cpp
Normal file
382
toolkit/components/fuzzyfox/Fuzzyfox.cpp
Normal file
@ -0,0 +1,382 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "Fuzzyfox.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/SystemGroup.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "prrng.h"
|
||||
#include "prtime.h"
|
||||
|
||||
// For usleep/Sleep & QueryPerformanceFrequency
|
||||
#ifdef XP_WIN
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static LazyLogModule sFuzzyfoxLog("Fuzzyfox");
|
||||
|
||||
#define US_TO_NS(x) ((x)*1000)
|
||||
#define NS_TO_US(x) ((x)/1000)
|
||||
|
||||
#ifdef LOG
|
||||
#undef LOG
|
||||
#endif
|
||||
|
||||
#define LOG(level, args) MOZ_LOG(sFuzzyfoxLog, mozilla::LogLevel::level, args)
|
||||
|
||||
#define FUZZYFOX_ENABLED_PREF "privacy.fuzzyfox.enabled"
|
||||
#define FUZZYFOX_ENABLED_PREF_DEFAULT false
|
||||
#define FUZZYFOX_CLOCKGRAIN_PREF "privacy.fuzzyfox.clockgrainus"
|
||||
#define FUZZYFOX_CLOCKGRAIN_PREF_DEFAULT 100
|
||||
|
||||
Atomic<uint32_t, Relaxed> Fuzzyfox::sFuzzyfoxClockGrain;
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(Fuzzyfox, Runnable, nsIObserver)
|
||||
|
||||
/* static */ void
|
||||
Fuzzyfox::Start()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<Fuzzyfox> r = new Fuzzyfox();
|
||||
SystemGroup::Dispatch(TaskCategory::Other, r.forget());
|
||||
}
|
||||
|
||||
Fuzzyfox::Fuzzyfox()
|
||||
: Runnable("Fuzzyfox")
|
||||
, mSanityCheck(false)
|
||||
, mStartTime(0)
|
||||
, mDuration(PickDuration())
|
||||
, mTickType(eUptick)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// [[ I originally ran this after observing profile-after-change, but
|
||||
// it turned out that this contructor was getting called _after_ that
|
||||
// event had already fired. ]]
|
||||
Preferences::AddAtomicUintVarCache(&sFuzzyfoxClockGrain,
|
||||
FUZZYFOX_CLOCKGRAIN_PREF,
|
||||
FUZZYFOX_CLOCKGRAIN_PREF_DEFAULT);
|
||||
|
||||
bool fuzzyfoxEnabled =
|
||||
Preferences::GetBool(FUZZYFOX_ENABLED_PREF, FUZZYFOX_ENABLED_PREF_DEFAULT);
|
||||
|
||||
LOG(Info, ("PT(%p) Created Fuzzyfox, FuzzyFox is now %s \n",
|
||||
this, (fuzzyfoxEnabled ? "enabled" : "disabled")));
|
||||
|
||||
TimeStamp::SetFuzzyfoxEnabled(fuzzyfoxEnabled);
|
||||
|
||||
// Should I see if these fail? And do what?
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
prefs->AddObserver(FUZZYFOX_ENABLED_PREF, this, false);
|
||||
prefs->AddObserver(FUZZYFOX_CLOCKGRAIN_PREF, this, false);
|
||||
}
|
||||
|
||||
Fuzzyfox::~Fuzzyfox() = default;
|
||||
|
||||
/*
|
||||
* Fuzzyfox::Run is the core of FuzzyFox. Every so often we pop into this method, and pick
|
||||
* a new point in the future to hold time constant until. If we have not reached the _previous_
|
||||
* point in time we had picked, we sleep until we do so.
|
||||
* Then we round the current time downwards to a configurable grain value, fix it in place so
|
||||
* time does not advance, and let execution continue.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
Fuzzyfox::Observe(nsISupports* aObject, const char* aTopic,
|
||||
const char16_t* aMessage)
|
||||
{
|
||||
if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
|
||||
NS_ConvertUTF16toUTF8 pref(aMessage);
|
||||
|
||||
if (pref.EqualsLiteral(FUZZYFOX_ENABLED_PREF)) {
|
||||
bool fuzzyfoxEnabled =
|
||||
Preferences::GetBool(FUZZYFOX_ENABLED_PREF, FUZZYFOX_ENABLED_PREF_DEFAULT);
|
||||
|
||||
LOG(Info, ("PT(%p) Observed a pref change, FuzzyFox is now %s \n",
|
||||
this, (fuzzyfoxEnabled ? "enabled" : "disabled")));
|
||||
|
||||
|
||||
TimeStamp::SetFuzzyfoxEnabled(fuzzyfoxEnabled);
|
||||
|
||||
|
||||
if (TimeStamp::GetFuzzyfoxEnabled()) {
|
||||
// Queue a runnable
|
||||
nsCOMPtr<nsIRunnable> r = this;
|
||||
SystemGroup::Dispatch(TaskCategory::Other, r.forget());
|
||||
} else {
|
||||
mStartTime = 0;
|
||||
mTickType = eUptick;
|
||||
mSanityCheck = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#define DISPATCH_AND_RETURN() \
|
||||
nsCOMPtr<nsIRunnable> r = this; \
|
||||
SystemGroup::Dispatch(TaskCategory::Other, r.forget()); \
|
||||
return NS_OK
|
||||
|
||||
NS_IMETHODIMP
|
||||
Fuzzyfox::Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!TimeStamp::GetFuzzyfoxEnabled()) {
|
||||
LOG(Info, ("[FuzzyfoxEvent] PT(%p) Fuzzyfox is shut down, doing nothing \n", this));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mStartTime == 0) {
|
||||
// This is the first time we are running afer enabling FuzzyFox. We need
|
||||
// to prevent time from going backwards, so for the first run we round the time up
|
||||
// to the next grain.
|
||||
mStartTime = CeilToGrain(ActualTime());
|
||||
MOZ_ASSERT(mStartTime != 0);
|
||||
TimeStamp newTimeStamp = CeilToGrain(TimeStamp::NowUnfuzzed());
|
||||
Fuzzyfox::UpdateClocks(mStartTime, newTimeStamp);
|
||||
|
||||
mSanityCheck = true;
|
||||
LOG(Info, ("[FuzzyfoxEvent] PT(%p) Going to start Fuzzyfox, queuing up the job \n",
|
||||
this));
|
||||
|
||||
DISPATCH_AND_RETURN();
|
||||
}
|
||||
|
||||
// We need to check how long its been since we ran
|
||||
uint64_t endTime = ActualTime();
|
||||
|
||||
uint64_t remaining = 0;
|
||||
|
||||
// Pick the amount to sleep
|
||||
if (endTime < mStartTime) {
|
||||
// This can only happen if we just enabled FuzzyFox, rounded up, and then re-ran the
|
||||
// runnable before we advanced to the next grain.
|
||||
// If that happens, then repeat the current time.
|
||||
// We use mSanityCheck just to be sure (and will eventually remove it.)
|
||||
MOZ_ASSERT(mSanityCheck);
|
||||
LOG(Debug, ("[FuzzyfoxEvent] PT(%p) endTime < mStartTime mStartTime %" PRIu64 " endTime %" PRIu64 " \n",
|
||||
this, mStartTime, endTime));
|
||||
|
||||
mSanityCheck = true;
|
||||
DISPATCH_AND_RETURN();
|
||||
}
|
||||
|
||||
uint64_t actualRunDuration = endTime - mStartTime;
|
||||
if (actualRunDuration > mDuration) {
|
||||
// We ran over our budget!
|
||||
uint64_t over = actualRunDuration - mDuration;
|
||||
LOG(Verbose, ("[FuzzyfoxEvent] PT(%p) Overran budget of %" PRIu32 " by %" PRIu64 " \n",
|
||||
this, mDuration, over));
|
||||
|
||||
uint64_t nextDuration = PickDuration();
|
||||
while (over > nextDuration) {
|
||||
over -= nextDuration;
|
||||
nextDuration = PickDuration();
|
||||
mTickType = mTickType == eUptick ? eDowntick : eUptick;
|
||||
}
|
||||
|
||||
remaining = nextDuration - over;
|
||||
} else {
|
||||
// Didn't go over budget
|
||||
remaining = mDuration - actualRunDuration;
|
||||
LOG(Verbose, ("[FuzzyfoxEvent] PT(%p) Finishing budget of %" PRIu32 " with %" PRIu64 " \n",
|
||||
this, mDuration, remaining));
|
||||
}
|
||||
mSanityCheck = false;
|
||||
|
||||
// Sleep for now
|
||||
#ifdef XP_WIN
|
||||
Sleep(remaining);
|
||||
#else
|
||||
usleep(remaining);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Update clocks (and fire pending events etc)
|
||||
*
|
||||
* Note: Anytime we round the current time to the grain, and then round the 'real'
|
||||
* time to the grain, we are introducing the risk that we split the grain. That is,
|
||||
* the time advances enough after the first rounding that the second rounding causes
|
||||
* us to move to a different grain.
|
||||
*
|
||||
* In theory, such an occurance breaks the security of FuzzyFox, and if an
|
||||
* attacker can influence the event to occur reliably, and then measure against it
|
||||
* they can attack FuzzyFox. But such an attack is so difficult that it will
|
||||
* never be acheived until you read this comment in a future Academic Publication
|
||||
* that demonstrates it. And at that point the paper would surely never be accepted
|
||||
* into any _respectable_ journal unless the authors had also presented a solution
|
||||
* for the issue that was usable and incorporated into Firefox!
|
||||
*/
|
||||
uint64_t newTime = FloorToGrain(ActualTime());
|
||||
TimeStamp newTimeStamp = FloorToGrain(TimeStamp::NowUnfuzzed());
|
||||
UpdateClocks(newTime, newTimeStamp);
|
||||
|
||||
// Reset values
|
||||
mTickType = mTickType == eUptick ? eDowntick : eUptick;
|
||||
mStartTime = ActualTime();
|
||||
mDuration = PickDuration();
|
||||
|
||||
DISPATCH_AND_RETURN();
|
||||
}
|
||||
|
||||
/*
|
||||
* ActualTime returns the unfuzzed/unrounded time in microseconds since the epoch
|
||||
*/
|
||||
uint64_t
|
||||
Fuzzyfox::ActualTime()
|
||||
{
|
||||
return PR_Now();
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate a duration we will wait until we allow time to advance again
|
||||
*/
|
||||
uint64_t
|
||||
Fuzzyfox::PickDuration()
|
||||
{
|
||||
// TODO: Bug 1484298 - use a real RNG
|
||||
long int rval = rand();
|
||||
|
||||
// Avoid divide by zero errors and overflow errors
|
||||
uint32_t duration = sFuzzyfoxClockGrain <= 0 ? 1 : sFuzzyfoxClockGrain;
|
||||
duration = duration >= (UINT32_MAX / 2) ? (UINT32_MAX / 2) : duration;
|
||||
|
||||
// We want uniform distribution from 1->duration*2
|
||||
// so that the mean is duration
|
||||
return 1 + (rval % (duration * 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the TimeStamp's class value for the current (constant) time and dispatch
|
||||
* the new (constant) timestamp so observers can register to receive it to update
|
||||
* their own time code.
|
||||
*/
|
||||
void
|
||||
Fuzzyfox::UpdateClocks(uint64_t aNewTime, TimeStamp aNewTimeStamp)
|
||||
{
|
||||
// newTime is the new canonical time for this scope!
|
||||
#ifndef XP_WIN
|
||||
LOG(Verbose, ("[Time] New time is %" PRIu64 " (compare to %" PRIu64 ") and timestamp is %" PRIu64 " (compare to %" PRIu64 ")\n",
|
||||
aNewTime, ActualTime(), aNewTimeStamp.mValue.mTimeStamp, TimeStamp::NowUnfuzzed().mValue.mTimeStamp));
|
||||
#else
|
||||
LOG(Verbose, ("[Time] New time is %" PRIu64 " (compare to %" PRIu64 ") \n", aNewTime, ActualTime()));
|
||||
#endif
|
||||
|
||||
// Fire notifications
|
||||
if (MOZ_UNLIKELY(!mObs)) {
|
||||
mObs = services::GetObserverService();
|
||||
if (NS_WARN_IF(!mObs)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Event firings on occur on downticks and have no data
|
||||
if (mTickType == eDowntick) {
|
||||
mObs->NotifyObservers(nullptr, FUZZYFOX_FIREOUTBOUND_OBSERVER_TOPIC, nullptr);
|
||||
}
|
||||
|
||||
if (!mTimeUpdateWrapper) {
|
||||
mTimeUpdateWrapper = do_CreateInstance(NS_SUPPORTS_PRINT64_CONTRACTID);
|
||||
if (NS_WARN_IF(!mTimeUpdateWrapper)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mTimeUpdateWrapper->SetData(aNewTime);
|
||||
|
||||
// Clocks get the new official (frozen) time. This happens on all ticks
|
||||
mObs->NotifyObservers(mTimeUpdateWrapper, FUZZYFOX_UPDATECLOCK_OBSERVER_TOPIC, nullptr);
|
||||
|
||||
// Update the timestamp's canonicaltime
|
||||
TimeStamp::UpdateFuzzyTimeStamp(aNewTimeStamp);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Fuzzyfox::GetClockGrain()
|
||||
{
|
||||
return sFuzzyfoxClockGrain;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FloorToGrain accepts a timestamp in microsecond precision
|
||||
* and returns it in microseconds, rounded down to the nearest
|
||||
* ClockGrain value.
|
||||
*/
|
||||
uint64_t
|
||||
Fuzzyfox::FloorToGrain(uint64_t aValue)
|
||||
{
|
||||
return aValue - (aValue % GetClockGrain());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FloorToGrain accepts a timestamp and returns it, rounded down
|
||||
* to the nearest ClockGrain value.
|
||||
*/
|
||||
TimeStamp
|
||||
Fuzzyfox::FloorToGrain(TimeStamp aValue)
|
||||
{
|
||||
#ifdef XP_WIN
|
||||
// grain is in us
|
||||
uint64_t grain = GetClockGrain();
|
||||
// GTC and QPS are stored in |mt| and need to be converted to
|
||||
uint64_t GTC = mt2ms(aValue.mValue.mGTC) * 1000;
|
||||
uint64_t QPC = mt2ms(aValue.mValue.mQPC) * 1000;
|
||||
|
||||
return TimeStamp(TimeStampValue(
|
||||
ms2mt((GTC - (GTC % grain)) / 1000),
|
||||
ms2mt((QPC - (QPC % grain)) / 1000),
|
||||
aValue.mValue.mHasQPC, true));
|
||||
#else
|
||||
return TimeStamp(TimeStampValue(true, US_TO_NS(FloorToGrain(NS_TO_US(aValue.mValue.mTimeStamp)))));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* CeilToGrain accepts a timestamp in microsecond precision
|
||||
* and returns it in microseconds, rounded up to the nearest
|
||||
* ClockGrain value.
|
||||
*/
|
||||
uint64_t
|
||||
Fuzzyfox::CeilToGrain(uint64_t aValue)
|
||||
{
|
||||
return (aValue / GetClockGrain()) * GetClockGrain();
|
||||
}
|
||||
|
||||
/*
|
||||
* CeilToGrain accepts a timestamp and returns it, rounded up
|
||||
* to the nearest ClockGrain value.
|
||||
*/
|
||||
TimeStamp
|
||||
Fuzzyfox::CeilToGrain(TimeStamp aValue)
|
||||
{
|
||||
#ifdef XP_WIN
|
||||
// grain is in us
|
||||
uint64_t grain = GetClockGrain();
|
||||
// GTC and QPS are stored in |mt| and need to be converted
|
||||
uint64_t GTC = mt2ms(aValue.mValue.mGTC) * 1000;
|
||||
uint64_t QPC = mt2ms(aValue.mValue.mQPC) * 1000;
|
||||
|
||||
return TimeStamp(TimeStampValue(
|
||||
ms2mt(((GTC / grain) * grain) / 1000),
|
||||
ms2mt(((QPC / grain) * grain) / 1000),
|
||||
aValue.mValue.mHasQPC, true));
|
||||
#else
|
||||
return TimeStamp(TimeStampValue(true, US_TO_NS(CeilToGrain(NS_TO_US(aValue.mValue.mTimeStamp)))));
|
||||
#endif
|
||||
}
|
137
toolkit/components/fuzzyfox/Fuzzyfox.h
Normal file
137
toolkit/components/fuzzyfox/Fuzzyfox.h
Normal file
@ -0,0 +1,137 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_Fuzzyfox_h
|
||||
#define mozilla_Fuzzyfox_h
|
||||
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
|
||||
/*
|
||||
* This topic publishes the new canonical time according to Fuzzyfox,
|
||||
* in microseconds since the epoch. If code needs to know the current time,
|
||||
* it should listen for this topic and keep track of the 'current' time,
|
||||
* so as to respect Fuzzyfox and be in sync with the rest of the browser's
|
||||
* timekeeping.
|
||||
*/
|
||||
#define FUZZYFOX_UPDATECLOCK_OBSERVER_TOPIC "fuzzyfox-update-clocks"
|
||||
|
||||
/*
|
||||
* For Fuzzyfox's security guarentees to hold, the browser must not execute
|
||||
* actions while it should be paused. We currently only pause the main thread,
|
||||
* so actions that occur on other threads should be queued until the browser
|
||||
* unpaused (and moreso than unpauses: until it reaches a downtick.)
|
||||
* This topic indicates when any queued outbound events should be delivered.
|
||||
* TODO: Bug 1484300 and 1484299 would apply this to other communication channels
|
||||
*/
|
||||
#define FUZZYFOX_FIREOUTBOUND_OBSERVER_TOPIC "fuzzyfox-fire-outbound"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
||||
/*
|
||||
* Fuzzyfox is an implementation of the Fermata concept presented in
|
||||
* Trusted Browsers for Uncertain Times.
|
||||
*
|
||||
* Web Browsers expose explicit (performance.now()) and implicit
|
||||
* (WebVTT, Video Frames) timers that, when combined with algorithmic
|
||||
* improvements such as edge thresholding, produce extremely high
|
||||
* resolution clocks.
|
||||
*
|
||||
* High Resolution clocks can be used to time network accesses, browser
|
||||
* cache reads, web page rendering, access to the CPU cache, and other
|
||||
* operations - and the time these operations take to perform can yield
|
||||
* detailed information about user information we want to keep private.
|
||||
*
|
||||
* Fuzzyfox limits the information disclosure by limiting an attacker's
|
||||
* ability to create a high resolution clock. It does this by introducing
|
||||
* a concept called 'fuzzy time' that degrades all clocks (explicit and
|
||||
* implicit). This is done through a combination of holding time constant
|
||||
* during program execution and pausing program execution.
|
||||
*
|
||||
* @InProceedings{KS16,
|
||||
* author = {David Kohlbrenner and Hovav Shacham},
|
||||
* title = {Trusted Browsers for Uncertain Times},
|
||||
* booktitle = {Proceedings of USENIX Security 2016},
|
||||
* pages = {463-80},
|
||||
* year = 2016,
|
||||
* editor = {Thorsten Holz and Stefan Savage},
|
||||
* month = aug,
|
||||
* organization = {USENIX}
|
||||
* }
|
||||
* https://www.usenix.org/system/files/conference/usenixsecurity16/sec16_paper_kohlbrenner.pdf
|
||||
*
|
||||
* Fuzzyfox is an adaptation of
|
||||
* W.-M. Hu, “Reducing timing channels with fuzzy time,” in
|
||||
* Proceedings of IEEE Security and Privacy (“Oakland”)
|
||||
* 1991, T. F. Lunt and J. McLean, Eds. IEEE Computer
|
||||
* Society, May 1991, pp. 8–20.
|
||||
*/
|
||||
class Fuzzyfox final : public Runnable, public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
static void
|
||||
Start();
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override;
|
||||
|
||||
private:
|
||||
Fuzzyfox();
|
||||
~Fuzzyfox();
|
||||
|
||||
uint64_t
|
||||
ActualTime();
|
||||
|
||||
uint64_t
|
||||
PickDuration();
|
||||
|
||||
void
|
||||
UpdateClocks(uint64_t aNewTime, TimeStamp aNewTimeStamp);
|
||||
|
||||
uint64_t
|
||||
GetClockGrain();
|
||||
|
||||
uint64_t
|
||||
FloorToGrain(uint64_t aValue);
|
||||
|
||||
TimeStamp
|
||||
FloorToGrain(TimeStamp aValue);
|
||||
|
||||
uint64_t
|
||||
CeilToGrain(uint64_t aValue);
|
||||
|
||||
TimeStamp
|
||||
CeilToGrain(TimeStamp aValue);
|
||||
|
||||
bool mSanityCheck;
|
||||
uint64_t mStartTime;
|
||||
uint32_t mDuration;
|
||||
|
||||
enum Tick {
|
||||
eUptick,
|
||||
eDowntick,
|
||||
};
|
||||
|
||||
Tick mTickType;
|
||||
|
||||
nsCOMPtr<nsIObserverService> mObs = nullptr;
|
||||
nsCOMPtr<nsISupportsPRInt64> mTimeUpdateWrapper = nullptr;
|
||||
|
||||
static Atomic<bool, Relaxed> sFuzzyfoxEnabledPrefMapped;
|
||||
static Atomic<uint32_t, Relaxed> sFuzzyfoxClockGrain;
|
||||
};
|
||||
|
||||
} // mozilla namespace
|
||||
|
||||
#endif /* mozilla_Fuzzyfox_h */
|
15
toolkit/components/fuzzyfox/moz.build
Normal file
15
toolkit/components/fuzzyfox/moz.build
Normal file
@ -0,0 +1,15 @@
|
||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
SOURCES += [
|
||||
'Fuzzyfox.cpp',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'Fuzzyfox.h'
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
@ -36,6 +36,7 @@ DIRS += [
|
||||
'filewatcher',
|
||||
'finalizationwitness',
|
||||
'find',
|
||||
'fuzzyfox',
|
||||
'jsoncpp/src/lib_json',
|
||||
'lz4',
|
||||
'mediasniffer',
|
||||
|
Loading…
Reference in New Issue
Block a user