Public bug reported:

SUMMARY

SearchResultsView._unregisterProvider() does not check the result of
indexOf():

    _unregisterProvider(provider) {
        const index = this._providers.indexOf(provider);
        this._providers.splice(index, 1);

        if (provider.display)
            provider.display.destroy();
    }

If the passed provider is not in this._providers, indexOf() returns -1 and
splice(-1, 1) silently removes the LAST provider in the array - an arbitrary,
unrelated provider. Since SearchController.removeProvider() is a thin wrapper
around this method, the public API documented for extensions (gjs.guide) is
affected as well.

This is easy to trigger because _registerProvider() can silently refuse to
register a provider:

    _registerProvider(provider) {
        provider.searchInProgress = false;

        // Filter out unwanted providers.
        if (provider.appInfo && 
!this._parentalControlsManager.shouldShowApp(provider.appInfo))
            return;

        this._providers.push(provider);
        this._ensureProviderDisplay(provider);
    }

The caller has no way to know registration was refused, keeps its provider
reference, and will later call removeProvider()/_unregisterProvider() with a
provider that was never registered - killing an innocent provider each time.

REAL-WORLD IMPACT (how this was found)

On Ubuntu 26.04, the [email protected] extension registers a
provider whose appInfo is the xdg default browser. Google Chrome's deb package
ships com.google.Chrome.desktop with NoDisplay=true (an alias kept for XDG
portal app-ID matching), and "xdg-settings get default-web-browser" can
legitimately point at it. In that configuration:

1. On every extension enable (login/unlock), registration is silently refused
   (shouldShowApp() -> appInfo.should_show() -> false), but the extension
   keeps its reference.
2. On every extension disable (screen lock/suspend), _unregisterProvider() is
   called with the never-registered provider -> splice(-1, 1) destroys the
   last provider in the list.
3. Remote providers are resurrected by _reloadRemoteProviders() on
   installed-changed (e.g. snap refreshes rewriting .desktop files), but the
   AppSearchProvider ('applications') is only registered once, in the
   SearchResultsView constructor. Once lock/unlock cycles between two reloads
   eat through the tail of the list and reach it, application search is dead
   for the rest of the session - the overview shows "No results" for every
   app, with nothing in the logs.

The stochastic race between suspend/lock cycles and installed-changed reloads
makes the breakage look random. Only a re-login fixes it. (The extension's
side of the bug - keeping a stale reference - is filed separately against
gnome-shell-ubuntu-extensions: <LINK-BUG-EXTENSION>)

MINIMAL REPRODUCER

In Looking Glass (Alt+F2, "lg"), on any session:

    Main.overview.searchController._searchResults._providers.map(p => 
p.id).join(' | ')
    // note the list, then:
    Main.overview.searchController.removeProvider({})
    Main.overview.searchController._searchResults._providers.map(p => 
p.id).join(' | ')
    // -> the last provider has been silently removed and its display destroyed

SUGGESTED FIX

    _unregisterProvider(provider) {
        const index = this._providers.indexOf(provider);
        if (index < 0)
            return; // or log a warning

        this._providers.splice(index, 1);

        if (provider.display)
            provider.display.destroy();
    }

Additionally, consider making _registerProvider()'s refusal observable (return
a boolean, or log), so callers don't end up holding references to providers
that were never registered.

** Affects: gnome-shell (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/2161808

Title:
  SearchResultsView._unregisterProvider() removes an arbitrary provider
  when called with an unregistered provider (splice(-1, 1))

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/gnome-shell/+bug/2161808/+subscriptions


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

Reply via email to