Page MenuHome GnuPG

gpg-agent: Spurious pinentries for an already unlocked key when decryption OpenPGP in 10 threads
Open, NormalPublic

Description

This is a strange one:

To reproduce for me:

export GNUPGHOME=$(mktemp -d) 
gpg --yes --pinentry-mode loopback --passphrase "test" --quick-gen-key test@example.com
echo Hello | gpg -er test@example.com > $GNUPGHOME/pgp-enc
# unlock the key
gpg  --pinentry-mode loopback --passphrase "test" -d $GNUPGHOME/pgp-enc
./run-threaded --no-list --threads 10 --data-type 3 --repeat 10 $GNUPGHOME/pgp-enc

Sometimes a pinentry pops up. Which I find quite surprising.

Details

Version
STABLE-BRANCH-2-2

Event Timeline

There is indeed a race condition between the passphrase cache and the pinentry invocation. There is even a comment on this somewhere in the code. The problem is that we would need to lock almost everything to avoid this rare condition.

Well, it should not happen if you always use the same key.

Happens though. With the test invocation above there is only one key in the keyring.

Just as a note: I think the main selling point of GnuPG is that its stable. We care about backwards compatibility and we (are || want to be) rock solid. Even if there is a rare race. With millions of installations, that race will happen regularly. So I really would like us to get all this fixed without losing to much performance by locking to much.

If you see a race and think "uh unlikely" multiply it by a billion executions. If it's still unlikely. Ignore it :-P

And I can't believe that we would have to lock _everything_ down for such an condition. Even if it means that we have to get creative.

aheinecke triaged this task as Normal priority.

You seem to accept it. So Normal Prio and assigned to you :-p

My analysis is that it's not a race condition but... it's about secure memory.
It is true that we have a race condition between putting an entry to cache after pinentry interaction _and_ next examining cache to invoke pinentry. But for this test case, the gpg process of unlock the key (and cache the passphrase) is finished before running the run-threaded command.

When secure memory pressure is high, xtrymalloc_secure may fail. Speficically, agent_get_cache may fail by the failure of getting the passphrase into secure memory, then, pinentry pops up.