SharedWorker: PBackground Sender Principal Completely Unverified (RecvPSharedWorkerConstructor)
Categories
(Core :: DOM: Service Workers, defect)
Tracking
()
People
(Reporter: t.satoki111, Assigned: nika)
References
(Blocks 1 open bug)
Details
(4 keywords, Whiteboard: [client-bounty-form])
Attachments
(1 file, 1 obsolete file)
|
5.34 KB,
application/x-javascript
|
Details |
Summary
RecvPSharedWorkerConstructor (BackgroundParentImpl.cpp) forwards child-supplied RemoteWorkerData with zero validation. The function body is cast + Initialize() + IPC_OK() — nothing else.
RemoteWorkerData contains principalInfo, loadingPrincipalInfo, resolvedScriptURL, etc. None are verified against the sending process's actual principal.
Downstream, RemoteWorkerManager::LaunchInternal uses the forged principal to call TransmitPermissionsAndCookiesAndBlobURLsForPrincipalInfo, injecting the victim origin's permissions, cookies, and BlobURL registrations into the target content process in one shot.
This is the only PBackground constructor with zero sender verification.
Attack Chain
Compromised content process (evil.com)
│
▼ [1] PBackground IPC
SendPSharedWorkerConstructor(RemoteWorkerData{
principalInfo: victim.example.com, // forged
loadingPrincipalInfo: victim.example.com, // forged
resolvedScriptURL: victim's worker script, // forged
})
│
▼ [2] BackgroundParentImpl.cpp RecvPSharedWorkerConstructor()
actor->Initialize(aData, aWindowID, aPortIdentifier);
return IPC_OK();
// Validation: ZERO. Cast + Initialize + return only.
│
▼ [3] SharedWorkerService.cpp GetOrCreateWorkerManagerOnMainThread()
principal = PrincipalInfoToPrincipal(aData.principalInfo());
// Pure deserialization. No sender binding.
// remoteType is recomputed, but principal itself is used as-is.
│
▼ [4] RemoteWorkerManager.cpp LaunchInternal()
TransmitPermissionsAndCookiesAndBlobURLsForPrincipalInfo(
contentParent, aData.principalInfo() // forged principal
);
// → TransmitPermissionsForPrincipal(victim)
// → TransmitBlobURLsForPrincipal(victim)
// → CookieServiceParent::UpdateCookieInContentList(victim)
│
▼ Victim's permissions, cookies, BlobURLs injected into attacker process
Vulnerable Code
1. RecvPSharedWorkerConstructor — Zero Checks
ipc/glue/BackgroundParentImpl.cpp:
IPCResult BackgroundParentImpl::RecvPSharedWorkerConstructor(
PSharedWorkerParent* aActor, const mozilla::dom::RemoteWorkerData& aData,
const uint64_t& aWindowID,
const mozilla::dom::MessagePortIdentifier& aPortIdentifier) {
mozilla::dom::SharedWorkerParent* actor =
static_cast<mozilla::dom::SharedWorkerParent*>(aActor);
actor->Initialize(aData, aWindowID, aPortIdentifier);
return IPC_OK();
}
2. LaunchInternal — Bulk Injection with Forged Principal
dom/workers/remoteworkers/RemoteWorkerManager.cpp:
void RemoteWorkerManager::LaunchInternal(..., const RemoteWorkerData& aData) {
if (aTargetActor != mParentActor) {
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(__func__,
[contentHandle = ..., principalInfo = aData.principalInfo()] {
if (RefPtr<ContentParent> cp = contentHandle->GetContentParent()) {
TransmitPermissionsAndCookiesAndBlobURLsForPrincipalInfo(
cp, principalInfo); // Forged principal used directly
}
});
SchedulerGroup::Dispatch(r.forget());
}
}
3. IPDL Protocol
dom/workers/sharedworkers/PSharedWorker.ipdl:
[ManualDealloc]
protocol PSharedWorker {
manager PBackground;
// No security annotations
};
Constructor arguments (RemoteWorkerData) defined in PBackground.ipdl. Child-to-parent direction.
Comparison with Other PBackground Constructors
| IPC Handler | Sender Check | Impact Scope |
|---|---|---|
| RecvPSharedWorkerConstructor | None (zero) | permission + cookie + BlobURL + worker launch |
| RecvPLockManagerConstructor | SystemPrincipal rejection only | lock namespace |
| RecvCreateNotificationParent | None | notification permission |
SharedWorker is the only zero-check constructor on PBackground.
Exploitation Scenarios
Scenario 1: Victim Credentials Theft
- Compromise a content process (JS engine exploit)
- Forge
RemoteWorkerDatawithvictim.example.comprincipal - Parent calls
TransmitPermissionsAndCookiesAndBlobURLsForPrincipalInfo, opening victim's cookie routing to the attacker process - Access victim's cookies from the attacker process
Scenario 2: Attach to Existing SharedWorker
- Victim origin has a running SharedWorker
- Attacker forges constructor with matching principal + script URL
SharedWorkerManager::MatchOnMainThreadmatches the existing manager- MessagePort communication established with victim's SharedWorker
Scenario 3: BlobURL Hijacking
- Victim origin has registered BlobURLs
- Create SharedWorker with forged principal
TransmitBlobURLsForPrincipalinjects victim's BlobURL registrations into attacker process- Access victim data via BlobURLs
Suggested Fix
// Add to RecvPSharedWorkerConstructor:
RefPtr<ContentParent> cp = BackgroundParent::GetContentParent(this);
if (cp) {
auto claimed = PrincipalInfoToPrincipal(aData.principalInfo());
if (claimed.isErr() || !cp->GetRemoteType().Equals(
GetRemoteType(claimed.unwrap(), WorkerKind::WorkerKindShared))) {
return IPC_FAIL(this, "SharedWorker principal mismatch");
}
}
Structural fix: derive RemoteWorkerData principals on the parent side from the sender's verified identity.
Updated•8 months ago
|
Updated•8 months ago
|
Updated•8 months ago
|
Updated•8 months ago
|
Comment 1•7 months ago
|
||
The severity field is not set for this bug.
:mccr8, could you have a look please?
For more information, please visit BugBot documentation.
Updated•7 months ago
|
Updated•6 months ago
|
Updated•6 months ago
|
Comment 10•4 months ago
|
||
This is sketchy and fixing this would probably fix bug 2049149, too. Can you look at this? Thanks.
Comment 12•4 months ago
|
||
As far as I know this was fixed by bug 2039990: https://phabricator.services.mozilla.com/D302407
Comment 13•4 months ago
|
||
Actually, I guess we are only verifying loadingPrincipalInfo and not principalInfo. principalInfo is the one that actually ends up being used for RemoteWorkerManager::GetRemoteType. https://searchfox.org/firefox-main/rev/d5171e9e0f4729494423b0524f289073e0f0cb6c/dom/workers/sharedworkers/SharedWorkerService.cpp#190,213,237-239
Verification for partitionedPrincipal is also missing.
Comment 14•4 months ago
|
||
Comment 15•4 months ago
•
|
||
Simply adding BackgroundParent::ValidatePrincipalInfo for principalInfo (as a did in the patch above) causes crashes such as in the WPT mixed-content/gen/iframe-inherit.meta/opt-in/sharedworker-classic.https.html. In that case the principal's originNoSuffix is http://web-platform.test:8000 while aRemoteType is webIsolated=https://web-platform.test.
I would have assumed that shared workers aren't shared across https and http, so this feels a bit surprising to me.
Comment 16•4 months ago
|
||
Ah actually we already check the principal and loadingPrincipal, but only later and we fail gracefully: https://phabricator.services.mozilla.com/D302414
I think we could call this fixed?
Updated•4 months ago
|
| Assignee | ||
Comment 17•4 months ago
|
||
Yeah I think this should be fixed. That was at least partially the intention of that patch stack.
Updated•4 months ago
|
Updated•4 months ago
|
Updated•3 months ago
|
Updated•1 month ago
|
Description
•