From 116a8b848788c582fb2c8577f1250438b100da25 Mon Sep 17 00:00:00 2001
From: Alexander Larsson <alexl@redhat.com>
Date: Tue, 17 Mar 2020 14:13:14 +0100
Subject: [PATCH] transaction: Ensure the metadata in the pulled commit matches
 what we resolved

We're using the metadata from the summary, ostree-metadata or available
commit when making security sensitive decisions, so lets verify this
matches what we get in the actual commit we pulled.

We already did check that this then actually also matches what gets deployed,
so the new check shares code with that.

Note, we don't do this for OCI installs, because it seems the current
fedora flatpaks don't have this set, and we don't want to break
existing remotes.

Backported by Mike Gorse <mgorse@suse.com>; related to CVE-2021-43860.
---
diff -urp flatpak-1.2.3.orig/common/flatpak-dir.c flatpak-1.2.3/common/flatpak-dir.c
--- flatpak-1.2.3.orig/common/flatpak-dir.c	2022-09-01 10:19:42.964862285 -0500
+++ flatpak-1.2.3/common/flatpak-dir.c	2022-09-01 10:29:16.005473716 -0500
@@ -999,6 +999,32 @@ flatpak_get_user_base_dir_location (void
   return g_object_ref ((GFile *) file);
 }
 
+static gboolean
+validate_commit_metadata (GVariant   *commit_data,
+                          const char *ref,
+                          const char *required_metadata,
+                          gboolean   require_xa_metadata,
+                          GError   **error)
+{
+  g_autoptr(GVariant) commit_metadata = NULL;
+  const char *xa_metadata = NULL;
+
+  commit_metadata = g_variant_get_child_value (commit_data, 0);
+
+  if (commit_metadata != NULL)
+    g_variant_lookup (commit_metadata, "xa.metadata", "&s", &xa_metadata);
+
+  if ((xa_metadata == NULL && require_xa_metadata) ||
+      (xa_metadata != NULL && g_strcmp0 (required_metadata, xa_metadata) != 0))
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+                   _("Commit metadata for %s not matching expected metadata"), ref);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
 /* This is a cache directory similar to ~/.cache/flatpak/system-cache,
  * but in /var/tmp. This is useful for things like the system child
  * repos, because it is more likely to be on the same filesystem as
@@ -3691,12 +3717,12 @@ flatpak_dir_update_appstream (FlatpakDir
           /* No need to use an existing OstreeRepoFinderResult array, since
            * appstream updates do not need to be atomic wrt other updates. */
           used_branch = new_branch;
