Verified gnome-shell 50.1-0ubuntu1.2 on Ubuntu 26.04 LTS.
After locking/unlocking the screen over 20 times the search providers are still 
available, and I'm able to find applications by searching.

** Description changed:

  [ Impact ]
  
  If the default HTTP URL handler is a "hidden" application, every time
  you lock and unlock the screen a random shell search provider is
  removed.
  
  Eventually, all search built-in search providers will be removed and
  searching for installed applications will yield no results.
  
  This is notably the case for Google's official Chrome deb package, which
  ships two desktop entries: com.google.Chrome.desktop as hidden, and
  google-chrome.desktop as visible. If the hidden one is set as the
  default Web Browser, then the bug will happen.
  
  [ Test Plan ]
  
  0. Install the gnome-shell update, log-out and log-in again (or reboot)
  1. Install Google Chrome from https://www.google.com/chrome/
  2. Open Google Chrome
  3. When prompted, set it as the default browser
+    -> Check that $ gio mime x-scheme-handler/https
+       returns 'com.google.Chrome.desktop' as default.
+    -> If not, from Settings > Apps > Default Apps > Web
+       change the default to the other Google Chrome entry
  4. Lock and unlock the screen 20 times in a row
  5. Open the applications menu
  6. Verify that searching for an installed application does find it
  
  [ Where problems could occur ]
  
  GNOME Shell provides the desktop UI in Ubuntu Desktop. Issues could
  manifest anywhere in the desktop. The change is trivial enough to not
  expect any regressions.
  
  [ Other info -- the full original analysis ]
  
  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.

** Tags removed: verification-needed-resolute
** Tags added: verification-done-resolute

-- 
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/gnome-shell/+bug/2161808/+subscriptions


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

Reply via email to