Commit 3d2d5b12 authored by Dana Keeler's avatar Dana Keeler Committed by Pier Angelo Vendrame
Browse files

Bug 2027310 - improve thread coordination in ShowProtectedAuthPrompt r=jschanck

parent 45870afc
Loading
Loading
Loading
Loading
+32 −8
Original line number Diff line number Diff line
@@ -491,6 +491,21 @@ mozilla::pkix::Result DoOCSPRequest(
  return Success;
}

// Helper struct to simplify thread coordination in `ShowProtectedAuthPrompt`.
struct BackgroundPromptStatus final {
  explicit BackgroundPromptStatus(PK11SlotInfo* slot)
      : mSlot(slot), mDone(false), mResult(SECFailure) {}

  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BackgroundPromptStatus)

  UniquePK11SlotInfo mSlot;
  Atomic<bool> mDone;
  SECStatus mResult;

 private:
  ~BackgroundPromptStatus() = default;
};

static char* ShowProtectedAuthPrompt(PK11SlotInfo* slot, nsIPrompt* prompt) {
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(slot);
@@ -501,12 +516,13 @@ static char* ShowProtectedAuthPrompt(PK11SlotInfo* slot, nsIPrompt* prompt) {

  // Dispatch a background task to (eventually) call C_Login. The call will
  // block until the protected authentication succeeds or fails.
  Atomic<bool> done;
  Atomic<SECStatus> result;
  nsresult rv =
      NS_DispatchBackgroundTask(NS_NewRunnableFunction(__func__, [&]() mutable {
        result = PK11_CheckUserPassword(slot, nullptr);
        done = true;
  RefPtr<BackgroundPromptStatus> backgroundPromptStatus(
      new BackgroundPromptStatus(PK11_ReferenceSlot(slot)));
  nsresult rv = NS_DispatchBackgroundTask(
      NS_NewRunnableFunction(__func__, [backgroundPromptStatus]() mutable {
        backgroundPromptStatus->mResult = PK11_CheckUserPassword(
            backgroundPromptStatus->mSlot.get(), nullptr);
        backgroundPromptStatus->mDone = true;
      }));
  if (NS_FAILED(rv)) {
    return nullptr;
@@ -529,15 +545,23 @@ static char* ShowProtectedAuthPrompt(PK11SlotInfo* slot, nsIPrompt* prompt) {
  if (NS_FAILED(errorResult.StealNSResult())) {
    return nullptr;
  }

  // The idea here is to dispatch the background task before showing the
  // (synchronous) alert, so that the browser is telling the user what to do
  // while waiting for the protected authentication (if the alert were shown
  // before dispatching the task, the user would have to dismiss it first).
  rv = prompt->Alert(nullptr, NS_ConvertUTF8toUTF16(promptString).get());
  if (NS_FAILED(rv)) {
    return nullptr;
  }

  // Spin the event loop until the background task has completed.
  MOZ_ALWAYS_TRUE(SpinEventLoopUntil(
      "ShowProtectedAuthPrompt"_ns, [&]() { return static_cast<bool>(done); }));
      "ShowProtectedAuthPrompt"_ns, [backgroundPromptStatus]() {
        return static_cast<bool>(backgroundPromptStatus->mDone);
      }));

  switch (result) {
  switch (backgroundPromptStatus->mResult) {
    case SECSuccess:
      return ToNewCString(nsDependentCString(PK11_PW_AUTHENTICATED));
    case SECWouldBlock: