gpgv / can't allocate lock for

gpgv / can't allocate lock for

  • Written by
    Walter Doekes
  • Published on

gpgv prints out a warning that it cannot allocate a lock. This looks like something should be fixable, but it isn't.

Observed with gpg version 2.2.27-3ubuntu2.1:

$ gpgv </dev/null
gpgv: can't allocate lock for '/home/walter/.gnupg/trustedkeys.gpg'
gpgv: verify signatures failed: Unknown system error

The issue at hand here is the “gpgv: can't allocate lock for '/home/walter/.gnupg/trustedkeys.gpg'”. Can we fix something to suppress that?

TL;DR: no

Investigation

Fire up the debugger gdb and break at keybox_lock.constprop.0.isra.0.

(gdb) break keybox_lock.constprop.0.isra.0
Breakpoint 1 at 0x2f850: file ../kbx/../../kbx/keybox-init.c, line 271.
(gdb) run
Starting program: /usr/bin/gpgv
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, keybox_lock.constprop.0.isra.0 (yes=yes@entry=1, timeout=0, hd=<optimized out>, hd=<optimized out>) at ../kbx/../../kbx/keybox-init.c:271
271 keybox_lock (KEYBOX_HANDLE hd, int yes, long timeout)
(gdb) list
266  * Lock the keybox at handle HD, or unlock if YES is false.  TIMEOUT
267  * is the value used for dotlock_take.  In general -1 should be used
268  * when taking a lock; use 0 when releasing a lock.
269  */
270 gpg_error_t
271 keybox_lock (KEYBOX_HANDLE hd, int yes, long timeout)
272 {
273   gpg_error_t err = 0;
274   KB_NAME kb = hd->kb;
275
(gdb) list
276   if (!keybox_is_writable (kb))
277     return 0;
278
279   /* Make sure the lock handle has been created.  */
280   if (!kb->lockhd)
281     {
282       kb->lockhd = dotlock_create (kb->fname, 0);
283       if (!kb->lockhd)
284         {
285           err = gpg_error_from_syserror ();
(gdb) next
276   if (!keybox_is_writable (kb))
(gdb)
280   if (!kb->lockhd)
(gdb)
285           err = gpg_error_from_syserror ();

Okay, there was a dotlock_create that supposedly failed. But it isn't even called!

We can confirm this in the machine code:

$ objdump -d `which gpgv` --disassemble=keybox_lock.constprop.0.isra.0
...
000000000002f850 <keybox_lock.constprop.0.isra.0>:
   2f850: f3 0f 1e fa           endbr64
   2f854: 41 55                 push   %r13
   2f856: 41 54                 push   %r12
   2f858: 55                    push   %rbp
   2f859: 53                    push   %rbx
   2f85a: 48 83 ec 08           sub    $0x8,%rsp
   2f85e: 48 85 ff              test   %rdi,%rdi
   2f861: 74 3d                 je     2f8a0 <keybox_lock.constprop.0.isra.0+0x50>
   2f863: 4c 8d 6f 30           lea    0x30(%rdi),%r13
   2f867: 48 89 fb              mov    %rdi,%rbx
   2f86a: 89 f5                 mov    %esi,%ebp
   2f86c: be 02 00 00 00        mov    $0x2,%esi
   2f871: 4c 89 ef              mov    %r13,%rdi
   2f874: e8 97 6f fd ff        call   6810 <gpgrt_access@plt>

This call was the keybox_is_writable check.

   2f879: 41 89 c4              mov    %eax,%r12d
   2f87c: 85 c0                 test   %eax,%eax
   2f87e: 75 20                 jne    2f8a0 <keybox_lock.constprop.0.isra.0+0x50>
   2f880: 48 83 7b 20 00        cmpq   $0x0,0x20(%rbx)

Here is the first !kb->lockhd check.

   2f885: 74 41                 je     2f8c8 <keybox_lock.constprop.0.isra.0+0x78>

It was zero, so we jump to 0x2f8c8.

   2f887: 8b 43 28              mov    0x28(%rbx),%eax
   2f88a: 85 ed                 test   %ebp,%ebp
   2f88c: 74 2a                 je     2f8b8 <keybox_lock.constprop.0.isra.0+0x68>
   2f88e: 85 c0                 test   %eax,%eax
...

0x2f8c8 is here: immediate error handling. No attempt to call dotlock_create at all.

   2f8c8: e8 d3 6a fd ff        call   63a0 <gpg_err_code_from_syserror@plt>
   2f8cd: 4c 89 ee              mov    %r13,%rsi
   2f8d0: 48 8d 3d db c6 00 00  lea    0xc6db(%rip),%rdi        # 3bfb2 <__FUNCTION__.0.lto_priv.14+0x192>

Here the "can't allocate lock for '%s'\n" string is loaded.

   2f8d7: 41 89 c4              mov    %eax,%r12d
   2f8da: 0f b7 c0              movzwl %ax,%eax
   2f8dd: 0d 00 00 00 08        or     $0x8000000,%eax
   2f8e2: 45 85 e4              test   %r12d,%r12d
   2f8e5: 44 0f 45 e0           cmovne %eax,%r12d
   2f8e9: 31 c0                 xor    %eax,%eax
   2f8eb: e8 70 5b fe ff        call   15460 <log_info>
   2f8f0: eb b1                 jmp    2f8a3 <keybox_lock.constprop.0.isra.0+0x53>

So, we get a “can't allocate” warning always.

If we build gpgv ourselves, we can take a look at the gpgv.o object file, which has a no-op dotlock_create:

0000000000000400 <dotlock_create>:
 400:   f3 0f 1e fa             endbr64
 404:   31 c0                   xor    %eax,%eax
 406:   c3                      ret
 407:   66 0f 1f 84 00 00 00    nopw   0x0(%rax,%rax,1)
 40e:   00 00

This function does nothing and returns NULL. When linking, it is elided, so the call disappears, along with the double !kb->lockhd check.

(That nopw is an extended nop (nop-op). It is there for alignment purposes only.)

Conclusion

This leaves two questions:

  • Why is dotlock_create a no-op? Apparently gpgv.c contains this:

    // ...
    
    /* We do not do any locking, so use these stubs here */
    void
    dotlock_disable (void)
    {
    }
    
    dotlock_t
    dotlock_create (const char *file_to_lock, unsigned int flags)
    {
      (void)file_to_lock;
      (void)flags;
      return NULL;
    }
    
    // ...
    
  • Why are we forced to look at a warning message for something that will never succeed anyway? I guess no one saw this as an issue.


Back to overview Newer post: bash / postfix health check / dev tcp Older post: etckeeper / git / pack-objects died of signal 9