CVE-2022-21682 (C, published 2022-01-13T21:15Z)
Description: value: Flatpak is a Linux application sandboxing and distribution framework. A path traversal vulnerability affects versions of Flatpak prior to 1.12.3 and 1.10.6. flatpak-builder applies `finish-args` last in the build. At this point the build directory will have the full access that is specified in the manifest, so running `flatpak build` against it will gain those permissions. Normally this will not be done, so this is not problem. However, if `--mirror-screenshots-url` is specified, then flatpak-builder will launch `flatpak build --nofilesystem=host appstream-utils mirror-screenshots` after finalization, which can lead to issues even with the `--nofilesystem=host` protection. In normal use, the only issue is that these empty directories can be created wherever the user has write permissions. However, a malicious application could replace the `appstream-util` binary and potentially do something more hostile. This has been resolved in Flatpak 1.12.3 and 1.10.6 by changing the behaviour of `--nofilesystem=home` and `--nofilesystem=host`.
Severity: MEDIUM (CVSS v3 base score: 6.5)
Weakness: CWE-22 \u2014 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
Repository: https://github.com/flatpak/flatpak
Files changed:
common/flatpak-context.c
Commit message: Make --nofilesystem=host/home remove access to subdirs of those

Previously --nofilesystem=host only removed specifically access to the
`host` permissions, and not necessarily other filesystems (like `home`
or `/some/path`). This isn't very useful to limit access because you
don't know what other filesystems the app may have access too.

We change this to mean that `--nofilesystem=host` removes *all* filesystem
access from the parent layer, and `--nofilesystem=home` removes all
file access to the homedir and paths inside it.

The available layers are, in order:

 * app permissions
 * overrides
 * commandline args

This allows you to start from scratch with the filesystem permissions
in the overrides or the commandline. This is a small change in
behaviour, but not a lot of things use --nofilesystem, and the ones
that do probably expects this behaviour.


Vulnerable code:

Fixed code:
/* Note: This only works with valid keys, i.e. they passed flatpak_context_parse_filesystem */
static gboolean
flatpak_filesystem_key_in_home (const char *filesystem)
{
  /* "home" is definitely in home */
  if (strcmp (filesystem, "home") == 0)
    return TRUE;

  /* All the other special fs:es are non-home.
   * Note: This considers absolute paths that are in the homedir as non-home.
   */
  if (g_strv_contains (flatpak_context_special_filesystems, filesystem) ||
      g_str_has_prefix (filesystem, "/"))
    return FALSE;

  /* Files in xdg-run are not in home */
  if (g_str_has_prefix (filesystem, "xdg-run"))
    return FALSE;

  /* All remaining keys (~/, xdg-data, etc) are considered in home,
   * Note: technically $XDG_HOME_DATA could point outside the homedir, but we ignore that.
   */
  return TRUE;
}

  gboolean no_home = FALSE;
  gboolean no_host = FALSE;
  /* We first handle all negative home and host as they override other
     keys than themselves from the parent */
  if (g_hash_table_lookup_extended (other->filesystems,
                                    "host",
                                    NULL, &value))
    {
      FlatpakFilesystemMode host_mode = GPOINTER_TO_INT (value);
      if (host_mode == FLATPAK_FILESYSTEM_MODE_NONE)
        no_host = TRUE;
    }

  if (g_hash_table_lookup_extended (other->filesystems,
                                    "home",
                                    NULL, &value))
    {
      FlatpakFilesystemMode home_mode = GPOINTER_TO_INT (value);
      if (home_mode == FLATPAK_FILESYSTEM_MODE_NONE)
        no_home = TRUE;
    }

  if (no_host)
    {
      g_hash_table_remove_all (context->filesystems);
    }
  else if (no_home)
    {
      g_hash_table_iter_init (&iter, context->filesystems);
      while (g_hash_table_iter_next (&iter, &key, &value))
        {
          if (flatpak_filesystem_key_in_home ((const char *)key))
            g_hash_table_iter_remove (&iter);
        }
    }

  /* Then set the new ones, which includes propagating the nohost and nohome ones. */