*** This bug is a duplicate of bug 2173315 ***
    https://bugs.launchpad.net/bugs/2173315

Public bug reported:

ENVIRONMENT
-----------

- Ubuntu 26.04 (resolute), kernel 7.0.0-42-generic, Wayland session
- gnome-shell 50.1-0ubuntu1.5, mutter 50.1-0ubuntu2.4 (libmutter-18-0)
- libgcr-4-4 4.4.0.1-8 (source package gcr4), libgcrypt20 1.12.0-2ubuntu1.1,
  libsecret-1-0 0.21.7-2build1, gnome-keyring 50.0-1
- Intel Arc Graphics (Meteor Lake-P, i915); gnome-shell runs as 
[email protected]

ACTUAL BEHAVIOUR
----------------

gnome-shell aborts with SIGABRT ("free(): invalid pointer") while it is acting 
as the
org.gnome.keyring.SystemPrompter, i.e. while a keyring password prompt from
gnome-keyring-daemon is completing. The compositor dies, the Wayland session is 
lost and
gdm shows the login screen; every running application is terminated.

Journal of the crashed session:

  23:26:35.936991 gnome-shell[13028]: free(): invalid pointer
  23:26:35.936991 gnome-shell[13028]: GNOME Shell crashed with signal 6
  23:26:44.914131 gnome-shell[13459]: (EE) failed to read Wayland events: 
Broken pipe
  23:26:44.9 systemd[8308]: [email protected]: Main process 
exited, code=killed, status=6/ABRT
  23:26:44.910054 gnome-keyring-daemon[12349]: couldn't prompt for password: 
The operation was cancelled

The last line is the requester losing its prompter 8 s after the abort: a 
prompt was in
flight when the shell died.

Note the second-order damage: gnome-shell's failure guard
(org.gnome.Shell-disable-extensions.service, 
ConditionPathExists=%t/gnome-shell-disable-extensions)
then runs `gsettings set org.gnome.shell disable-user-extensions true`, so 
after this crash
*all* user extensions come back disabled. The symptom the user sees is "my 
GNOME extensions
are gone after the upgrade", not a crash.

STACK (from the apport core of the crashed shell, symbolized with debuginfod)
----------------------------------------------------------------------------

#15 g_realloc (mem=<optimized out>, n_bytes=<optimized out>) at 
../../../glib/gmem.c:180
#16 _gcry_free (p=0x7aff3ceac008) at ../../src/global.c:1124
#17 _gcry_mpi_free (a=0x59ff54475b00) at ../mpi/../../mpi/mpiutil.c:240
#18 _gcry_mpi_release (a=0x59ff54475b00) at ../mpi/../../mpi/mpiutil.c:746
#19 gcry_mpi_release (a=0x59ff54475b00) at ../../src/visibility.c:284
#20 egg_dh_privkey_free (privkey=0x59ff54324b10) at 
../egg/egg-dh-libgcrypt.c:243
#21 gcr_secret_exchange_default_free (to_free=0x59ff544e7ee0) at 
../gcr/gcr-secret-exchange.c:584
#22 gcr_secret_exchange_finalize (obj=0x59ff544e7570 [GcrSecretExchange]) at 
../gcr/gcr-secret-exchange.c:200
#23 g_object_unref (_object=0x59ff544e7570) at ../../../gobject/gobject.c:4910
#24 active_prompt_unref (data=0x59ff533e6270) at 
../gcr/gcr-system-prompter.c:210
#25 active_prompt_unref (data=0x59ff533e6270) at 
../gcr/gcr-system-prompter.c:596
#26 on_prompt_ready_complete (source=<optimized out>, result=0x59ff553aa480, 
user_data=0x59ff533e6270) at ../gcr/gcr-system-prompter.c:616
#27 g_task_return_now (task=0x59ff553aa480 [GTask]) at ../../../gio/gtask.c:1363

Full backtrace with the abort path (malloc_printerr) attached.

WHAT THE CRASHING CODE DOES
---------------------------

A prompt completes (gcr-system-prompter.c:616, on_prompt_ready_complete), the 
ActivePrompt
reference is dropped (active_prompt_unref), which drops the prompt's 
GcrSecretExchange
(g_object_unref at gcr-system-prompter.c:210). gcr_secret_exchange_finalize() 
then calls
gcr_secret_exchange_default_free() -> egg_dh_privkey_free() -> 
gcry_mpi_release() for the DH
private key MPI, and glibc rejects the MPI's limb buffer (0x7aff3ceac008): it 
is not a live
allocation, so either it is freed twice or it was not allocated by the 
allocator libgcrypt is
currently using.

That second variant is plausible because gcrypt's free here goes through GLib
(_gcry_free -> g_realloc), i.e. through the handlers installed by
egg_libgcrypt_initialize():

    gcry_set_allocation_handler ((gcry_handler_alloc_t)g_malloc,
                                 (gcry_handler_alloc_t)egg_secure_alloc,
                                 egg_secure_check,
                                 (gcry_handler_realloc_t)egg_secure_realloc,
                                 egg_secure_free);

and that function skips all of it when libgcrypt is already initialized:

    if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) { ... }

gcr-secret-exchange.c never calls egg_libgcrypt_initialize() itself (it goes 
straight to
egg_dh_default_params() at gcr-secret-exchange.c:607 from 
gcr_secret_exchange_new()), so a
secret exchange created before something else initializes gcrypt would hold 
MPIs allocated
with a different allocator than the one used to free them.

EXPECTED BEHAVIOUR
------------------

The shell completes or cancels the prompt and survives; the session is not lost 
and
extensions are not disabled.

HOW TO REPRODUCE
----------------

Needs a locked secret collection so that gnome-keyring-daemon has to ask
the system prompter:

 1. Log in with the login keyring locked (fresh session where PAM did not hand 
the password
    to gnome-keyring, or lock it explicitly with
    `busctl --user call org.freedesktop.secrets 
/org/freedesktop/secrets/collection/login \
     org.freedesktop.Secret.Collection Lock` ).
 2. From any client, request a secret (libsecret lookup: seahorse, GNOME 
Settings / Online
    Accounts, Evolution, a browser, `secret-tool lookup ...`).
 3. gnome-keyring-daemon raises the prompt; the shell's Gcr.SystemPrompter 
shows it.
 4. Answer or cancel the prompt: gnome-shell dies in the stack above and the 
session ends.

On this machine it happened with an ordinary secret lookup shortly after login, 
without any
deliberate action in the prompter.

IMPACT
------

Every application is killed and unsaved work is lost; after the crash all user 
GNOME Shell
extensions are switched off by the failure guard, which looks like "the upgrade 
broke my
extensions".

NOT A SHELL EXTENSION PROBLEM
-----------------------------

Verified: the same extension set was run in an isolated private shell
(`gnome-shell --wayland --headless`, separate XDG_* roots); all extensions 
reached
State: ACTIVE and the code paths they add (keybinding activation) were 
exercised without any
crash. In the core above there is no JS frame at all between the main loop and 
the aborting
C code: the abort is entirely inside libgcr/libgcrypt. Extensions can only be 
the reason a
prompt is requested, not the reason the free fails.

RELATED UPSTREAM REPORTS (not the same signature)
-------------------------------------------------

- GNOME/gcr#150  gcr-ssh-agent crashes (SIGSEGV in on_prompt_open) when a 
prompt open times out
- GNOME/gcr#77   gcr-prompter terminates with SIGABRT
- GNOME/gcr#9    Recent g_hash_table_lookup_extended change crashes GNOME Shell 
after unlocking a SSH key

VERSIONS CHECKED
----------------

gcr-system-prompter.c and gcr-secret-exchange.c are byte-identical between gcr 
4.4.0.1-3 and
4.4.1-3, so this does not look fixed by the 4.4.1 release; a fix, if any, needs 
to be located
upstream first.

** Affects: gcr4 (Ubuntu)
     Importance: Undecided
         Status: New

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2173300

Title:
  gnome-shell aborts with "free(): invalid pointer" in gcr's
  egg_dh_privkey_free when a keyring prompt completes (whole session
  lost)

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/gcr4/+bug/2173300/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to