Skip to content

Commit

Permalink
Bug 1729640 - P4. Setting high-value permission for sites that are co…
Browse files Browse the repository at this point in the history
…nsidered is logged in. r=farre,sfoster,tgiles

Sites that match the following heuristic are considered high-value:
1. Sites that have a password stored in the password manager
2. Sites that we detect that users submit a form with a password

This patch adds LoginDetectionService to detect login attempts.
When LoginDetectionService finds a site that matches any of the above
heuristics, it adds the corresponding high-value permission to the
permission manager.

Differential Revision: https://phabricator.services.mozilla.com/D127105
  • Loading branch information
DimiDL committed Nov 5, 2021
1 parent 1170d5b commit 4744525
Show file tree
Hide file tree
Showing 8 changed files with 274 additions and 3 deletions.
10 changes: 10 additions & 0 deletions browser/components/BrowserGlue.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -2673,6 +2673,16 @@ BrowserGlue.prototype = {
},
},

// Login detection service is used in fission to identify high value sites.
{
task: () => {
let loginDetection = Cc[
"@mozilla.org/login-detection-service;1"
].createInstance(Ci.nsILoginDetectionService);
loginDetection.init();
},
},

// WebDriver components (Remote Agent and Marionette) need to be
// initialized as very last step.
{
Expand Down
137 changes: 137 additions & 0 deletions dom/ipc/LoginDetectionService.cpp
Original file line number Diff line number Diff line change
@@ -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/. */

#include "LoginDetectionService.h"

#include "nsILoginInfo.h"
#include "nsILoginManager.h"
#include "nsIObserver.h"
#include "nsIXULRuntime.h"
#include "nsServiceManagerUtils.h"
#include "nsXULAppAPI.h"

#include "mozilla/ClearOnShutdown.h"
#include "mozilla/StaticPrefs_fission.h"
#include "mozilla/dom/ProcessIsolation.h"

namespace mozilla::dom {

static StaticRefPtr<LoginDetectionService> gLoginDetectionService;

namespace {

void OnFissionPrefsChange(const char* aPrefName, void* aData) {
MOZ_ASSERT(gLoginDetectionService);

gLoginDetectionService->MaybeStartMonitoring();
}

} // namespace

NS_IMPL_ISUPPORTS(LoginDetectionService, nsILoginDetectionService,
nsILoginSearchCallback, nsIObserver, nsISupportsWeakReference)

// static
already_AddRefed<LoginDetectionService> LoginDetectionService::GetSingleton() {
if (gLoginDetectionService) {
return do_AddRef(gLoginDetectionService);
}

gLoginDetectionService = new LoginDetectionService();
ClearOnShutdown(&gLoginDetectionService);

return do_AddRef(gLoginDetectionService);
}

LoginDetectionService::~LoginDetectionService() { UnregisterObserver(); }

void LoginDetectionService::MaybeStartMonitoring() {
if (IsIsolateHighValueSiteEnabled()) {
// We want to isolate sites with a saved password, so fetch saved logins
// from the password manager, and then add the 'HighValue' permission.

// Note that we don't monitor whether a login is added or removed after
// logins are fetched. For adding logins, this will be covered by form
// submission detection heuristic. As for removing logins, it doesn't
// provide security benefit just to NOT isolate the removed site. The site
// will not be isolated when its permission expired.
FetchLogins();

if (!mObs) {
mObs = mozilla::services::GetObserverService();
mObs->AddObserver(this, "passwordmgr-form-submission-detected", false);
}
} else {
UnregisterObserver();
}
}

void LoginDetectionService::FetchLogins() {
nsresult rv;
nsCOMPtr<nsILoginManager> loginManager =
do_GetService(NS_LOGINMANAGER_CONTRACTID, &rv);
if (NS_WARN_IF(!loginManager)) {
return;
}

Unused << loginManager->GetAllLoginsWithCallbackAsync(this);
}

void LoginDetectionService::UnregisterObserver() {
if (mObs) {
mObs->RemoveObserver(this, "passwordmgr-form-submission-detected");
mObs = nullptr;
}
}

///////////////////////////////////////////////////////////////////////////////
// nsILoginDetectionService implementation
NS_IMETHODIMP LoginDetectionService::Init() {
if (XRE_IsContentProcess()) {
return NS_OK;
}

Preferences::RegisterCallback(OnFissionPrefsChange, "fission.autostart");
Preferences::RegisterCallback(OnFissionPrefsChange,
"fission.webContentIsolationStrategy");

MaybeStartMonitoring();

return NS_OK;
}

///////////////////////////////////////////////////////////////////////////////
// nsILoginSearchObserver implementation
NS_IMETHODIMP
LoginDetectionService::OnSearchComplete(
const nsTArray<RefPtr<nsILoginInfo>>& aLogins) {
// Add all origins with saved passwords to the permission manager.
for (const auto& login : aLogins) {
nsString origin;
login->GetOrigin(origin);

AddHighValuePermission(NS_ConvertUTF16toUTF8(origin),
mozilla::dom::kHighValueHasSavedLoginPermission);
}

return NS_OK;
}

///////////////////////////////////////////////////////////////////////////////
// nsIObserver implementation
NS_IMETHODIMP
LoginDetectionService::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) {
if ("passwordmgr-form-submission-detected"_ns.Equals(aTopic)) {
nsDependentString origin(aData);
AddHighValuePermission(NS_ConvertUTF16toUTF8(origin),
mozilla::dom::kHighValueIsLoggedInPermission);
}

return NS_OK;
}

} // namespace mozilla::dom
57 changes: 57 additions & 0 deletions dom/ipc/LoginDetectionService.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* -*- 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_dom_LoginDetectionService_h
#define mozilla_dom_LoginDetectionService_h

#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsILoginDetectionService.h"
#include "nsILoginManager.h"
#include "nsWeakReference.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"

namespace mozilla::dom {

/**
* Detect whether the user is 'possibly' logged in to a site, and add the
* HighValue permission to the permission manager. We say 'possibly' because
* the detection is done in a very loose way. For example, for sites that have
* an associated login stored in the password manager are considered `logged in`
* by the service, which is not always true in terms of whether the users is
* really logged in to the site.
*/
class LoginDetectionService final : public nsILoginDetectionService,
public nsILoginSearchCallback,
public nsIObserver,
public nsSupportsWeakReference {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSILOGINDETECTIONSERVICE
NS_DECL_NSILOGINSEARCHCALLBACK
NS_DECL_NSIOBSERVER

static already_AddRefed<LoginDetectionService> GetSingleton();

void MaybeStartMonitoring();

private:
LoginDetectionService() = default;
virtual ~LoginDetectionService();

// Fetch saved logins from the password manager.
void FetchLogins();

void RegisterObserver();
void UnregisterObserver();

nsCOMPtr<nsIObserverService> mObs;
};

} // namespace mozilla::dom

#endif
20 changes: 20 additions & 0 deletions dom/ipc/ProcessIsolation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -955,4 +955,24 @@ void AddHighValuePermission(nsIPrincipal* aResultPrincipal,
nsIPermissionManager::EXPIRE_TIME, expirationTime);
}

void AddHighValuePermission(const nsACString& aOrigin,
const nsACString& aPermissionType) {
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
nsCOMPtr<nsIPrincipal> principal;
nsresult rv =
ssm->CreateContentPrincipalFromOrigin(aOrigin, getter_AddRefs(principal));
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}

AddHighValuePermission(principal, aPermissionType);
}

bool IsIsolateHighValueSiteEnabled() {
return mozilla::FissionAutostart() &&
WebContentIsolationStrategy(
StaticPrefs::fission_webContentIsolationStrategy()) ==
WebContentIsolationStrategy::IsolateHighValue;
}

} // namespace mozilla::dom
14 changes: 11 additions & 3 deletions dom/ipc/ProcessIsolation.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@
#include "mozilla/dom/RemoteType.h"
#include "mozilla/dom/SessionHistoryEntry.h"
#include "nsString.h"

class nsIURI;
class nsIPrincipal;
#include "nsIPrincipal.h"
#include "nsIURI.h"

namespace mozilla::dom {

Expand Down Expand Up @@ -80,6 +79,15 @@ Result<NavigationIsolationOptions, nsresult> IsolationOptionsForNavigation(
void AddHighValuePermission(nsIPrincipal* aResultPrincipal,
const nsACString& aPermissionType);

void AddHighValuePermission(const nsACString& aOrigin,
const nsACString& aPermissionType);

/**
* Returns true when fission is enabled and the
* `fission.webContentIsolationStrategy` pref is set to `IsolateHighValue`.
*/
bool IsIsolateHighValueSiteEnabled();

} // namespace mozilla::dom

#endif
16 changes: 16 additions & 0 deletions dom/ipc/components.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# -*- 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/.

Classes = [
{
'cid': '{91fdaa4e-eba4-4ed3-831c-ce05c142822d}',
'contract_ids': ['@mozilla.org/login-detection-service;1'],
'type': 'mozilla::dom::LoginDetectionService',
'singleton': True,
'headers': ['/dom/ipc/LoginDetectionService.h'],
'constructor': 'mozilla::dom::LoginDetectionService::GetSingleton',
},
]
7 changes: 7 additions & 0 deletions dom/ipc/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@ XPIDL_SOURCES += [
"nsIDOMProcessChild.idl",
"nsIDOMProcessParent.idl",
"nsIHangReport.idl",
"nsILoginDetectionService.idl",
]

XPIDL_MODULE = "dom"

XPCOM_MANIFESTS += [
"components.conf",
]

EXTRA_JS_MODULES += [
"ManifestMessagesChild.jsm",
]
Expand Down Expand Up @@ -53,6 +58,7 @@ EXPORTS.mozilla.dom += [
"FilePickerParent.h",
"InProcessChild.h",
"InProcessParent.h",
"LoginDetectionService.h",
"MaybeDiscarded.h",
"MemoryReportRequest.h",
"NativeThreadId.h",
Expand Down Expand Up @@ -106,6 +112,7 @@ UNIFIED_SOURCES += [
"DocShellMessageUtils.cpp",
"FilePickerParent.cpp",
"InProcessImpl.cpp",
"LoginDetectionService.cpp",
"MemMapSnapshot.cpp",
"MemoryReportRequest.cpp",
"MMPrinter.cpp",
Expand Down
16 changes: 16 additions & 0 deletions dom/ipc/nsILoginDetectionService.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* 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 "nsISupports.idl"

interface nsIURI;

[scriptable, uuid(4c3c9a82-722a-4b0b-9c7d-36ef90135537)]
interface nsILoginDetectionService : nsISupports
{
/**
* called to initialize the login detection service.
*/
void init();
};

0 comments on commit 4744525

Please sign in to comment.