Public bug reported:

# bubblewrap 0.9.0-1ubuntu0.2 (CVE-2026-87766): bind-mount destination
mis-resolves relative symlinks containing "..", breaking flatpak apps

## Summary

The security patch in **bubblewrap 0.9.0-1ubuntu0.2** (noble-security,
2026-09-14, CVE-2026-87766) introduced a regression in destination-path
resolution: when a bind-mount **destination** traverses a relative symlink
whose target contains `..`, bubblewrap resolves it incorrectly (one `..` is
effectively dropped). It then attempts the mount at a non-existent path and
fails with `ENOENT`.

This breaks Flatpak apps whose manifest grants a per-app `xdg-run` directory
with `:create` (e.g. Discord IPC / `xdg-run/app/com.discordapp.Discord:create`).
Such apps no longer start at all.

Regression is present in `0.9.0-1ubuntu0.2` and absent in
`0.9.0-1ubuntu0.1`.

## Environment

- OS: Linux Mint 22.3 (Zena), based on Ubuntu 24.04 (noble), amd64
- Kernel: 6.14.0-37-generic
- bubblewrap: `0.9.0-1ubuntu0.2` (noble-security), `/usr/bin/bwrap` non-setuid
  (unprivileged user namespaces; `kernel.unprivileged_userns_clone=1`,
  `kernel.apparmor_restrict_unprivileged_userns=0`)
- Flatpak: 1.14.6
- Affected example: `com.heroicgameslauncher.hgl` (Heroic Games Launcher)

## Regression source

`/usr/share/doc/bubblewrap/changelog.Debian.gz`:

```
bubblewrap (0.9.0-1ubuntu0.2) noble-security; urgency=medium

  * SECURITY UPDATE: Improper link resolution during sandbox setup
    - debian/patches/CVE-2026-87766-1.patch: Import safe_openat() from crun
      in chroot_realpath.c, meson.build, safe_openat.c, and utils.h
    - debian/patches/CVE-2026-87766-2.patch: Create and resolve destinations
      without following symlinks, and reject mount operations on symlink
      destinations in bubblewrap.c
    - CVE-2026-87766

 -- Kyle Kernick <[email protected]>  Mon, 14 Sep 2026 12:44:27 -0600
```

The `CVE-2026-87766-2.patch` rewriting of destination creation/resolution
mis-handles relative symlinks that contain `..`, which Flatpak legitimately
relies on (see below).

## Steps to reproduce

A self-contained reproducer that needs neither Flatpak nor any app is attached
(`bubblewrap-symlink-dest-repro.sh`). Core of it:

```sh
R=$(mktemp -d)
mkdir -p "$R/root/run/user/1000" "$R/root/run/flatpak/app" "$R/root/bin" 
"$R/src"
ln -sfn ../../flatpak/app "$R/root/run/user/1000/app"      # same link Flatpak 
creates
ln -sfn /usr/bin/true      "$R/root/bin/true"

bwrap --bind "$R/root" / \
      --bind "$R/src" /run/user/1000/app/com.discordapp.Discord \
      -- /bin/true
```

Real-world reproduction (Flatpak):

```sh
flatpak run --branch=stable --arch=x86_64 --command=true 
com.heroicgameslauncher.hgl
```

## Expected result

bwrap follows the symlink `/run/user/1000/app -> ../../flatpak/app` while
resolving the destination. The symlink lives in directory `/run/user/1000`,
so the target resolves to `/run/flatpak/app`; the destination is therefore

```
/newroot/run/flatpak/app/com.discordapp.Discord
```

which exists (bwrap creates it / Flatpak's `:create` grant), and the bind
mount succeeds.

## Actual result

Both the minimal reproducer and the real Flatpak run fail:

```
bwrap: Can't bind mount /oldroot/.../src on 
/newroot/run/user/flatpak/app/com.discordapp.Discord: Unable to mount source on 
destination: No such file or directory
```

Note the bogus path component `/run/user/flatpak/...` (one `..` was dropped:
the correct path is `/run/flatpak/...`).

## strace evidence

```
readlink("/newroot/run/user",           ..., 4095) = -1 EINVAL
readlink("/newroot/run/user/1000",      ..., 4095) = -1 EINVAL
readlink("/newroot/run/user/1000/app",  "../../flatpak/app", 4095) = 17
readlink("/newroot/run/user/flatpak",   ..., 4095) = -1 ENOENT
mount("/oldroot/.../src",
      "/newroot/run/user/flatpak/app/com.discordapp.Discord",
      NULL, MS_BIND|MS_REC|MS_SILENT, NULL) = -1 ENOENT
```

bwrap resolves `../../flatpak/app` relative to the wrong base directory:
after `readlink(".../1000/app") = "../../flatpak/app"` it should walk up to
`/newroot/run` and append `flatpak/app`, yielding `/newroot/run/flatpak/app`.
Instead it reaches `/newroot/run/user/flatpak`, i.e. it applies one `..` less
than expected.

## Root cause / analysis

1. Flatpak's per-app runtime directory
   `/run/user/<uid>/.flatpak/<app-id>/xdg-run/` contains relative symlinks
   such as `app -> ../../flatpak/app`, `bus -> ../../flatpak/bus`,
   `doc -> ../../flatpak/doc`, `.flatpak -> ../../flatpak/.flatpak`, etc.
   This directory is bind-mounted to `/run/user/<uid>` inside the sandbox, so
   inside the sandbox `/run/user/<uid>/app` is that relative symlink.
2. Flatpak emits the operation
   `--bind /run/user/1000/app/com.discordapp.Discord 
/run/user/1000/app/com.discordapp.Discord`
   (source == destination; the `:create` grant).
3. The new destination resolution code added by
   `CVE-2026-87766-2.patch` resolves the destination path component by
   component. On encountering the relative symlink it computes the result
   incorrectly, producing `/run/user/flatpak/app/...` instead of
   `/run/flatpak/app/...`.
4. `mount(2)` is then called with a destination that does not exist, and
   fails with `ENOENT`, aborting sandbox setup.

The symptom is specific to destinations that traverse a **relative symlink
containing `..`**; simple destinations and absolute symlinks are unaffected.
That is why e.g. `org.flatpak.Builder` still launches (it has no `xdg-run/app`
grant), while Heroic fails.

## Impact

Users on noble (and derivatives such as Linux Mint 22.x) who updated
bubblewrap to `0.9.0-1ubuntu0.2` can no longer launch affected Flatpak apps.
Impact is `bwrap` aborting before exec, i.e. complete failure to start, not a
degraded sandbox.

## Workaround

Replace the offending symlink in the app's runtime directory with a real
directory (Flatpak prints a harmless warning and proceeds):

```sh
D=/run/user/$UID/.flatpak/com.heroicgameslauncher.hgl/xdg-run
rm  "$D/app"
mkdir "$D/app"
```

Verified: `flatpak run ... --command=true com.heroicgameslauncher.hgl` then
exits 0. The symlinks are recreated by Flatpak at login, so the workaround may
need to be repeated. A cleaner temporary workaround is downgrading:

```sh
sudo apt install bubblewrap=0.9.0-1ubuntu0.1
```

## Suggested fix

Correct the destination component resolution introduced in
`CVE-2026-87766-2.patch` so that relative symlink targets are resolved
correctly with respect to the symlink's containing directory (each `..` pops
one component of the resolved path). Absolute symlinks and symlink-free paths
already behave correctly.

## Attachments

- `bubblewrap-symlink-dest-repro.sh` — minimal reproducer (no Flatpak
needed)

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

** Attachment added: "bubblewrap-symlink-dest-repro.sh"
   
https://bugs.launchpad.net/bugs/2167649/+attachment/6000912/+files/bubblewrap-symlink-dest-repro.sh

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

Title:
  bubblewrap 0.9.0-1ubuntu0.2 (CVE-2026-87766): bind-mount destination
  mis-resolves relative symlinks with "..", breaks flatpak apps

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


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

Reply via email to