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/2173315 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/2173315/+subscriptions -- ubuntu-bugs mailing list [email protected] https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs
