The runtime files directory was opened with open() using O_PATH but
without symlink protection, unlike the app files path which used
O_NOFOLLOW. Since "files" is validated as a non-symlink during deploy,
this is not exploitable through normal install flow. However, the open
should still use safe fd-relative operations as defense-in-depth.
Use flatpak_deploy_get_files_fd which validates the path with
glnx_chaseat(GLNX_CHASE_RESOLVE_NO_SYMLINKS), rejecting any symlink
at the directory boundary.
Hardening related to CVE-2026-97023, CVE-2026-97024
Helps: https://github.com/flatpak/flatpak/security/advisories/GHSA-5p67-xh8x-rq54
Helps: https://github.com/flatpak/flatpak/security/advisories/GHSA-8xgq-v545-vgvf
dir_is_locked() used g_file_resolve_relative_path to construct the
path to files/.ref, then open() without O_NOFOLLOW. Since "files" is
validated as a non-symlink during deploy and ".ref" is atomically
created as a regular file, this is not exploitable through normal
install flow. However, the function should still use safe fd-relative
operations as defense-in-depth.
Rename dir_is_locked to deploy_dir_is_locked to reflect that it
operates specifically on deploy directories, not arbitrary ones.
Hardening related to CVE-2026-97023, CVE-2026-97024
Helps: https://github.com/flatpak/flatpak/security/advisories/GHSA-5p67-xh8x-rq54
Helps: https://github.com/flatpak/flatpak/security/advisories/GHSA-8xgq-v545-vgvf
The runtime deploy path used GFile operations to manipulate files
inside files/etc (passwd, group, machine-id, resolv.conf). While
the "files" directory is validated with glnx_chaseat using
GLNX_CHASE_RESOLVE_NO_SYMLINKS, "etc" inside it is not checked.
A malicious runtime with files/etc as a symlink causes the GFile
operations (g_file_delete, g_file_replace_contents,
g_file_make_symbolic_link) to follow it and modify files at the
symlink target. On system installs (running as root), this modifies
arbitrary files — e.g. replacing /etc/resolv.conf.
This commit uses fd-based operations to prevent to prevent the symlink
attack.
Resolves: CVE-2026-97024
Resolves: https://github.com/flatpak/flatpak/security/advisories/GHSA-8xgq-v545-vgvf
The export directory cleanup during deploy used flatpak_rm_rf which
wraps glnx_shutil_rm_rf_at(AT_FDCWD, path). The kernel resolves
intermediate symlinks in the path, so a malicious ostree commit with
"export" as a symlink causes flatpak_rm_rf(export/bin) to delete files
at the symlink target. On system installs (running as root), this is
arbitrary file deletion.
This commit uses fd-based operations to prevent to prevent the symlink
attack.
Resolves: CVE-2026-97023
Resolves: https://github.com/flatpak/flatpak/security/advisories/GHSA-5p67-xh8x-rq54
Add deploy_open_fd, flatpak_deploy_get_files_fd,
flatpak_deploy_get_export_fd, and flatpak_deploy_get_metadata_fd which
open files within a deploy directory using fd-relative operations with
symlink protection.
deploy_open_fd uses a two-step resolution:
GLNX_CHASE_RESOLVE_NO_SYMLINKS at the directory boundary (files/,
export/) to reject symlinks, then GLNX_CHASE_RESOLVE_BENEATH within the
directory to safely resolve symlinks relative to the directory root.
These will be used by subsequent commits to close TOCTOU gaps where
GFile path operations were used after fd-based validation.
Prerequsite for fixing CVE-2026-97023, CVE-2026-97024
Helps: https://github.com/flatpak/flatpak/security/advisories/GHSA-5p67-xh8x-rq54
Helps: https://github.com/flatpak/flatpak/security/advisories/GHSA-8xgq-v545-vgvf
This prevents sandboxed processes from being able to kill processes
outside the sandbox with `kill (0, SIGNAL)`. The only process they can
kill like this will be the `bwrap` supervisor, which just terminates
the sandbox when killed.
Resolves: CVE-2026-97029
Resolves: https://github.com/flatpak/flatpak/security/advisories/GHSA-f3p8-vr7v-gxf2
Signed-off-by: Simon McVittie <smcv@collabora.com>
The document portal is mounted at /run/flatpak/doc inside the sandbox,
but forwarded arguments used its host mount path. With a nonstandard
host runtime directory, that path is inaccessible to the application.
Keep the host path local to mount setup and return the sandbox destination
to argument forwarding. Preserve NULL when the portal is unavailable.
Add real-portal regression tests for user and isolated system installs.
Check file read/write, escaped URIs, directories and passthrough controls.
Skip the directory subtest on portal interfaces older than version 4.
Applications using libflatpak currently have to duplicate the CLI's
private cleanup logic to offer the equivalent of uninstall --delete-data.
Add a standalone API that removes ~/.var/app data and resets permission
store entries without requiring the app to be installed. Keep it separate
from transactions so callers can retry partial failures or reset data for
an installed app.
Validate app IDs before constructing paths, propagate cancellation and
permission table errors, and document partial failure behavior.
Permission table discovery reads the on-disk database directory and does
not use the D-Bus permission store proxy. Remove the unused argument and
update callers.
Return the permission reset result directly after app data removal. This
keeps the success and error paths equivalent while removing an unnecessary
conditional.
Libflatpak needs to reuse user-data deletion and permission reset logic
that was previously private to the command-line builtins. This will let
software stores offer the equivalent of uninstall --delete-data.
Move each concern into a separate common module without changing behavior
so a public API can be added in a later commit. Name the user-data module
and its helper consistently here, and keep them distinct from the
existing appdata metadata code.
flatpak update --commit and flatpak remote-info read the download size
from xa.download-size in the commit metadata, which only covers the
ostree file objects and not extra-data. The summary cache path used by
a regular flatpak update does add extra-data sizes, so the two differed:
extra-data apps like com.jetbrains.Rider showed 1.3 MB instead of 1.6 GB.
Add flatpak_commit_add_extra_data_sizes() to sum the extra-data sizes
from a commit variant, and use it in resolve_op_from_commit() and
remote-info so they match the summary path. The existing
flatpak_repo_collect_extra_data_sizes() is changed to reuse it.
Fixes: https://github.com/flatpak/flatpak/issues/5947
The variables d, m, y are declared as 'int', but the format string
used '%u' which expects 'unsigned int *'. Change to '%d' to match
the actual argument type.
Detected by GCC -Wformat when building with warning_level=3.
BundleData retains explicit GPG key data with g_bytes_ref(), but its
cleanup treats the data as a GObject. This crashes transaction cleanup
when a bundle is installed with explicit key bytes.
Use g_clear_pointer() with g_bytes_unref() to release the retained data.
flatpak_context_to_args() built the D-Bus name options from
flatpak_policy_to_string(). That function gives the values used in the
[Session Bus Policy] and [System Bus Policy] metadata groups. Two of
them, "none" and "see", are not command-line options. A context that
contained such a policy gave --none-name= and --system-none-name=.
flatpak-run(1) writes these arguments to the [Instance] extra-args of
/.flatpak-info. flatpak-portal gives them back to flatpak(1) when a
sandboxed app calls flatpak-spawn(1). flatpak(1) then rejected the whole
command line with "Unknown option --none-name=...", so --no-talk-name
and --system-no-talk-name broke flatpak-spawn(1).
Map each policy to the option that sets it: --no-talk-name for
FLATPAK_POLICY_NONE, --talk-name for FLATPAK_POLICY_TALK, and --own-name
for FLATPAK_POLICY_OWN. FLATPAK_POLICY_SEE has no command-line option,
so emit nothing for it. It cannot occur here: the only caller serializes
a context that comes from the command line.
While I'm changing the translatable string anyway, this also
incorporates a suggestion from #6753 to quote the invalid character, so
that output is clearer in the case where the invalid character is
whitespace.
Thanks: Christian Stadelmann
Signed-off-by: Simon McVittie <smcv@collabora.com>
Until now we have been using `%c` to show invalid characters, but in
general that will corrupt our output if the input is non-ASCII,
because the individual bytes of a UTF-8 string are not valid UTF-8 alone.
Signed-off-by: Simon McVittie <smcv@collabora.com>
It is not a meson project, but we can use the patch_directory key to
overlay a meson.build file over the git checkout. It uses
meson.override_find_program so that in flatpak, a call to
find_program('variant-schema-compiler') will find the program.
Reject summaries, subsummaries, and summary indexes that are not in
GVariant normal form before passing them to the generated variant
accessor framework, which performs direct pointer arithmetic without
structural validation.
We require glib 2.46, so we can't rely on g_hash_table_new_similar.
Fixes: 17cb1135 ("context: Keep fallback-x11 separate from x11 conditionals")
Closes: #6775
On architectures like i386, socket operations were historically
multiplexed through the socketcall syscall. The seccomp socket family
filter only applied to the direct socket syscall, so a binary using
socketcall could bypass it entirely.
Switch from seccomp_rule_add_exact to seccomp_rule_add, which lets
libseccomp also block socketcall. Since libseccomp cannot inspect
socketcall arguments (they are behind a userspace pointer), this
blocks all of socketcall, forcing userspace to use the direct socket
syscalls that have been available on i386 since Linux 4.3.
apply_extra_data() used GFile path-based operations that follow
symlinks: --ro-bind/--bind with resolved paths, chmod on the extra
directory path, and flatpak_cp_a for the extra/export merge.
These are not independently exploitable: apply_extra_data only runs
after extract_extra_data has already created files/extra as a real
directory, so there is no symlink left to follow. The apply_extra
script itself runs in a restricted sandbox with dropped caps and no
/proc. The extra/export merge only adds to the app's own export
directory, which is already app-controlled and whose desktop file
Exec keys are rewritten to flatpak run.
Replace with fd-relative operations as defense in depth:
glnx_chaseat with GLNX_CHASE_RESOLVE_NO_SYMLINKS and
GLNX_CHASE_RESOLVE_BENEATH for directory traversal,
--ro-bind-fd/--bind-fd for bwrap mounts, fchmod on the directory fd,
and flatpak_cp_a_at for the export merge.
Helps: https://github.com/flatpak/flatpak/security/advisories/GHSA-fqx6-vh4p-42cg
[smcv: Use glnx_fd_reopen() to reopen O_PATH fd as readable]
Co-authored-by: Simon McVittie <smcv@collabora.com>
extract_extra_data() had two vulnerabilities:
1. It resolved "files/extra" using g_file_resolve_relative_path()
which follows symlinks. A crafted OSTree commit with "files" as a
symlink causes extra-data blobs to be written at the symlink target.
On system installs this runs as root via the system helper, which
validates signatures and checksums but not tree structure.
2. It used g_file_get_child(extradir, name) where name comes from
xa.extra-data-sources in the commit metadata. Names containing ".."
escape the extra/ directory. This is exploitable through the normal
build flow: flatpak build-export rejects "/" but not "..".
Replace GFile path operations with fd-relative operations: open
"files" with glnx_chaseat using GLNX_CHASE_RESOLVE_NO_SYMLINKS,
create "extra" with glnx_chase_and_mkdirat using
GLNX_CHASE_RESOLVE_BENEATH, validate extra-data names against ".",
"..", and "/", and write with glnx_file_replace_contents_at anchored
to the extra directory fd.
[smcv: Open checkoutdir_dfd before trying to open its files subdir]
Co-authored-by: Simon McVittie <smcv@collabora.com>
Resolves: https://github.com/flatpak/flatpak/security/advisories/GHSA-fqx6-vh4p-42cg
Reject extra-data names containing ".", "..", or "/" early during the
download phase. The name is used to construct a local cache file path
via flatpak_build_file() which uses g_file_resolve_relative_path(),
so ".." components could traverse outside the cache directory.
In practice this is not exploitable: the local cache path is only
used for a g_file_query_exists() check followed by g_file_load_contents(),
and the loaded content is verified against the expected sha256 from
the commit metadata.
Helps: https://github.com/flatpak/flatpak/security/advisories/GHSA-fqx6-vh4p-42cg
We have two use cases for removing refs: uninstalling, and pruning of
undeployed refs. Pruning undeployed refs is something we want anyone to
be able to do, because they can also pull updates and then not deploy
them. Uninstalling arbitrary refs on the other hand is problematic, and
its possible to remove the AppStream ref, and a deployed ref.
So we split removing a ref into a function which removes any ref, and
use it internally to implement e.g. uninstalling, and a function to
remove refs which are safe to remove. Only the latter one will escalate
through the system helper, making it harder for unprivileged users to
get into a state which can be exploited.
See the previous commit for such a state.
Resolves: https://github.com/flatpak/flatpak/security/advisories/GHSA-q4gr-vc25-57m5
Hardlink targets were not rebased to the destination directory,
allowing a crafted archive to hardlink arbitrary host files into the
extraction directory.
Also improve the documentation on how this all works, because it is all
a bit subtle.
Resolves: https://github.com/flatpak/flatpak/security/advisories/GHSA-9rww-v4mm-x4jg
Subpaths passed via D-Bus to the system helper are not validated, so
a value containing ".." components is accepted.
The only reason why this isn't exploitable is because we resolve the
path relative to `root` via g_file_resolve_relative_path, where root is
a OstreeRepoFile which will return FALSE when it encounters ".." or
symlinks.
Harden the code by using glnx_chase_and_mkdirat with RESOLVE_BENEATH to
create parent directories, and check out into the resulting fd.
The paths up to files/ are not attacker-controlled, and
g_file_replace_contents with G_FILE_CREATE_REPLACE_DESTINATION already
replaces symlinks rather than following them, so this is not a security
fix. The only reason why is that the file is in the root of the attacker
controlled directory.
This is a bit subtle, so lets do the right thing and concistently use
fd-relative operations when doing anything inside attacker/app
controlled directories.
Helps: https://github.com/flatpak/flatpak/security/advisories/GHSA-w69g-9x8j-7p8f
Extension content is controlled by the extension developer. When setting
up the sandbox, Flatpak accesses the .ref file and iterates merge_dirs
within the extension's files directory on the host using path-based
operations that follow symlinks. A malicious extension can place symlinks
that escape the extension directory, causing Flatpak's host process to
access arbitrary host paths. This discloses host directory listings to
the sandboxed application via the resulting merge symlinks.
Use glnx_chaseat with GLNX_CHASE_RESOLVE_BENEATH to confine path
resolution to the extension's files directory.
Resolves: https://github.com/flatpak/flatpak/security/advisories/GHSA-w69g-9x8j-7p8f
Validate extension directory, subdir_suffix, add_ld_path, and
merge_dirs at parse time, rejecting absolute paths and paths with
.. components that escape the intended mount point. This prevents
extension metadata from mounting content at unintended locations
inside the sandbox.
Helps: https://github.com/flatpak/flatpak/security/advisories/GHSA-w69g-9x8j-7p8f
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
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
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.