Use glnx_chaseat to ensure that all the attacker-controlled paths end up
inside the basefd directory, and then AT_SYMLINK_NOFOLLOW to make sure
that the last path component won't escape from the basefd.
On kernels >= 6.6 we can now use fchmodat() with AT_SYMLINK_NOFOLLOW,
but on older kernels that didn't work, so if necessary fall back to
opening the file with O_NOFOLLOW and then calling fchmod() on it.
Because this is the last syscall that used the previous (flawed)
validation mechanism, we can now remove the validation helpers and be
sure that everything is using the glnx-chaseat()-based replacements.
[smcv: Separated from a larger commit for better reviewability]
Co-authored-by: Simon McVittie <smcv@collabora.com>
Resolves: https://github.com/flatpak/flatpak/security/advisories/GHSA-qrwq-7qwx-q9rp
Use glnx_chaseat to ensure that the attacker-controlled symlink name
ends up inside the basefd directory. Note that the symlink *target* is
also attacker-controlled, but it's OK for them to be able to set any
target of their choice: that can't immediately cause traversal outside
the base directory.
[smcv: Separated from a larger commit for better reviewability]
Co-authored-by: Simon McVittie <smcv@collabora.com>
Helps: https://github.com/flatpak/flatpak/security/advisories/GHSA-qrwq-7qwx-q9rp
Again, use glnx_chaseat to ensure that all the attacker-controlled paths
end up inside the basefd directory. These two syscalls are a bit more
complicated, and take two paths.
[smcv: Separated from a larger commit for better reviewability]
Co-authored-by: Simon McVittie <smcv@collabora.com>
Helps: https://github.com/flatpak/flatpak/security/advisories/GHSA-qrwq-7qwx-q9rp
Use glnx_chaseat to ensure that all the attacker-controlled paths end up
inside the basefd directory.
This requires some new helper functions, which will be used in more
complicated syscalls' implementations in subsequent commits.
[smcv: Separated from a larger commit for better reviewability]
Co-authored-by: Simon McVittie <smcv@collabora.com>
Helps: https://github.com/flatpak/flatpak/security/advisories/GHSA-qrwq-7qwx-q9rp
We pass them on to internal functions which assume that they are valid,
and specifically also create paths which contain those strings which can
be used for path traversal attacks.
Let's simply consistently validate all of those arguments.
Resolves: https://github.com/flatpak/flatpak/security/advisories/GHSA-v2gw-v9h5-9q4x
These had the *INTERFACE*.*METHOD* where the bus name should have been,
and a blank interface/method (meaning match any interface/method).
Because there's no bus name of that name on the AT-SPI bus, the only reason
why Flatpak apps were able to receive these broadcasts is that there was
a vulnerability in xdg-dbus-proxy, tracked as GHSA-r7hp-698j-2h6c. To
avoid regressions in Flatpak when the x-d-p vulnerability is fixed,
we need to correct these rules to have the intended bus name.
Signed-off-by: Simon McVittie <smcv@collabora.com>
Helps: https://github.com/flatpak/xdg-dbus-proxy/security/advisories/GHSA-r7hp-698j-2h6c
The previous commit ensures that there isn't a heap overflow when
reading a huge delta path, but we should also just reject unreasonably
long paths. So we chose the arbitrary limit of PATH_MAX and assume that
anything beyond that arbitrary limit is probably abusive.
Helps: https://github.com/flatpak/flatpak/security/advisories/GHSA-jr92-2v97-wgvc
delta_read_data computed g_malloc(size + 1) where size came from the
delta stream. If size equals G_MAXSIZE, size + 1 wraps to zero and
g_malloc returns a minimal allocation, then g_input_stream_read_all
writes size bytes into it — a heap buffer overflow.
Resolves: https://github.com/flatpak/flatpak/security/advisories/GHSA-jr92-2v97-wgvc
The delta varint parser decoded into guint64 values which were then
passed to GLib I/O and allocation functions that take gsize. On 32-bit
systems where gsize is 32 bits this silently truncated the values.
Change the varint output and all delta operation size parameters to
gsize, and clamp the parsed value to G_MAXSIZE.
Resolves: https://github.com/flatpak/flatpak/security/advisories/GHSA-jr92-2v97-wgvc
The original reporter used various tricks to find a way for the sandboxed
app to overwrite these locations with symlinks, but for the purposes
of this test, I'm doing the setup outside the sandbox instead: probably
not all of these potential exploit routes are actually possible, but we
defend against all of them symmetrically.
Signed-off-by: Simon McVittie <smcv@collabora.com>
Replace path-based flatpak_mkdir_p calls in flatpak_ensure_data_dir
with glnx_chase_and_mkdirat(RESOLVE_NO_SYMLINKS) to prevent an app
from replacing subdirectories of its data dir with symlinks between
runs and having them followed during the next sandbox setup.
In flatpak_run_setup_base_argv, replace path-based --bind args for
the app cache/data/config/tmp directories with --bind-fd using fds
obtained via glnx_chaseat(RESOLVE_NO_SYMLINKS), preventing both
symlink following and TOCTOU races when setting up these bind mounts.
Assisted-by: Claude:opus-4.6
Resolves: https://github.com/flatpak/flatpak/security/advisories/GHSA-8688-9x26-hhxj
This use of symlinks to ensure that the canonicalized paths of
`$XDG_CACHE_HOME`, `$XDG_CONFIG_HOME`, `$XDG_DATA_HOME` are
`~/.cache`, `~/.config`, `~/.local/share` is the sort of thing that
could easily regress if not tested.
Signed-off-by: Simon McVittie <smcv@collabora.com>
A sandboxed app can replace ~/.var/app/$appid/.ld.so with a symlink,
causing regenerate_ld_cache to write files at an arbitrary location.
A concurrent app instance makes this a TOCTOU even after the initial
directory verification.
Replace all path-based operations with fd-based equivalents using
ld_so_dir_fd obtained via glnx_chase_and_mkdirat, and pass the
directory to bwrap via --bind-fd instead of --bind.
Assisted-by: Claude:opus-4.6
Resolves: https://github.com/flatpak/flatpak/security/advisories/GHSA-99wv-m8rp-g58x
This reverts commit 420ce91428.
Apparently we do depend on the session-set certificates in some
situations. We should fix that, but until someone puts in the effort to
do so, reverting this will at least unbreak things.
systemd-tmpfiles can be configured to periodically cleans /run/user,
which can remove the session helper's p11-kit socket. Once removed, all
subsequent Flatpak launches fail with "Can't find source path" until the
session helper restarts.
Take a shared flock on the .flatpak-helper directory for the lifetime
of the process. systemd-tmpfiles --clean skips directories that are
locked.
Helps: https://github.com/flatpak/flatpak/issues/6341
`dnf builddep flatpak` only installs `ostree-devel` and `ostree-libs`.
The standalone `/usr/bin/ostree` binary was trimmed out in 2017. Add `ostree` explicitly to `CONTRIBUTING.md`.
The commit metadata and ref validation checks in validate_commit_metadata()
and flatpak_dir_deploy() used G_IO_ERROR which gets downgraded to a generic
G_DBUS_ERROR_FAILED when crossing the system helper D-Bus boundary.
Use FLATPAK_ERROR_PERMISSION_DENIED so the error is preserved across D-Bus.
Every other access to index->manifests in the codebase checks for NULL
before dereferencing, but flatpak_image_collection_new did not. Add the
same guard to avoid a NULL pointer dereference if the OCI index has no
manifests array.
Instead of just blindly accepting any characters to make up the docker
registry domain, reject invalid domains (including ones which contain
e.g. '@', '#', and '?').
flatpak_docker_reference_parse() asserts that the regex always matches,
but inputs containing newlines cause the match to fail since the regex
is not compiled with G_REGEX_DOTALL. Return an error instead.
flatpak_permission_adds_permissions() had two bugs in its sorted-array
merge walk for comparing conditional permissions:
The function returned FALSE when a new conditional was not present in
the old set, which is the opposite of correct — a new conditional means
the permission can be granted under conditions it previously could not.
The loop also relied on reading a NULL sentinel past the end of the
GPtrArray, which is not NULL-terminated, causing an out-of-bounds read.
Replace with proper bounds-checked iteration that correctly detects new
conditionals as permission additions.
The close function would bail out on the first child stream close
failure, skipping the remaining children. Close all children and
propagate the first error.
The metadata, appstream, icon_64, and icon_128 fields are conditionally
initialized in flatpak_bundle_ref_new() depending on which keys exist in
the bundle metadata. The finalize function used g_bytes_unref() which is
not NULL-safe on older GLib versions.
The appdata XML parser uses g_assert() to validate parser state in
several places. Since the XML comes from the app's deploy directory and
is controlled by the package author, malformed XML triggers abort().
Replace all g_assert() calls with graceful handling: early returns when
there is no current component, NULL checks for content_rating, and
state resets for accumulated text and lang.
flatpak_oci_registry_mirror_blob uses self->token (destination registry)
instead of source_registry->token when downloading from the source. All
other parameters on the same call correctly use source_registry.
In practice the destination is always a local on-disk registry with no
token set, so this results in missing authentication when pulling from
authenticated source registries rather than a credential leak.
handle_remove_local_ref validates the remote name but passes the ref
string directly to flatpak_dir_remove_ref without validation. Since the
polkit action for this method is modify-repo (allow_active=yes), any
active session user can delete arbitrary ostree refs in the system repo
without authentication.
All legitimate callers of RemoveLocalRef pass standard flatpak refs
(app/runtime). Non-standard refs like appstream/, appstream2/, and
ostree-metadata are managed through their own dedicated D-Bus methods
(DeployAppstream, UpdateRemote, ConfigureRemote) and never go through
RemoveLocalRef.
Validate the ref with flatpak_decomposed_new_from_ref() to restrict
removal to valid flatpak refs.
The Deploy authorization handler decides between app-install (requires
admin auth) and app-update (no auth needed) by checking whether the ref
is currently installed. The deploy handler then independently checks the
deployed state to decide whether to install or update.
Record the authorization decision on the invocation and verify in the
deploy handler that the operation matches what was authorized.
The --assumeyes (-y) option was setting both the CLI-level
disable_interaction flag and the library-level no_interaction flag to
TRUE. This caused -y to suppress not just confirmation prompts, but
also credential prompts (basic auth, webflow), polkit authorization
dialogs, and parental control consent -- even though -y is documented
as "automatically answer yes to all questions".
Rename disable_interaction to assume_yes to clarify its purpose: it
auto-answers yes/no confirmations and picks default choices. Stop
calling flatpak_transaction_set_no_interaction() from the CLI
transaction constructor, so the library-level no_interaction flag is
only set by --noninteractive (which uses FlatpakQuietTransaction).
Remove the assume_yes guard from basic_auth_start so credential
prompts are always shown when the CLI transaction is in use.
Assisted-by: Cursor
If flatpak is built with code coverage enabled, libgcov sometimes
helpfully emits messages in the output from programs under test.
If we’re strictly comparing the whole output of a program to an expected
string, as `test-history.sh` does in these two places, this can cause
spurious test failures.
Temporarily tell it to send its error messages to `/dev/null` as we
don’t care about them for those tests.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Downgrading an app or runtime previously failed outright for non root
users calling through the system helper, with an error stating that
updating to a specific commit requires root permissions.
Instead, allow downgrades through the system helper by introducing a new
flag that is set when the caller requests a downgrade.
New "org.freedesktop.Flatpak.app-downgrade" and "runtime-downgrade"
polkit actions are added that require auth_admin_keep for active users.
Instead of modifying the host-like run environment to clear the sandbox
environment, we'll use the new --clear-env flag which does the correct
thing.
Assisted-by: Claude:opus-4.6
Closes: #5271
This reverts commit a57f6bc372.
The run-environ from the calling instance is a host-like environment
(e.g. on NixOS it contains /nix/store paths). Passing it via --env
injects it into the sandbox payload environment where those paths don't
exist.
Revert the commit, so we pass run-environ as the envp for spawning
flatpak run again to let it make host-level decisions (DISPLAY,
FLATPAK_GL_DRIVERS, XDG_RUNTIME_DIR, etc.) without leaking into the
sandbox.
It also passes --clear-env unconditionally, because we'd build up the
environment, but the wrong one. We will implement --clear-env properly
again in the next few commits.
Closes: #6717
Fixes: a57f6bc3 ("portal: Clear the environment via flatpak arguments")
When bundle metadata validation fails after commit, the ref cleanup
via ostree_repo_set_ref_immediate could set error, then
flatpak_fail_error would try to set it again. Pass NULL for the
cleanup call since it's best-effort.
Handle NULL from g_key_file_get_string when a desktop file has no
Icon key, and from flatpak_dir_get_origin when deploy metadata is
missing or corrupted.