gpgv / can't allocate lock for
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? Apparentlygpgv.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.