-          if (!flatpak_dir_pull (self, state, used_branch, NULL, NULL, NULL,
+          if (!flatpak_dir_pull (self, state, used_branch, NULL, NULL, NULL, NULL,
                                  child_repo, FLATPAK_PULL_FLAGS_NONE, OSTREE_REPO_PULL_FLAGS_MIRROR,
                                  progress, cancellable, &first_error))
             {
               used_branch = old_branch;
-              if (!flatpak_dir_pull (self, state, used_branch, NULL, NULL, NULL,
+              if (!flatpak_dir_pull (self, state, used_branch, NULL, NULL, NULL, NULL,
                                      child_repo, FLATPAK_PULL_FLAGS_NONE, OSTREE_REPO_PULL_FLAGS_MIRROR,
                                      progress, cancellable, &second_error))
                 {
@@ -3749,12 +3775,12 @@ flatpak_dir_update_appstream (FlatpakDir
   /* No need to use an existing OstreeRepoFinderResult array, since
    * appstream updates do not need to be atomic wrt other updates. */
   used_branch = new_branch;
-  if (!flatpak_dir_pull (self, state, used_branch, NULL, NULL, NULL, NULL,
+  if (!flatpak_dir_pull (self, state, used_branch, NULL, NULL, NULL, NULL, NULL,
                          FLATPAK_PULL_FLAGS_NONE, OSTREE_REPO_PULL_FLAGS_NONE, progress,
                          cancellable, &first_error))
     {
       used_branch = old_branch;
-      if (!flatpak_dir_pull (self, state, used_branch, NULL, NULL, NULL, NULL,
+      if (!flatpak_dir_pull (self, state, used_branch, NULL, NULL, NULL, NULL, NULL,
                              FLATPAK_PULL_FLAGS_NONE, OSTREE_REPO_PULL_FLAGS_NONE, progress,
                              cancellable, &second_error))
         {
@@ -4597,6 +4623,7 @@ flatpak_dir_pull (FlatpakDir
                   const char                           *opt_rev,
                   const OstreeRepoFinderResult * const *opt_results,
                   const char                          **subpaths,
+                  GBytes                               *require_metadata,
                   OstreeRepo                           *repo,
                   FlatpakPullFlags                      flatpak_flags,
                   OstreeRepoPullFlags                   flags,
@@ -4775,6 +4802,14 @@ flatpak_dir_pull (FlatpakDir
       goto out;
     }
 
+  if (require_metadata)
+    {
+      g_autoptr(GVariant) commit_data = NULL;
+      if (!ostree_repo_load_commit (repo, rev, &commit_data, NULL, error) ||
+          !validate_commit_metadata (commit_data, ref, (const char *)g_bytes_get_data (require_metadata, NULL), TRUE, error))
+        return FALSE;
+    }
+
   if (!flatpak_dir_pull_extra_data (self, repo,
                                     state->remote_name,
                                     ref, rev,
@@ -6907,7 +6942,6 @@ flatpak_dir_deploy (FlatpakDir
   glnx_autofd int checkoutdir_dfd = -1;
   g_autoptr(GFile) tmp_dir_template = NULL;
   g_autofree char *tmp_dir_path = NULL;
-  const char *xa_metadata = NULL;
   const char *xa_ref = NULL;
   g_autofree char *checkout_basename = NULL;
   gboolean created_extra_data = FALSE;
@@ -6917,6 +6951,7 @@ flatpak_dir_deploy (FlatpakDir
   g_autofree char *metadata_contents = NULL;
   g_auto(GStrv) ref_parts = NULL;
   gboolean is_app;
+  gboolean is_oci;
 
   if (!flatpak_dir_ensure_repo (self, cancellable, error))
     return FALSE;
@@ -7172,19 +7207,15 @@ flatpak_dir_deploy (FlatpakDir
     }
 
   /* Check the metadata in the commit to make sure it matches the actual
-     deployed metadata, in case we relied on the one in the commit for
-     a decision */
-  g_variant_lookup (commit_metadata, "xa.metadata", "&s", &xa_metadata);
-  if (xa_metadata != NULL)
-    {
-      if (g_strcmp0 (metadata_contents, xa_metadata) != 0)
-        {
-          g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
-                       _("Deployed metadata does not match commit"));
-          return FALSE;
-        }
-    }
-
+   * deployed metadata, in case we relied on the one in the commit for
+   * a decision
+   * Note: For historical reason we don't enforce commits to contain xa.metadata
+   * since this was lacking in fedora builds.
+   */
+  is_oci = flatpak_dir_get_remote_oci (self, origin);
+  if (!validate_commit_metadata (commit_data, ref, metadata_contents, !is_oci, error))
+    return FALSE;
+ 
   dotref = g_file_resolve_relative_path (checkoutdir, "files/.ref");
   if (!g_file_replace_contents (dotref, "", 0, NULL, FALSE,
                                 G_FILE_CREATE_REPLACE_DESTINATION, NULL, cancellable, error))
@@ -7721,6 +7752,7 @@ flatpak_dir_install (FlatpakDir
                      const char          *ref,
                      const char          *opt_commit,
                      const char         **opt_subpaths,
+                     GBytes              *require_metadata,
                      OstreeAsyncProgress *progress,
                      GCancellable        *cancellable,
                      GError             **error)
@@ -7813,7 +7845,7 @@ flatpak_dir_install (FlatpakDir
 
           flatpak_flags |= FLATPAK_PULL_FLAGS_SIDELOAD_EXTRA_DATA;
 
-          if (!flatpak_dir_pull (self, state, ref, opt_commit, NULL, subpaths,
+          if (!flatpak_dir_pull (self, state, ref, opt_commit, NULL, subpaths, require_metadata,
                                  child_repo,
                                  flatpak_flags,
                                  OSTREE_REPO_PULL_FLAGS_MIRROR,
@@ -7854,7 +7886,7 @@ flatpak_dir_install (FlatpakDir
 
   if (!no_pull)
     {
-      if (!flatpak_dir_pull (self, state, ref, opt_commit, NULL, opt_subpaths, NULL,
+      if (!flatpak_dir_pull (self, state, ref, opt_commit, NULL, opt_subpaths, require_metadata, NULL,
                              flatpak_flags, OSTREE_REPO_PULL_FLAGS_NONE,
                              progress, cancellable, error))
         return FALSE;
@@ -8293,6 +8325,7 @@ flatpak_dir_update (FlatpakDir
                     const char                           *commit,
                     const OstreeRepoFinderResult * const *results,
                     const char                          **opt_subpaths,
+                    GBytes                               *require_metadata,
                     OstreeAsyncProgress                  *progress,
                     GCancellable                         *cancellable,
                     GError                              **error)
@@ -8413,7 +8446,7 @@ flatpak_dir_update (FlatpakDir
             return FALSE;
 
           flatpak_flags |= FLATPAK_PULL_FLAGS_SIDELOAD_EXTRA_DATA;
-          if (!flatpak_dir_pull (self, state, ref, commit, results, subpaths,
+          if (!flatpak_dir_pull (self, state, ref, commit, results, subpaths, require_metadata,
                                  child_repo,
                                  flatpak_flags, OSTREE_REPO_PULL_FLAGS_MIRROR,
                                  progress, cancellable, error))
@@ -8451,7 +8484,7 @@ flatpak_dir_update (FlatpakDir
 
   if (!no_pull)
     {
-      if (!flatpak_dir_pull (self, state, ref, commit, results, subpaths,
+      if (!flatpak_dir_pull (self, state, ref, commit, results, subpaths, require_metadata,
                              NULL, flatpak_flags, OSTREE_REPO_PULL_FLAGS_NONE,
                              progress, cancellable, error))
         return FALSE;
@@ -11951,7 +11984,7 @@ _flatpak_dir_fetch_remote_state_metadata
           if (child_repo == NULL)
             return FALSE;
 
-          if (!flatpak_dir_pull (self, state, OSTREE_REPO_METADATA_REF, NULL, NULL, NULL,
+          if (!flatpak_dir_pull (self, state, OSTREE_REPO_METADATA_REF, NULL, NULL, NULL, NULL,
                                  child_repo,
                                  flatpak_flags,
                                  OSTREE_REPO_PULL_FLAGS_MIRROR,
@@ -11981,7 +12014,7 @@ _flatpak_dir_fetch_remote_state_metadata
       return TRUE;
     }
 
-  if (!flatpak_dir_pull (self, state, OSTREE_REPO_METADATA_REF, NULL, NULL, NULL, NULL,
+  if (!flatpak_dir_pull (self, state, OSTREE_REPO_METADATA_REF, NULL, NULL, NULL, NULL, NULL,
                          flatpak_flags, OSTREE_REPO_PULL_FLAGS_NONE,
                          progress, cancellable, error))
     return FALSE;
diff -urp flatpak-1.2.3.orig/common/flatpak-dir-private.h flatpak-1.2.3/common/flatpak-dir-private.h
--- flatpak-1.2.3.orig/common/flatpak-dir-private.h	2022-09-01 10:19:42.964862285 -0500
+++ flatpak-1.2.3/common/flatpak-dir-private.h	2022-09-01 10:19:55.160970272 -0500
@@ -511,6 +511,7 @@ gboolean    flatpak_dir_pull (FlatpakDir
                               const char                           *opt_rev,
                               const OstreeRepoFinderResult * const *results,
                               const char                          **subpaths,
+                              GBytes                               *require_metadata,
                               OstreeRepo                           *repo,
                               FlatpakPullFlags                      flatpak_flags,
                               OstreeRepoPullFlags                   flags,
@@ -612,6 +613,7 @@ gboolean   flatpak_dir_install (FlatpakD
                                 const char          *ref,
                                 const char          *opt_commit,
                                 const char         **subpaths,
+                                GBytes              *require_metadata,
                                 OstreeAsyncProgress *progress,
                                 GCancellable        *cancellable,
                                 GError             **error);
@@ -656,6 +658,7 @@ gboolean   flatpak_dir_update (FlatpakDi
                                const char                           *checksum_or_latest,
                                const OstreeRepoFinderResult * const *results,
                                const char                          **opt_subpaths,
+                               GBytes                               *require_metadata,
                                OstreeAsyncProgress                  *progress,
                                GCancellable                         *cancellable,
                                GError                              **error);
diff -urp flatpak-1.2.3.orig/common/flatpak-installation.c flatpak-1.2.3/common/flatpak-installation.c
--- flatpak-1.2.3.orig/common/flatpak-installation.c	2022-09-01 10:19:42.968862320 -0500
+++ flatpak-1.2.3/common/flatpak-installation.c	2022-09-01 10:19:55.164970309 -0500
@@ -1914,7 +1914,7 @@ flatpak_installation_install_full (Flatp
                             (flags & FLATPAK_INSTALL_FLAGS_NO_DEPLOY) != 0,
                             (flags & FLATPAK_INSTALL_FLAGS_NO_STATIC_DELTAS) != 0,
                             FALSE, FALSE, state,
-                            ref, NULL, (const char **) subpaths,
+                            ref, NULL, (const char **) subpaths, NULL,
                             ostree_progress, cancellable, error))
     goto out;
 
@@ -2087,7 +2087,7 @@ flatpak_installation_update_full (Flatpa
                            FALSE, FALSE, FALSE, state,
                            ref, target_commit,
                            (const OstreeRepoFinderResult * const *) check_results,
-                           (const char **) subpaths,
+                           (const char **) subpaths, NULL,
                            ostree_progress, cancellable, error))
     goto out;
 
diff -urp flatpak-1.2.3.orig/common/flatpak-transaction.c flatpak-1.2.3/common/flatpak-transaction.c
--- flatpak-1.2.3.orig/common/flatpak-transaction.c	2022-09-01 10:19:42.968862320 -0500
+++ flatpak-1.2.3/common/flatpak-transaction.c	2022-09-01 10:19:55.164970309 -0500
@@ -2899,6 +2899,7 @@ flatpak_transaction_real_run (FlatpakTra
                                        priv->max_op >= APP_UPDATE,
                                        state, op->ref, op->resolved_commit,
                                        (const char **) op->subpaths,
+                                       op->resolved_metadata,
                                        progress->ostree_progress,
                                        cancellable, &local_error);
 
@@ -2941,6 +2942,7 @@ flatpak_transaction_real_run (FlatpakTra
                                           state, op->ref, op->resolved_commit,
                                           NULL,
                                           (const char **) op->subpaths,
+                                          op->resolved_metadata,
                                           progress->ostree_progress,
                                           cancellable, &local_error);
               flatpak_transaction_progress_done (progress);
diff -urp flatpak-1.2.3.orig/system-helper/flatpak-system-helper.c flatpak-1.2.3/system-helper/flatpak-system-helper.c
--- flatpak-1.2.3.orig/system-helper/flatpak-system-helper.c	2022-09-01 10:19:42.968862320 -0500
+++ flatpak-1.2.3/system-helper/flatpak-system-helper.c	2022-09-01 10:19:55.168970343 -0500
@@ -449,7 +449,7 @@ handle_deploy (FlatpakSystemHelper   *ob
 
       ostree_progress = ostree_async_progress_new_and_connect (no_progress_cb, NULL);
 
-      if (!flatpak_dir_pull (system, state, arg_ref, NULL, NULL, (const char **) arg_subpaths, NULL,
+      if (!flatpak_dir_pull (system, state, arg_ref, NULL, NULL, (const char **) arg_subpaths, NULL, NULL,
                              FLATPAK_PULL_FLAGS_NONE, OSTREE_REPO_PULL_FLAGS_UNTRUSTED, ostree_progress,
                              NULL, &error))
         {
@@ -633,11 +633,11 @@ handle_deploy_appstream (FlatpakSystemHe
 
       ostree_progress = ostree_async_progress_new_and_connect (no_progress_cb, NULL);
 
-      if (!flatpak_dir_pull (system, state, new_branch, NULL, NULL, NULL, NULL,
+      if (!flatpak_dir_pull (system, state, new_branch, NULL, NULL, NULL, NULL, NULL,
                              FLATPAK_PULL_FLAGS_NONE, OSTREE_REPO_PULL_FLAGS_UNTRUSTED, ostree_progress,
                              NULL, &first_error))
         {
-          if (!flatpak_dir_pull (system, state, old_branch, NULL, NULL, NULL, NULL,
+          if (!flatpak_dir_pull (system, state, old_branch, NULL, NULL, NULL, NULL, NULL,
                                  FLATPAK_PULL_FLAGS_NONE, OSTREE_REPO_PULL_FLAGS_UNTRUSTED, ostree_progress,
                                  NULL, &second_error))
             {
diff -urp flatpak-1.2.3.orig/tests/test-extensions.sh flatpak-1.2.3/tests/test-extensions.sh
--- flatpak-1.2.3.orig/tests/test-extensions.sh	2022-09-01 10:19:42.968862320 -0500
+++ flatpak-1.2.3/tests/test-extensions.sh	2022-09-01 10:19:55.168970343 -0500
@@ -101,7 +101,7 @@ ostree init --repo=repos/test --mode=arc
 # Modify platform metadata
 ostree checkout -U --repo=repos/test runtime/org.test.Platform/${ARCH}/master platform
 add_extensions platform
-ostree commit --repo=repos/test --owner-uid=0 --owner-gid=0 --no-xattrs --canonical-permissions  --branch=runtime/org.test.Platform/${ARCH}/master -s "modified metadata" platform
+${FLATPAK} build-export --disable-sandbox repos/test platform --files=files master
 ${FLATPAK} build-update-repo repos/test
 
 ${FLATPAK} remote-add --user --no-gpg-verify test-repo repos/test
@@ -155,7 +155,7 @@ echo "ok runtime extensions"
 # Modify app metadata
 ostree checkout -U --repo=repos/test app/org.test.Hello/${ARCH}/master hello
 add_extensions hello
-ostree commit --repo=repos/test --owner-uid=0 --owner-gid=0 --no-xattrs --canonical-permissions --branch=app/org.test.Hello/${ARCH}/master -s "modified metadata" hello
+${FLATPAK} build-export --disable-sandbox repos/test hello master
 ${FLATPAK} build-update-repo repos/test
 
 ${FLATPAK} --user update -y org.test.Hello master
diff -urp flatpak-1.2.3.orig/tests/test-run.sh flatpak-1.2.3/tests/test-run.sh
--- flatpak-1.2.3.orig/tests/test-run.sh	2022-09-01 10:19:42.968862320 -0500
+++ flatpak-1.2.3/tests/test-run.sh	2022-09-01 10:19:55.168970343 -0500
@@ -367,7 +367,8 @@ mkdir -p app/files/a-dir
 chmod a+rwx app/files/a-dir
 flatpak build-finish --command=hello.sh app
 # Note: not --canonical-permissions
-ostree --repo=repos/test commit --owner-uid=0 --owner-gid=0  --no-xattrs  ${FL_GPGARGS} --branch=app/org.test.Writable/$ARCH/master app
+${FLATPAK} build-export -vv --disable-sandbox --files=files repos/test app stable
+ostree --repo=repos/test commit  --keep-metadata=xa.metadata --owner-uid=0 --owner-gid=0  --no-xattrs  ${FL_GPGARGS} --branch=app/org.test.Writable/$ARCH/stable app
 update_repo
 
 ${FLATPAK} ${U} install -y test-repo org.test.Writable
@@ -383,7 +384,8 @@ touch app/files/exe
 chmod u+s app/files/exe
 flatpak build-finish --command=hello.sh app
 # Note: not --canonical-permissions
-ostree --repo=repos/test commit --owner-uid=0 --owner-gid=0 --no-xattrs  ${FL_GPGARGS} --branch=app/org.test.Setuid/$ARCH/master app
+${FLATPAK} build-export -vv --disable-sandbox --files=files repos/test app stable
+ostree -v --repo=repos/test commit --keep-metadata=xa.metadata --owner-uid=0 --owner-gid=0 --no-xattrs  ${FL_GPGARGS} --branch=app/org.test.Setuid/$ARCH/stable app
 update_repo
 
 if ${FLATPAK} ${U} install -y test-repo org.test.Setuid &> err2.txt; then
