#1129944 pinentry-qt: immediate exit with a core dump if $DISPLAY is unset or set but unavailable

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
#1129944#5
Date:
2026-03-06 11:21:08 UTC
From:
To:
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

#1129944#10
Date:
2026-03-06 11:41:35 UTC
From:
To:
[...]

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.

#1129944#15
Date:
2026-03-06 12:41:14 UTC
From:
To:
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

#1129944#24
Date:
2026-03-06 13:51:51 UTC
From:
To:
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.

#1129944#31
Date:
2026-03-06 17:14:26 UTC
From:
To:
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

#1129944#36
Date:
2026-03-06 17:55:11 UTC
From:
To:
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.

#1129944#41
Date:
2026-03-06 22:53:26 UTC
From:
To:
This also fails:

qaa:~> env -u DISPLAY pinentry-qt --help
qt.qpa.xcb: could not connect to display
[...]

with no help displayed.

#1129944#46
Date:
2026-03-07 06:03:50 UTC
From:
To:
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

#1129944#51
Date:
2026-03-07 06:53:31 UTC
From:
To:
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

#1129944#56
Date:
2026-03-07 06:53:31 UTC
From:
To:
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

#1129944#61
Date:
2026-03-07 16:17:20 UTC
From:
To:
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.

#1129944#66
Date:
2026-03-07 17:06:25 UTC
From:
To:
[...]

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

#1129944#71
Date:
2026-03-07 18:17:54 UTC
From:
To:

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

#1129944#76
Date:
2026-03-07 22:45:48 UTC
From:
To:
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;
}

#1129944#81
Date:
2026-03-08 17:29:19 UTC
From:
To:
[...]

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