gnupg 2.1.16 blocos esperando por entropia

8

Lançamentos de gnupg do 2.1.16 (atualmente 2.1.17) bloco esperando pela entropia somente na primeira invocação .

Nota: isso não é uma tentativa de gerar uma chave, apenas para descriptografar um arquivo e iniciar o agente.

A primeira vez que o gpg-agent é iniciado, diretamente com gpg2 file.gpg ou usando um aplicativo como pass , o pinentry aparece e assim que eu insiro minha senha e teco Enter ele fica pendurado por volta de 15s .

Todas as chamadas subseqüentes, dentro da janela do default-cache-ttl, são executadas imediatamente.

Em execução no modo --debug-all , o período em que ocorre o travamento imprime 1 :

gpg: DBG: chan_6 <- S PROGRESS need_entropy X 30 120
gpg: DBG: chan_6 <- S PROGRESS need_entropy X 120 120
gpg: DBG: chan_6 <- S PROGRESS need_entropy X 30 120
gpg: DBG: chan_6 <- S PROGRESS need_entropy X 120 120
gpg: DBG: chan_6 <- S PROGRESS need_entropy X 30 120
...

Eu instalei rng-tools para suplementar o pool de entropia:

cat /proc/sys/kernel/random/entropy_avail 
4094

e comparado com uma máquina com a mesma versão do gnupg que não tinha ferramentas de gravação ou haveged instalado, que exibe sem demora:

cat /proc/sys/kernel/random/entropy_avail
3783

Portanto, aparece como entropia suficiente no conjunto. Isso foi testado nos kernels 4.8.13 e 4.9.

O gpg usa um pool diferente? Como posso fornecer entropia suficiente ou eliminar o atraso dos 15s ao iniciar o agente?


1. O log de depuração completo .
por jasonwryan 24.12.2016 / 08:54

1 resposta

3

Eu acho que sei o que está acontecendo. No agente / gpg-agent.c do gnupg, esta função processa mensagens do libgcrypt.

/* This is our callback function for gcrypt progress messages.  It is
   set once at startup and dispatches progress messages to the
   corresponding threads of the agent.  */
static void 
agent_libgcrypt_progress_cb (void *data, const char *what, int printchar,
                             int current, int total)
{
  struct progress_dispatch_s *dispatch;
  npth_t mytid = npth_self ();

  (void)data;

  for (dispatch = progress_dispatch_list; dispatch; dispatch = dispatch->next)
    if (dispatch->ctrl && dispatch->tid == mytid)
      break;
  if (dispatch && dispatch->cb)
    dispatch->cb (dispatch->ctrl, what, printchar, current, total);

  /* Libgcrypt < 1.8 does not know about nPth and thus when it reads
   * from /dev/random this will block the process.  To mitigate this
   * problem we take a short nap when Libgcrypt tells us that it needs
   * more entropy.  This way other threads have chance to run.  */
#if GCRYPT_VERSION_NUMBER < 0x010800 /* 1.8.0 */
  if (what && !strcmp (what, "need_entropy"))
    npth_usleep (100000); /* 100ms */
#endif
}

Essa última parte com npth_usleep foi adicionada entre 2.1.15 e 2.1.17. Como isso é condicionalmente compilado se o libgcrypt for mais antigo que o 1.8.0, a correção direta seria recompilar o gnupg contra o libgcrypt 1.8.0 ou posterior… infelizmente essa versão parece não existir ainda.

O mais estranho é que o comentário sobre a leitura da libgcrypt / dev / random não é verdade. Stracing the agent revela que ele está lendo / dev / urandom e usando o novo getrandom (2) syscall, sem bloquear. No entanto, ele envia muitas mensagens need_entropy, fazendo com que npth_usleep bloqueie. A exclusão dessas linhas resolve o problema.

Devo mencionar que npth parece ser algum tipo de biblioteca multitarefa cooperativa, e npth_usleep provavelmente é o seu caminho para render, então pode ser melhor apenas reduzir significativamente esse atraso, caso a libgcrypt decida bloquear algum dia. (1ms não é perceptível)

    
por 30.12.2016 / 08:49