зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1403818 - Fix WebAuthn IPC crashes by keeping the child actor alive until process shutdown r=jcj
Summary: We currently call ChildActor.send__delete() when clearing an active transaction and thereby destroy the child actor. If that happens, e.g. due to a tab switch, while a message is in the IPC buffer waiting to be delivered, we crash. This patch creates the child actor lazily as before, but keeps it around until the WebAuthnManager goes away, which will be at process shutdown. Each transaction now has a unique id, that the parent process will include in any of the ConfirmRegister, ConfirmSign, or Abort messages. That way we can easily ignore stale messages that were in the buffer while we started a new transaction or cancelled the current one. Reviewers: jcj Reviewed By: jcj Bug #: 1403818 Differential Revision: https://phabricator.services.mozilla.com/D149
This commit is contained in:
Родитель
e166144d3b
Коммит
c29f1dbeb7
|
@ -104,12 +104,6 @@ U2FManager::ClearTransaction()
|
|||
}
|
||||
|
||||
mTransaction.reset();
|
||||
|
||||
if (mChild) {
|
||||
RefPtr<U2FTransactionChild> c;
|
||||
mChild.swap(c);
|
||||
c->Send__delete__(c);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -126,8 +120,8 @@ U2FManager::RejectTransaction(const nsresult& aError)
|
|||
void
|
||||
U2FManager::CancelTransaction(const nsresult& aError)
|
||||
{
|
||||
if (mChild) {
|
||||
mChild->SendRequestCancel();
|
||||
if (!NS_WARN_IF(!mChild || mTransaction.isNothing())) {
|
||||
mChild->SendRequestCancel(mTransaction.ref().mId);
|
||||
}
|
||||
|
||||
RejectTransaction(aError);
|
||||
|
@ -140,6 +134,12 @@ U2FManager::~U2FManager()
|
|||
if (mTransaction.isSome()) {
|
||||
RejectTransaction(NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
if (mChild) {
|
||||
RefPtr<U2FTransactionChild> c;
|
||||
mChild.swap(c);
|
||||
c->Send__delete__(c);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -281,11 +281,9 @@ U2FManager::Register(nsPIDOMWindowInner* aParent, const nsCString& aRpId,
|
|||
extensions);
|
||||
|
||||
MOZ_ASSERT(mTransaction.isNothing());
|
||||
|
||||
mTransaction = Some(U2FTransaction(aParent, Move(info), aClientDataJSON));
|
||||
|
||||
mChild->SendRequestRegister(mTransaction.ref().mInfo);
|
||||
|
||||
mChild->SendRequestRegister(mTransaction.ref().mId, mTransaction.ref().mInfo);
|
||||
return mTransaction.ref().mPromise.Ensure(__func__);
|
||||
}
|
||||
|
||||
|
@ -327,18 +325,18 @@ U2FManager::Sign(nsPIDOMWindowInner* aParent,
|
|||
MOZ_ASSERT(mTransaction.isNothing());
|
||||
mTransaction = Some(U2FTransaction(aParent, Move(info), aClientDataJSON));
|
||||
|
||||
mChild->SendRequestSign(mTransaction.ref().mInfo);
|
||||
|
||||
mChild->SendRequestSign(mTransaction.ref().mId, mTransaction.ref().mInfo);
|
||||
return mTransaction.ref().mPromise.Ensure(__func__);
|
||||
}
|
||||
|
||||
void
|
||||
U2FManager::FinishRegister(nsTArray<uint8_t>& aRegBuffer)
|
||||
U2FManager::FinishRegister(const uint64_t& aTransactionId,
|
||||
nsTArray<uint8_t>& aRegBuffer)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Check for a valid transaction.
|
||||
if (mTransaction.isNothing()) {
|
||||
if (mTransaction.isNothing() || mTransaction.ref().mId != aTransactionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -383,13 +381,14 @@ U2FManager::FinishRegister(nsTArray<uint8_t>& aRegBuffer)
|
|||
}
|
||||
|
||||
void
|
||||
U2FManager::FinishSign(nsTArray<uint8_t>& aCredentialId,
|
||||
U2FManager::FinishSign(const uint64_t& aTransactionId,
|
||||
nsTArray<uint8_t>& aCredentialId,
|
||||
nsTArray<uint8_t>& aSigBuffer)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Check for a valid transaction.
|
||||
if (mTransaction.isNothing()) {
|
||||
if (mTransaction.isNothing() || mTransaction.ref().mId != aTransactionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -442,11 +441,12 @@ U2FManager::FinishSign(nsTArray<uint8_t>& aCredentialId,
|
|||
}
|
||||
|
||||
void
|
||||
U2FManager::RequestAborted(const nsresult& aError)
|
||||
U2FManager::RequestAborted(const uint64_t& aTransactionId,
|
||||
const nsresult& aError)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mTransaction.isSome()) {
|
||||
if (mTransaction.isSome() && mTransaction.ref().mId == aTransactionId) {
|
||||
RejectTransaction(aError);
|
||||
}
|
||||
}
|
||||
|
@ -456,7 +456,6 @@ U2FManager::HandleEvent(nsIDOMEvent* aEvent)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aEvent);
|
||||
MOZ_ASSERT(mChild);
|
||||
|
||||
nsAutoString type;
|
||||
aEvent->GetType(type);
|
||||
|
@ -466,9 +465,11 @@ U2FManager::HandleEvent(nsIDOMEvent* aEvent)
|
|||
|
||||
nsCOMPtr<nsIDocument> doc =
|
||||
do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
|
||||
MOZ_ASSERT(doc);
|
||||
if (NS_WARN_IF(!doc)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (doc && doc->Hidden()) {
|
||||
if (doc->Hidden()) {
|
||||
MOZ_LOG(gU2FManagerLog, LogLevel::Debug,
|
||||
("Visibility change: U2F window is hidden, cancelling job."));
|
||||
|
||||
|
@ -481,6 +482,7 @@ U2FManager::HandleEvent(nsIDOMEvent* aEvent)
|
|||
void
|
||||
U2FManager::ActorDestroyed()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mChild = nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,10 @@ public:
|
|||
: mParent(aParent)
|
||||
, mInfo(aInfo)
|
||||
, mClientData(aClientData)
|
||||
{ }
|
||||
, mId(NextId())
|
||||
{
|
||||
MOZ_ASSERT(mId > 0);
|
||||
}
|
||||
|
||||
// Parent of the context we're running the transaction in.
|
||||
nsCOMPtr<nsPIDOMWindowInner> mParent;
|
||||
|
@ -75,6 +78,18 @@ public:
|
|||
|
||||
// Client data used to assemble reply objects.
|
||||
nsCString mClientData;
|
||||
|
||||
// Unique transaction id.
|
||||
uint64_t mId;
|
||||
|
||||
private:
|
||||
// Generates a unique id for new transactions. This doesn't have to be unique
|
||||
// forever, it's sufficient to differentiate between temporally close
|
||||
// transactions, where messages can intersect. Can overflow.
|
||||
static uint64_t NextId() {
|
||||
static uint64_t id = 0;
|
||||
return ++id;
|
||||
}
|
||||
};
|
||||
|
||||
class U2FManager final : public nsIDOMEventListener
|
||||
|
@ -97,10 +112,12 @@ public:
|
|||
const uint32_t& aTimeoutMillis,
|
||||
const nsTArray<WebAuthnScopedCredentialDescriptor>& aKeyList);
|
||||
|
||||
void FinishRegister(nsTArray<uint8_t>& aRegBuffer);
|
||||
void FinishSign(nsTArray<uint8_t>& aCredentialId,
|
||||
void FinishRegister(const uint64_t& aTransactionId,
|
||||
nsTArray<uint8_t>& aRegBuffer);
|
||||
void FinishSign(const uint64_t& aTransactionId,
|
||||
nsTArray<uint8_t>& aCredentialId,
|
||||
nsTArray<uint8_t>& aSigBuffer);
|
||||
void RequestAborted(const nsresult& aError);
|
||||
void RequestAborted(const uint64_t& aTransactionId, const nsresult& aError);
|
||||
|
||||
// XXX This is exposed only until we fix bug 1410346.
|
||||
void MaybeCancelTransaction(const nsresult& aError) {
|
||||
|
@ -129,11 +146,9 @@ private:
|
|||
// parent) and rejects it by calling RejectTransaction().
|
||||
void CancelTransaction(const nsresult& aError);
|
||||
|
||||
typedef MozPromise<nsresult, nsresult, false> BackgroundActorPromise;
|
||||
|
||||
bool MaybeCreateBackgroundActor();
|
||||
|
||||
// IPC Channel for the current transaction.
|
||||
// IPC Channel to the parent process.
|
||||
RefPtr<U2FTransactionChild> mChild;
|
||||
|
||||
// The current transaction, if any.
|
||||
|
|
|
@ -18,30 +18,33 @@ U2FTransactionChild::U2FTransactionChild()
|
|||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
U2FTransactionChild::RecvConfirmRegister(nsTArray<uint8_t>&& aRegBuffer)
|
||||
U2FTransactionChild::RecvConfirmRegister(const uint64_t& aTransactionId,
|
||||
nsTArray<uint8_t>&& aRegBuffer)
|
||||
{
|
||||
RefPtr<U2FManager> mgr = U2FManager::Get();
|
||||
MOZ_ASSERT(mgr);
|
||||
mgr->FinishRegister(aRegBuffer);
|
||||
mgr->FinishRegister(aTransactionId, aRegBuffer);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
U2FTransactionChild::RecvConfirmSign(nsTArray<uint8_t>&& aCredentialId,
|
||||
U2FTransactionChild::RecvConfirmSign(const uint64_t& aTransactionId,
|
||||
nsTArray<uint8_t>&& aCredentialId,
|
||||
nsTArray<uint8_t>&& aBuffer)
|
||||
{
|
||||
RefPtr<U2FManager> mgr = U2FManager::Get();
|
||||
MOZ_ASSERT(mgr);
|
||||
mgr->FinishSign(aCredentialId, aBuffer);
|
||||
mgr->FinishSign(aTransactionId, aCredentialId, aBuffer);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
U2FTransactionChild::RecvAbort(const nsresult& aError)
|
||||
U2FTransactionChild::RecvAbort(const uint64_t& aTransactionId,
|
||||
const nsresult& aError)
|
||||
{
|
||||
RefPtr<U2FManager> mgr = U2FManager::Get();
|
||||
MOZ_ASSERT(mgr);
|
||||
mgr->RequestAborted(aError);
|
||||
mgr->RequestAborted(aTransactionId, aError);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -23,11 +23,21 @@ class U2FTransactionChild final : public PWebAuthnTransactionChild
|
|||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(U2FTransactionChild);
|
||||
U2FTransactionChild();
|
||||
mozilla::ipc::IPCResult RecvConfirmRegister(nsTArray<uint8_t>&& aRegBuffer) override;
|
||||
mozilla::ipc::IPCResult RecvConfirmSign(nsTArray<uint8_t>&& aCredentialId,
|
||||
nsTArray<uint8_t>&& aBuffer) override;
|
||||
mozilla::ipc::IPCResult RecvAbort(const nsresult& aError) override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvConfirmRegister(const uint64_t& aTransactionId,
|
||||
nsTArray<uint8_t>&& aRegBuffer) override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvConfirmSign(const uint64_t& aTransactionId,
|
||||
nsTArray<uint8_t>&& aCredentialId,
|
||||
nsTArray<uint8_t>&& aBuffer) override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvAbort(const uint64_t& aTransactionId, const nsresult& aError) override;
|
||||
|
||||
void ActorDestroy(ActorDestroyReason why) override;
|
||||
|
||||
private:
|
||||
~U2FTransactionChild() = default;
|
||||
};
|
||||
|
|
|
@ -12,29 +12,31 @@ namespace mozilla {
|
|||
namespace dom {
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
U2FTransactionParent::RecvRequestRegister(const WebAuthnTransactionInfo& aTransactionInfo)
|
||||
U2FTransactionParent::RecvRequestRegister(const uint64_t& aTransactionId,
|
||||
const WebAuthnTransactionInfo& aTransactionInfo)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
U2FTokenManager* mgr = U2FTokenManager::Get();
|
||||
mgr->Register(this, aTransactionInfo);
|
||||
mgr->Register(this, aTransactionId, aTransactionInfo);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
U2FTransactionParent::RecvRequestSign(const WebAuthnTransactionInfo& aTransactionInfo)
|
||||
U2FTransactionParent::RecvRequestSign(const uint64_t& aTransactionId,
|
||||
const WebAuthnTransactionInfo& aTransactionInfo)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
U2FTokenManager* mgr = U2FTokenManager::Get();
|
||||
mgr->Sign(this, aTransactionInfo);
|
||||
mgr->Sign(this, aTransactionId, aTransactionInfo);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
U2FTransactionParent::RecvRequestCancel()
|
||||
U2FTransactionParent::RecvRequestCancel(const uint64_t& aTransactionId)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
U2FTokenManager* mgr = U2FTokenManager::Get();
|
||||
mgr->Cancel(this);
|
||||
mgr->Cancel(this, aTransactionId);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -23,12 +23,20 @@ class U2FTransactionParent final : public PWebAuthnTransactionParent
|
|||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(U2FTransactionParent);
|
||||
U2FTransactionParent() = default;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvRequestRegister(const WebAuthnTransactionInfo& aTransactionInfo) override;
|
||||
RecvRequestRegister(const uint64_t& aTransactionId,
|
||||
const WebAuthnTransactionInfo& aTransactionInfo) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvRequestSign(const WebAuthnTransactionInfo& aTransactionInfo) override;
|
||||
virtual mozilla::ipc::IPCResult RecvRequestCancel() override;
|
||||
RecvRequestSign(const uint64_t& aTransactionId,
|
||||
const WebAuthnTransactionInfo& aTransactionInfo) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvRequestCancel(const uint64_t& aTransactionId) override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
private:
|
||||
~U2FTransactionParent() = default;
|
||||
};
|
||||
|
|
|
@ -39,13 +39,13 @@ async protocol PWebAuthnTransaction {
|
|||
manager PBackground;
|
||||
parent:
|
||||
async __delete__();
|
||||
async RequestRegister(WebAuthnTransactionInfo aTransactionInfo);
|
||||
async RequestSign(WebAuthnTransactionInfo aTransactionInfo);
|
||||
async RequestCancel();
|
||||
async RequestRegister(uint64_t aTransactionId, WebAuthnTransactionInfo aTransactionInfo);
|
||||
async RequestSign(uint64_t aTransactionId, WebAuthnTransactionInfo aTransactionInfo);
|
||||
async RequestCancel(uint64_t aTransactionId);
|
||||
child:
|
||||
async ConfirmRegister(uint8_t[] RegBuffer);
|
||||
async ConfirmSign(uint8_t[] CredentialID, uint8_t[] ReplyBuffer);
|
||||
async Abort(nsresult Error);
|
||||
async ConfirmRegister(uint64_t aTransactionId, uint8_t[] RegBuffer);
|
||||
async ConfirmSign(uint64_t aTransactionId, uint8_t[] CredentialID, uint8_t[] ReplyBuffer);
|
||||
async Abort(uint64_t aTransactionId, nsresult Error);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ NS_IMPL_ISUPPORTS(U2FPrefManager, nsIObserver);
|
|||
|
||||
U2FTokenManager::U2FTokenManager()
|
||||
: mTransactionParent(nullptr)
|
||||
, mTransactionId(0)
|
||||
, mLastTransactionId(0)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
// Create on the main thread to make sure ClearOnShutdown() works.
|
||||
|
@ -158,9 +158,10 @@ U2FTokenManager::Get()
|
|||
}
|
||||
|
||||
void
|
||||
U2FTokenManager::AbortTransaction(const nsresult& aError)
|
||||
U2FTokenManager::AbortTransaction(const uint64_t& aTransactionId,
|
||||
const nsresult& aError)
|
||||
{
|
||||
Unused << mTransactionParent->SendAbort(aError);
|
||||
Unused << mTransactionParent->SendAbort(aTransactionId, aError);
|
||||
ClearTransaction();
|
||||
}
|
||||
|
||||
|
@ -183,8 +184,8 @@ U2FTokenManager::ClearTransaction()
|
|||
// Forget promises, if necessary.
|
||||
mRegisterPromise.DisconnectIfExists();
|
||||
mSignPromise.DisconnectIfExists();
|
||||
// Bump transaction id.
|
||||
mTransactionId++;
|
||||
// Clear transaction id.
|
||||
mLastTransactionId = 0;
|
||||
}
|
||||
|
||||
RefPtr<U2FTokenTransport>
|
||||
|
@ -218,6 +219,7 @@ U2FTokenManager::GetTokenManagerImpl()
|
|||
|
||||
void
|
||||
U2FTokenManager::Register(PWebAuthnTransactionParent* aTransactionParent,
|
||||
const uint64_t& aTransactionId,
|
||||
const WebAuthnTransactionInfo& aTransactionInfo)
|
||||
{
|
||||
MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthRegister"));
|
||||
|
@ -227,7 +229,7 @@ U2FTokenManager::Register(PWebAuthnTransactionParent* aTransactionParent,
|
|||
mTokenManagerImpl = GetTokenManagerImpl();
|
||||
|
||||
if (!mTokenManagerImpl) {
|
||||
AbortTransaction(NS_ERROR_DOM_NOT_ALLOWED_ERR);
|
||||
AbortTransaction(aTransactionId, NS_ERROR_DOM_NOT_ALLOWED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -237,11 +239,11 @@ U2FTokenManager::Register(PWebAuthnTransactionParent* aTransactionParent,
|
|||
|
||||
if ((aTransactionInfo.RpIdHash().Length() != SHA256_LENGTH) ||
|
||||
(aTransactionInfo.ClientDataHash().Length() != SHA256_LENGTH)) {
|
||||
AbortTransaction(NS_ERROR_DOM_UNKNOWN_ERR);
|
||||
AbortTransaction(aTransactionId, NS_ERROR_DOM_UNKNOWN_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t tid = mTransactionId;
|
||||
uint64_t tid = mLastTransactionId = aTransactionId;
|
||||
mozilla::TimeStamp startTime = mozilla::TimeStamp::Now();
|
||||
mTokenManagerImpl->Register(aTransactionInfo.Descriptors(),
|
||||
aTransactionInfo.RpIdHash(),
|
||||
|
@ -270,36 +272,31 @@ U2FTokenManager::Register(PWebAuthnTransactionParent* aTransactionParent,
|
|||
}
|
||||
|
||||
void
|
||||
U2FTokenManager::MaybeConfirmRegister(uint64_t aTransactionId,
|
||||
U2FTokenManager::MaybeConfirmRegister(const uint64_t& aTransactionId,
|
||||
U2FRegisterResult& aResult)
|
||||
{
|
||||
if (mTransactionId != aTransactionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mLastTransactionId == aTransactionId);
|
||||
mRegisterPromise.Complete();
|
||||
|
||||
nsTArray<uint8_t> registration;
|
||||
aResult.ConsumeRegistration(registration);
|
||||
|
||||
Unused << mTransactionParent->SendConfirmRegister(registration);
|
||||
Unused << mTransactionParent->SendConfirmRegister(aTransactionId, registration);
|
||||
ClearTransaction();
|
||||
}
|
||||
|
||||
void
|
||||
U2FTokenManager::MaybeAbortRegister(uint64_t aTransactionId,
|
||||
U2FTokenManager::MaybeAbortRegister(const uint64_t& aTransactionId,
|
||||
const nsresult& aError)
|
||||
{
|
||||
if (mTransactionId != aTransactionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mLastTransactionId == aTransactionId);
|
||||
mRegisterPromise.Complete();
|
||||
AbortTransaction(aError);
|
||||
AbortTransaction(aTransactionId, aError);
|
||||
}
|
||||
|
||||
void
|
||||
U2FTokenManager::Sign(PWebAuthnTransactionParent* aTransactionParent,
|
||||
const uint64_t& aTransactionId,
|
||||
const WebAuthnTransactionInfo& aTransactionInfo)
|
||||
{
|
||||
MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthSign"));
|
||||
|
@ -309,17 +306,17 @@ U2FTokenManager::Sign(PWebAuthnTransactionParent* aTransactionParent,
|
|||
mTokenManagerImpl = GetTokenManagerImpl();
|
||||
|
||||
if (!mTokenManagerImpl) {
|
||||
AbortTransaction(NS_ERROR_DOM_NOT_ALLOWED_ERR);
|
||||
AbortTransaction(aTransactionId, NS_ERROR_DOM_NOT_ALLOWED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((aTransactionInfo.RpIdHash().Length() != SHA256_LENGTH) ||
|
||||
(aTransactionInfo.ClientDataHash().Length() != SHA256_LENGTH)) {
|
||||
AbortTransaction(NS_ERROR_DOM_UNKNOWN_ERR);
|
||||
AbortTransaction(aTransactionId, NS_ERROR_DOM_UNKNOWN_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t tid = mTransactionId;
|
||||
uint64_t tid = mLastTransactionId = aTransactionId;
|
||||
mozilla::TimeStamp startTime = mozilla::TimeStamp::Now();
|
||||
mTokenManagerImpl->Sign(aTransactionInfo.Descriptors(),
|
||||
aTransactionInfo.RpIdHash(),
|
||||
|
@ -348,13 +345,10 @@ U2FTokenManager::Sign(PWebAuthnTransactionParent* aTransactionParent,
|
|||
}
|
||||
|
||||
void
|
||||
U2FTokenManager::MaybeConfirmSign(uint64_t aTransactionId,
|
||||
U2FTokenManager::MaybeConfirmSign(const uint64_t& aTransactionId,
|
||||
U2FSignResult& aResult)
|
||||
{
|
||||
if (mTransactionId != aTransactionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mLastTransactionId == aTransactionId);
|
||||
mSignPromise.Complete();
|
||||
|
||||
nsTArray<uint8_t> keyHandle;
|
||||
|
@ -362,25 +356,24 @@ U2FTokenManager::MaybeConfirmSign(uint64_t aTransactionId,
|
|||
nsTArray<uint8_t> signature;
|
||||
aResult.ConsumeSignature(signature);
|
||||
|
||||
Unused << mTransactionParent->SendConfirmSign(keyHandle, signature);
|
||||
Unused << mTransactionParent->SendConfirmSign(aTransactionId, keyHandle, signature);
|
||||
ClearTransaction();
|
||||
}
|
||||
|
||||
void
|
||||
U2FTokenManager::MaybeAbortSign(uint64_t aTransactionId, const nsresult& aError)
|
||||
U2FTokenManager::MaybeAbortSign(const uint64_t& aTransactionId,
|
||||
const nsresult& aError)
|
||||
{
|
||||
if (mTransactionId != aTransactionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mLastTransactionId == aTransactionId);
|
||||
mSignPromise.Complete();
|
||||
AbortTransaction(aError);
|
||||
AbortTransaction(aTransactionId, aError);
|
||||
}
|
||||
|
||||
void
|
||||
U2FTokenManager::Cancel(PWebAuthnTransactionParent* aParent)
|
||||
U2FTokenManager::Cancel(PWebAuthnTransactionParent* aParent,
|
||||
const uint64_t& aTransactionId)
|
||||
{
|
||||
if (mTransactionParent != aParent) {
|
||||
if (mTransactionParent != aParent || mLastTransactionId != aTransactionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,23 +31,25 @@ public:
|
|||
NS_INLINE_DECL_REFCOUNTING(U2FTokenManager)
|
||||
static U2FTokenManager* Get();
|
||||
void Register(PWebAuthnTransactionParent* aTransactionParent,
|
||||
const uint64_t& aTransactionId,
|
||||
const WebAuthnTransactionInfo& aTransactionInfo);
|
||||
void Sign(PWebAuthnTransactionParent* aTransactionParent,
|
||||
const uint64_t& aTransactionId,
|
||||
const WebAuthnTransactionInfo& aTransactionInfo);
|
||||
void Cancel(PWebAuthnTransactionParent* aTransactionParent);
|
||||
void Cancel(PWebAuthnTransactionParent* aTransactionParent,
|
||||
const uint64_t& aTransactionId);
|
||||
void MaybeClearTransaction(PWebAuthnTransactionParent* aParent);
|
||||
static void Initialize();
|
||||
private:
|
||||
U2FTokenManager();
|
||||
~U2FTokenManager();
|
||||
RefPtr<U2FTokenTransport> GetTokenManagerImpl();
|
||||
void AbortTransaction(const nsresult& aError);
|
||||
void AbortTransaction(const uint64_t& aTransactionId, const nsresult& aError);
|
||||
void ClearTransaction();
|
||||
void MaybeConfirmRegister(uint64_t aTransactionId,
|
||||
U2FRegisterResult& aResult);
|
||||
void MaybeAbortRegister(uint64_t aTransactionId, const nsresult& aError);
|
||||
void MaybeConfirmSign(uint64_t aTransactionId, U2FSignResult& aResult);
|
||||
void MaybeAbortSign(uint64_t aTransactionId, const nsresult& aError);
|
||||
void MaybeConfirmRegister(const uint64_t& aTransactionId, U2FRegisterResult& aResult);
|
||||
void MaybeAbortRegister(const uint64_t& aTransactionId, const nsresult& aError);
|
||||
void MaybeConfirmSign(const uint64_t& aTransactionId, U2FSignResult& aResult);
|
||||
void MaybeAbortSign(const uint64_t& aTransactionId, const nsresult& aError);
|
||||
// Using a raw pointer here, as the lifetime of the IPC object is managed by
|
||||
// the PBackground protocol code. This means we cannot be left holding an
|
||||
// invalid IPC protocol object after the transaction is finished.
|
||||
|
@ -55,10 +57,10 @@ private:
|
|||
RefPtr<U2FTokenTransport> mTokenManagerImpl;
|
||||
MozPromiseRequestHolder<U2FRegisterPromise> mRegisterPromise;
|
||||
MozPromiseRequestHolder<U2FSignPromise> mSignPromise;
|
||||
// Guards the asynchronous promise resolution of token manager impls.
|
||||
// We don't need to protect this with a lock as it will only be modified
|
||||
// and checked on the PBackground thread in the parent process.
|
||||
uint64_t mTransactionId;
|
||||
// The last transaction id, non-zero if there's an active transaction. This
|
||||
// guards any cancel messages to ensure we don't cancel newer transactions
|
||||
// due to a stale message.
|
||||
uint64_t mLastTransactionId;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -199,12 +199,6 @@ WebAuthnManager::ClearTransaction()
|
|||
}
|
||||
|
||||
mTransaction.reset();
|
||||
|
||||
if (mChild) {
|
||||
RefPtr<WebAuthnTransactionChild> c;
|
||||
mChild.swap(c);
|
||||
c->Send__delete__(c);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -220,8 +214,8 @@ WebAuthnManager::RejectTransaction(const nsresult& aError)
|
|||
void
|
||||
WebAuthnManager::CancelTransaction(const nsresult& aError)
|
||||
{
|
||||
if (mChild) {
|
||||
mChild->SendRequestCancel();
|
||||
if (!NS_WARN_IF(!mChild || mTransaction.isNothing())) {
|
||||
mChild->SendRequestCancel(mTransaction.ref().mId);
|
||||
}
|
||||
|
||||
RejectTransaction(aError);
|
||||
|
@ -234,6 +228,12 @@ WebAuthnManager::~WebAuthnManager()
|
|||
if (mTransaction.isSome()) {
|
||||
RejectTransaction(NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
if (mChild) {
|
||||
RefPtr<WebAuthnTransactionChild> c;
|
||||
mChild.swap(c);
|
||||
c->Send__delete__(c);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -460,7 +460,7 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent,
|
|||
}
|
||||
|
||||
if (!MaybeCreateBackgroundActor()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_NOT_ALLOWED_ERR);
|
||||
promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
@ -481,8 +481,7 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent,
|
|||
Move(info),
|
||||
Move(clientDataJSON)));
|
||||
|
||||
mChild->SendRequestRegister(mTransaction.ref().mInfo);
|
||||
|
||||
mChild->SendRequestRegister(mTransaction.ref().mId, mTransaction.ref().mInfo);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
@ -605,7 +604,7 @@ WebAuthnManager::GetAssertion(nsPIDOMWindowInner* aParent,
|
|||
}
|
||||
|
||||
if (!MaybeCreateBackgroundActor()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_NOT_ALLOWED_ERR);
|
||||
promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
@ -631,8 +630,7 @@ WebAuthnManager::GetAssertion(nsPIDOMWindowInner* aParent,
|
|||
Move(info),
|
||||
Move(clientDataJSON)));
|
||||
|
||||
mChild->SendRequestSign(mTransaction.ref().mInfo);
|
||||
|
||||
mChild->SendRequestSign(mTransaction.ref().mId, mTransaction.ref().mInfo);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
@ -660,12 +658,13 @@ WebAuthnManager::Store(nsPIDOMWindowInner* aParent,
|
|||
}
|
||||
|
||||
void
|
||||
WebAuthnManager::FinishMakeCredential(nsTArray<uint8_t>& aRegBuffer)
|
||||
WebAuthnManager::FinishMakeCredential(const uint64_t& aTransactionId,
|
||||
nsTArray<uint8_t>& aRegBuffer)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Check for a valid transaction.
|
||||
if (mTransaction.isNothing()) {
|
||||
if (mTransaction.isNothing() || mTransaction.ref().mId != aTransactionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -787,13 +786,14 @@ WebAuthnManager::FinishMakeCredential(nsTArray<uint8_t>& aRegBuffer)
|
|||
}
|
||||
|
||||
void
|
||||
WebAuthnManager::FinishGetAssertion(nsTArray<uint8_t>& aCredentialId,
|
||||
WebAuthnManager::FinishGetAssertion(const uint64_t& aTransactionId,
|
||||
nsTArray<uint8_t>& aCredentialId,
|
||||
nsTArray<uint8_t>& aSigBuffer)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Check for a valid transaction.
|
||||
if (mTransaction.isNothing()) {
|
||||
if (mTransaction.isNothing() || mTransaction.ref().mId != aTransactionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -872,11 +872,12 @@ WebAuthnManager::FinishGetAssertion(nsTArray<uint8_t>& aCredentialId,
|
|||
}
|
||||
|
||||
void
|
||||
WebAuthnManager::RequestAborted(const nsresult& aError)
|
||||
WebAuthnManager::RequestAborted(const uint64_t& aTransactionId,
|
||||
const nsresult& aError)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mTransaction.isSome()) {
|
||||
if (mTransaction.isSome() && mTransaction.ref().mId == aTransactionId) {
|
||||
RejectTransaction(aError);
|
||||
}
|
||||
}
|
||||
|
@ -895,9 +896,11 @@ WebAuthnManager::HandleEvent(nsIDOMEvent* aEvent)
|
|||
|
||||
nsCOMPtr<nsIDocument> doc =
|
||||
do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
|
||||
MOZ_ASSERT(doc);
|
||||
if (NS_WARN_IF(!doc)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (doc && doc->Hidden()) {
|
||||
if (doc->Hidden()) {
|
||||
MOZ_LOG(gWebAuthnManagerLog, LogLevel::Debug,
|
||||
("Visibility change: WebAuthn window is hidden, cancelling job."));
|
||||
|
||||
|
|
|
@ -71,7 +71,10 @@ public:
|
|||
, mPromise(aPromise)
|
||||
, mInfo(aInfo)
|
||||
, mClientData(aClientData)
|
||||
{ }
|
||||
, mId(NextId())
|
||||
{
|
||||
MOZ_ASSERT(mId > 0);
|
||||
}
|
||||
|
||||
// Parent of the context we're running the transaction in.
|
||||
nsCOMPtr<nsPIDOMWindowInner> mParent;
|
||||
|
@ -85,6 +88,18 @@ public:
|
|||
|
||||
// Client data used to assemble reply objects.
|
||||
nsCString mClientData;
|
||||
|
||||
// Unique transaction id.
|
||||
uint64_t mId;
|
||||
|
||||
private:
|
||||
// Generates a unique id for new transactions. This doesn't have to be unique
|
||||
// forever, it's sufficient to differentiate between temporally close
|
||||
// transactions, where messages can intersect. Can overflow.
|
||||
static uint64_t NextId() {
|
||||
static uint64_t id = 0;
|
||||
return ++id;
|
||||
}
|
||||
};
|
||||
|
||||
class WebAuthnManager final : public nsIDOMEventListener
|
||||
|
@ -108,14 +123,16 @@ public:
|
|||
Store(nsPIDOMWindowInner* aParent, const Credential& aCredential);
|
||||
|
||||
void
|
||||
FinishMakeCredential(nsTArray<uint8_t>& aRegBuffer);
|
||||
FinishMakeCredential(const uint64_t& aTransactionId,
|
||||
nsTArray<uint8_t>& aRegBuffer);
|
||||
|
||||
void
|
||||
FinishGetAssertion(nsTArray<uint8_t>& aCredentialId,
|
||||
FinishGetAssertion(const uint64_t& aTransactionId,
|
||||
nsTArray<uint8_t>& aCredentialId,
|
||||
nsTArray<uint8_t>& aSigBuffer);
|
||||
|
||||
void
|
||||
RequestAborted(const nsresult& aError);
|
||||
RequestAborted(const uint64_t& aTransactionId, const nsresult& aError);
|
||||
|
||||
void ActorDestroyed();
|
||||
|
||||
|
@ -131,11 +148,9 @@ private:
|
|||
// parent) and rejects it by calling RejectTransaction().
|
||||
void CancelTransaction(const nsresult& aError);
|
||||
|
||||
typedef MozPromise<nsresult, nsresult, false> BackgroundActorPromise;
|
||||
|
||||
bool MaybeCreateBackgroundActor();
|
||||
|
||||
// IPC Channel for the current transaction.
|
||||
// IPC Channel to the parent process.
|
||||
RefPtr<WebAuthnTransactionChild> mChild;
|
||||
|
||||
// The current transaction, if any.
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/WebAuthnTransactionChild.h"
|
||||
#include "mozilla/dom/WebAuthnManager.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -19,30 +18,33 @@ WebAuthnTransactionChild::WebAuthnTransactionChild()
|
|||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
WebAuthnTransactionChild::RecvConfirmRegister(nsTArray<uint8_t>&& aRegBuffer)
|
||||
WebAuthnTransactionChild::RecvConfirmRegister(const uint64_t& aTransactionId,
|
||||
nsTArray<uint8_t>&& aRegBuffer)
|
||||
{
|
||||
RefPtr<WebAuthnManager> mgr = WebAuthnManager::Get();
|
||||
MOZ_ASSERT(mgr);
|
||||
mgr->FinishMakeCredential(aRegBuffer);
|
||||
mgr->FinishMakeCredential(aTransactionId, aRegBuffer);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
WebAuthnTransactionChild::RecvConfirmSign(nsTArray<uint8_t>&& aCredentialId,
|
||||
WebAuthnTransactionChild::RecvConfirmSign(const uint64_t& aTransactionId,
|
||||
nsTArray<uint8_t>&& aCredentialId,
|
||||
nsTArray<uint8_t>&& aBuffer)
|
||||
{
|
||||
RefPtr<WebAuthnManager> mgr = WebAuthnManager::Get();
|
||||
MOZ_ASSERT(mgr);
|
||||
mgr->FinishGetAssertion(aCredentialId, aBuffer);
|
||||
mgr->FinishGetAssertion(aTransactionId, aCredentialId, aBuffer);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
WebAuthnTransactionChild::RecvAbort(const nsresult& aError)
|
||||
WebAuthnTransactionChild::RecvAbort(const uint64_t& aTransactionId,
|
||||
const nsresult& aError)
|
||||
{
|
||||
RefPtr<WebAuthnManager> mgr = WebAuthnManager::Get();
|
||||
MOZ_ASSERT(mgr);
|
||||
mgr->RequestAborted(aError);
|
||||
mgr->RequestAborted(aTransactionId, aError);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,11 +24,21 @@ class WebAuthnTransactionChild final : public PWebAuthnTransactionChild
|
|||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(WebAuthnTransactionChild);
|
||||
WebAuthnTransactionChild();
|
||||
mozilla::ipc::IPCResult RecvConfirmRegister(nsTArray<uint8_t>&& aRegBuffer) override;
|
||||
mozilla::ipc::IPCResult RecvConfirmSign(nsTArray<uint8_t>&& aCredentialId,
|
||||
nsTArray<uint8_t>&& aBuffer) override;
|
||||
mozilla::ipc::IPCResult RecvAbort(const nsresult& aError) override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvConfirmRegister(const uint64_t& aTransactionId,
|
||||
nsTArray<uint8_t>&& aRegBuffer) override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvConfirmSign(const uint64_t& aTransactionId,
|
||||
nsTArray<uint8_t>&& aCredentialId,
|
||||
nsTArray<uint8_t>&& aBuffer) override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvAbort(const uint64_t& aTransactionId, const nsresult& aError) override;
|
||||
|
||||
void ActorDestroy(ActorDestroyReason why) override;
|
||||
|
||||
private:
|
||||
~WebAuthnTransactionChild() = default;
|
||||
};
|
||||
|
|
|
@ -12,29 +12,31 @@ namespace mozilla {
|
|||
namespace dom {
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
WebAuthnTransactionParent::RecvRequestRegister(const WebAuthnTransactionInfo& aTransactionInfo)
|
||||
WebAuthnTransactionParent::RecvRequestRegister(const uint64_t& aTransactionId,
|
||||
const WebAuthnTransactionInfo& aTransactionInfo)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
U2FTokenManager* mgr = U2FTokenManager::Get();
|
||||
mgr->Register(this, aTransactionInfo);
|
||||
mgr->Register(this, aTransactionId, aTransactionInfo);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
WebAuthnTransactionParent::RecvRequestSign(const WebAuthnTransactionInfo& aTransactionInfo)
|
||||
WebAuthnTransactionParent::RecvRequestSign(const uint64_t& aTransactionId,
|
||||
const WebAuthnTransactionInfo& aTransactionInfo)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
U2FTokenManager* mgr = U2FTokenManager::Get();
|
||||
mgr->Sign(this, aTransactionInfo);
|
||||
mgr->Sign(this, aTransactionId, aTransactionInfo);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
WebAuthnTransactionParent::RecvRequestCancel()
|
||||
WebAuthnTransactionParent::RecvRequestCancel(const uint64_t& aTransactionId)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
U2FTokenManager* mgr = U2FTokenManager::Get();
|
||||
mgr->Cancel(this);
|
||||
mgr->Cancel(this, aTransactionId);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -23,12 +23,20 @@ class WebAuthnTransactionParent final : public PWebAuthnTransactionParent
|
|||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(WebAuthnTransactionParent);
|
||||
WebAuthnTransactionParent() = default;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvRequestRegister(const WebAuthnTransactionInfo& aTransactionInfo) override;
|
||||
RecvRequestRegister(const uint64_t& aTransactionId,
|
||||
const WebAuthnTransactionInfo& aTransactionInfo) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvRequestSign(const WebAuthnTransactionInfo& aTransactionInfo) override;
|
||||
virtual mozilla::ipc::IPCResult RecvRequestCancel() override;
|
||||
RecvRequestSign(const uint64_t& aTransactionId,
|
||||
const WebAuthnTransactionInfo& aTransactionInfo) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvRequestCancel(const uint64_t& aTransactionId) override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
private:
|
||||
~WebAuthnTransactionParent() = default;
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче