#1129944 pinentry-qt: immediate exit with a core dump if $DISPLAY is unset or set but unavailable #1129944
- Package:
- pinentry-qt
- Source:
- pinentry-qt
- Description:
- Qt-based PIN or pass-phrase entry dialog for GnuPG
- Submitter:
- Vincent Lefevre
- Date:
- 2026-03-08 17:31:03 UTC
- Severity:
- normal
pinentry-qt immediately crashes if the X display is not available. This can happen after a ssh to a remote machine (or if the value of DISPLAY is no longer valid). With "gpg -d file.gpg", I just get: [...] gpg: public key decryption failed: No pinentry gpg: decryption failed: No pinentry which is not informative at all. But the crash is visible when I run pinentry-qt directly from the command line: ------------------------------------------------------------ qaa:~> pinentry-qt qt.qpa.xcb: could not connect to display qt.qpa.plugin: From 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platform plugin. qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found. This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem. Available platform plugins are: xcb, wayland, linuxfb, offscreen, minimal, vkkhrdisplay, vnc, wayland-egl, eglfs, minimalegl. zsh: IOT instruction (core dumped) pinentry-qt ------------------------------------------------------------ Perhaps some "platform plugin" should be installed? But there are no Recommends on such a plugin, and the documentation provides no information. pinentry-gtk-2 from the pinentry-gtk2 package (removed in this version) did not have this issue. A workaround might be to use a wrapper script of the form #!/bin/sh if xset -q > /dev/null 2> /dev/null ; then exec pinentry-qt "$@" else exec pinentry-curses "$@" fi
[...] I forgot to say: obviously, if the X display is not available, an X dialog box cannot be displayed, and the correct behavior would be to use "an alternative text-mode dialog" as documented (in both the man page and the package description), like what the GTK2 flavor did.
Control: retitle -1 pinentry-qt: immediate exit if $DISPLAY set but unavailable Hello, this works as expected (fallback to tty) if DISPLAY is unset but pinentry-qt (and -fltk) exit with an error if DISPLAY points to an invalid or inacessible display. cu Andreas
Control: retitle -1 pinentry-qt: immediate exit with a core dump if $DISPLAY is unset or set but unavailable
a core dump.
pinentry-fltk in this case):
qaa:~> unset DISPLAY
qaa:~> pinentry-qt
qt.qpa.xcb: could not connect to display
qt.qpa.plugin: From 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platform plugin.
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
Available platform plugins are: xcb, wayland, linuxfb, offscreen, minimal, vkkhrdisplay, vnc, wayland-egl, eglfs, minimalegl.
zsh: IOT instruction (core dumped) pinentry-qt
Here's the backtrace:
(gdb) bt
#0 __pthread_kill_implementation (threadid=<optimized out>,
signo=signo@entry=6, no_tid=no_tid@entry=0) at ./nptl/pthread_kill.c:44
#1 0x00007f7ae38a147f in __pthread_kill_internal (threadid=<optimized out>,
signo=6) at ./nptl/pthread_kill.c:89
#2 0x00007f7ae384a942 in __GI_raise (sig=sig@entry=6)
at ../sysdeps/posix/raise.c:26
#3 0x00007f7ae38324ac in __GI_abort () at ./stdlib/abort.c:77
#4 0x00007f7ae46dc53b in ?? () from /usr/lib/x86_64-linux-gnu/libQt6Core.so.6
#5 0x00007f7ae46dd34f in QMessageLogger::fatal(char const*, ...) const ()
from /usr/lib/x86_64-linux-gnu/libQt6Core.so.6
#6 0x00007f7ae4d51144 in ?? () from /usr/lib/x86_64-linux-gnu/libQt6Gui.so.6
#7 0x00007f7ae4ded828 in QGuiApplicationPrivate::createEventDispatcher() ()
from /usr/lib/x86_64-linux-gnu/libQt6Gui.so.6
#8 0x00007f7ae47a90df in QCoreApplicationPrivate::init() ()
from /usr/lib/x86_64-linux-gnu/libQt6Core.so.6
#9 0x00007f7ae4ded8ce in QGuiApplicationPrivate::init() ()
from /usr/lib/x86_64-linux-gnu/libQt6Gui.so.6
#10 0x00007f7ae3fb2b8d in QApplicationPrivate::init() ()
from /usr/lib/x86_64-linux-gnu/libQt6Widgets.so.6
#11 0x0000564ee14196da in ?? ()
#12 0x00007f7ae3833f75 in __libc_start_call_main (
main=main@entry=0x564ee1419430, argc=argc@entry=1,
argv=argv@entry=0x7fff60fd70f8)
at ../sysdeps/nptl/libc_start_call_main.h:58
#13 0x00007f7ae3834027 in __libc_start_main_impl (main=0x564ee1419430, argc=1,
argv=0x7fff60fd70f8, init=<optimized out>, fini=<optimized out>,
rtld_fini=<optimized out>, stack_end=0x7fff60fd70e8)
at ../csu/libc-start.c:360
#14 0x0000564ee1419af1 in ?? ()
Perhaps some additional package is needed for this to work, which
would mean a missing dependency.
But I don't understand the error messages:
qt.qpa.plugin: From 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platform plugin.
The libxcb-cursor0 package is installed on my machine. In there a
reason for the above message?
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
Note: I do not use any desktop environment, just plain X11 with
FVWM2 as my window manager.
If DISPLAY points to an inaccessible display, pinentry-fltk exits
with an error, but not immediately (I mean, it first interacts
with GnuPG before exiting) and not with a core dump, contrary to
pinentry-qt, for which it looks like an initialization issue.
https://www.zsh.org/mla/workers/2023/msg00330.html it mixes up clean exit with SIGABRT and crashing. I do get the fallback for env -u DISPLAY pinentry-qt and invalid display "abort"s metzler@argenau:~$ env DISPLAY=invalid pinentry-qt qt.qpa.xcb: could not connect to display invalid qt.qpa.plugin: From 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platform plugin. qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found. This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem. Available platform plugins are: eglfs, wayland, offscreen, linuxfb, wayland-egl, vnc, minimalegl, minimal, xcb, vkkhrdisplay. Aborted env DISPLAY=invalid pinentry-qt [...] I think that is just a generic error message, communicating an at some point frequent cause for entering this code-path. [...] I will update the upstream bug report with your information. - Thanks! cu Andreas
really a minor issue.
SIGABRT is an abnormal termination (normally due to an unrecoverable
error following a bug, such as assertion failures, which is why a
core dump is generated for debugging), as opposed to a termination
with exit() (or equivalently, a return from main()).
I think I'm actually facing 2 bugs:
1. Some kind of initialization issue (because it occurs very early),
when DISPLAY is unset or set but unavailable. This one is specific to
pinentry-qt.
2. The lack of fallback when DISPLAY is set but unavailable. This one
affects both pinentry-fltk and pinentry-qt, and seems to occur only
when the program tries to display a dialog box.
In fltk/main.cxx, I can see:
#ifdef FALLBACK_CURSES
if (!pinentry_have_display(argc, argv))
pinentry_cmd_handler = curses_cmd_handler;
else
#endif
(qt/main.cpp has something very similar), and pinentry/pinentry.c
defines pinentry_have_display(), which just checks whether a --display
option is used or $DISPLAY is defined. In particular, it does not try
to connect to the display. This is the second bug (possibly seen as a
missing feature).
I suppose that the first bug occurs before the check for the fallback
to curses.
This also fails: qaa:~> env -u DISPLAY pinentry-qt --help qt.qpa.xcb: could not connect to display [...] with no help displayed.
I just tried this in a minimal chroot on barriere.debian.org: ametzler@barriere:~$ schroot --begin-session -c forky -n ametzler ; printf \\a ; dd-schroot-cmd -c ametzler apt-get update && dd-schroot-cmd -c ametzler apt-get -y dist-upgrade ; dd-schroot-cmd -c ametzler apt-get -y install pinentry-qt [...] ametzler@barriere:~$ schroot --run-session -c ametzler (forky_amd64-dchroot)ametzler@barriere:~$ env -u DISPLAY pinentry-qt --help pinentry-qt (pinentry) 1.3.2 Copyright (C) 2016 g10 Code GmbH License GPLv2+: GNU GPL version 2 or later <https://www.gnu.org/licenses/> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Usage: pinentry-qt [options] (-h for help) [...] Package list attached - Anything obvious that is missing on your system? Are you running wayland instead of X11? In that case you would also need to unset WAYLAND_DISPLAY. cu Andreas
On 2026-03-07 Andreas Metzler <ametzler@bebt.de> wrote:
[...]
Plus possibly XDG_SESSION_TYPE. The heuristics are a little bit strange
...
if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
// check a few environment variables that are usually set on X11 or Wayland sessions
const bool hasWaylandDisplay = qEnvironmentVariableIsSet("WAYLAND_DISPLAY");
const bool isWaylandSessionType = qgetenv("XDG_SESSION_TYPE") == "wayland";
const bool hasX11Display = pinentry_have_display(argc, argv);
const bool isX11SessionType = qgetenv("XDG_SESSION_TYPE") == "x11";
const bool isGUISession = hasWaylandDisplay || isWaylandSessionType || hasX11Display || isX11SessionType;
qCDebug(PINENTRY_LOG) << "hasWaylandDisplay:" << hasWaylandDisplay;
qCDebug(PINENTRY_LOG) << "isWaylandSessionType:" << isWaylandSessionType;
qCDebug(PINENTRY_LOG) << "hasX11Display:" << hasX11Display;
qCDebug(PINENTRY_LOG) << "isX11SessionType:" << isX11SessionType;
qCDebug(PINENTRY_LOG) << "isGUISession:" << isGUISession;
#else
const bool isGUISession = pinentry_have_display(argc, argv);
#endif
if (!isGUISession) {
pinentry_cmd_handler = curses_cmd_handler;
pinentry_set_flavor_flag ("curses");
... I doubt it is possible to open an X11 window if DISPLAY is unset,
even if XDG_SESSION_TYPE=x11.
cu Andreas
On 2026-03-07 Andreas Metzler <ametzler@bebt.de> wrote:
[...]
Plus possibly XDG_SESSION_TYPE. The heuristics are a little bit strange
...
if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
// check a few environment variables that are usually set on X11 or Wayland sessions
const bool hasWaylandDisplay = qEnvironmentVariableIsSet("WAYLAND_DISPLAY");
const bool isWaylandSessionType = qgetenv("XDG_SESSION_TYPE") == "wayland";
const bool hasX11Display = pinentry_have_display(argc, argv);
const bool isX11SessionType = qgetenv("XDG_SESSION_TYPE") == "x11";
const bool isGUISession = hasWaylandDisplay || isWaylandSessionType || hasX11Display || isX11SessionType;
qCDebug(PINENTRY_LOG) << "hasWaylandDisplay:" << hasWaylandDisplay;
qCDebug(PINENTRY_LOG) << "isWaylandSessionType:" << isWaylandSessionType;
qCDebug(PINENTRY_LOG) << "hasX11Display:" << hasX11Display;
qCDebug(PINENTRY_LOG) << "isX11SessionType:" << isX11SessionType;
qCDebug(PINENTRY_LOG) << "isGUISession:" << isGUISession;
#else
const bool isGUISession = pinentry_have_display(argc, argv);
#endif
if (!isGUISession) {
pinentry_cmd_handler = curses_cmd_handler;
pinentry_set_flavor_flag ("curses");
... I doubt it is possible to open an X11 window if DISPLAY is unset,
even if XDG_SESSION_TYPE=x11.
cu Andreas
I'm just under X11. If I unset XDG_SESSION_TYPE (which is "x11" here), the problem disappears in the case where DISPLAY is unset, i.e. (1) env -u XDG_SESSION_TYPE -u DISPLAY pinentry-qt --help gives the help text, but (2) env -u XDG_SESSION_TYPE DISPLAY=invalid pinentry-qt --help still terminates abnormally (aborts) without the help text. In case (1), isGUISession is false, but if XDG_SESSION_TYPE is x11 or DISPLAY is set (valid or invalid), isGUISession is true. In this latter case, if the display is unavailable, the abort occurs. I confirm. I think that the fallback to curses occurs too early. Instead of aborting, pinentry-qt should fall back to curses at this time.
[...] FYI, it is pam_systemd that sets the XDG_SESSION_TYPE environment variable (assuming something else does not set it, but that would be undocumented, and "grep -r XDG_SESSION_TYPE /etc" outputs nothing): the pam_systemd(8) man page says: The following environment variables are read by the module and may be used by the PAM service to pass metadata to the module. If these variables are not set when the PAM module is invoked but can be determined otherwise they are set by the module, so that these variables are initialized for the session and applications if known at all. $XDG_SESSION_TYPE [...] I'm wondering why you did not get an abort like me. But after ssh with X11 forwarding, $XDG_SESSION_TYPE is set to "tty" instead of "x11"[*], so that this changes the behavior. [*] I've just reported https://github.com/systemd/systemd/issues/40992
Hello, Because I have got XDG_SESSION_TYPE=tty since I am not using a graphical display manager like gdm but startx+wmaker. I have googled a little bit and iirc wayland behaves differently, applications fall back to a default compositor if XDG_SESSION_TYPE=wayland but WAYLAND_DISPLAY is unset. The whole thing is also not trivially fixable, neither QT nor FLTK have a direct replacement for gtk_init_check(). cu Andreas
OK, I suppose that pam_systemd is used at tty login time, but
not when X is started. I think that either startx or xinit
should change XDG_SESSION_TYPE to "x11", otherwise I don't
see the point of differentiating "tty" and "x11".
env DISPLAY=:1 vlc
VLC falls back to the tty interface. This shows that there is
a solution at least for Qt.
In any case, if X11 is detected, XOpenDisplay() could be used.
It seems that this is what VLC does: modules/gui/qt/qt.cpp has
static bool HasX11( vlc_object_t *obj )
{
if( !vlc_xlib_init( obj ) )
return false;
Display *dpy = XOpenDisplay( NULL );
if( dpy == NULL )
return false;
XCloseDisplay( dpy );
return true;
}
[...] Might be. I could not find verbose docs, contrary to the XDG... name it is systemd-specific, I would not rule out that setting XDG_SESSION_TYPE=x11 without an xsession-manager is wrong. I am sure it is solvable in some way, but adding Xlib (and wayland) calls to a QT application is quite far from a "trivial" fix. cu Andreas