update: Only allow downgrades if a commit is explicitly specified

If you run "flatpak update" then we will never update to
a commit that is older than the currently installed one. This
protects against a man-in-the-middle attack that would otherwise
let the attacker downgrade to a previously signed version that
may have some vulnerability.
tingping/wmclass
Alexander Larsson 2017-04-03 09:45:45 +02:00
parent 266b9cb6f0
commit 3ff6d312de
3 changed files with 51 additions and 4 deletions

View File

@ -1769,6 +1769,7 @@ repo_pull_one_dir (OstreeRepo *self,
const char **dirs_to_pull,
const char *ref_to_fetch,
const char *rev_to_fetch,
FlatpakPullFlags flatpak_flags,
OstreeRepoPullFlags flags,
OstreeAsyncProgress *progress,
GCancellable *cancellable,
@ -1776,7 +1777,11 @@ repo_pull_one_dir (OstreeRepo *self,
{
GVariantBuilder builder;
gboolean force_disable_deltas = FALSE;
g_autofree char *remote_and_branch = NULL;
g_autofree char *current_checksum = NULL;
g_autoptr(GVariant) options = NULL;
g_autoptr(GVariant) old_commit = NULL;
g_autoptr(GVariant) new_commit = NULL;
const char *refs_to_fetch[2];
const char *revs_to_fetch[2];
gboolean res;
@ -1811,9 +1816,33 @@ repo_pull_one_dir (OstreeRepo *self,
g_variant_new_variant (g_variant_new_strv ((const char * const *) revs_to_fetch, -1)));
options = g_variant_ref_sink (g_variant_builder_end (&builder));
remote_and_branch = g_strdup_printf ("%s:%s", remote_name, ref_to_fetch);
if (!ostree_repo_resolve_rev (self, remote_and_branch, TRUE, &current_checksum, error))
return FALSE;
if (current_checksum != NULL &&
!ostree_repo_load_commit (self, current_checksum, &old_commit, NULL, error))
return FALSE;
res = ostree_repo_pull_with_options (self, remote_name, options,
progress, cancellable, error);
if (old_commit &&
(flatpak_flags & FLATPAK_PULL_FLAGS_ALLOW_DOWNGRADE) == 0)
{
guint64 old_timestamp;
guint64 new_timestamp;
if (!ostree_repo_load_commit (self, rev_to_fetch, &new_commit, NULL, error))
return FALSE;
old_timestamp = ostree_commit_get_timestamp (old_commit);
new_timestamp = ostree_commit_get_timestamp (new_commit);
if (new_timestamp < old_timestamp)
return flatpak_fail (error, "Update is older then current version");
}
return res;
}
@ -2376,7 +2405,7 @@ flatpak_dir_pull (FlatpakDir *self,
if (!repo_pull_one_dir (repo, repository,
subdirs_arg ? (const char **)subdirs_arg->pdata : NULL,
ref, rev, flags,
ref, rev, flatpak_flags, flags,
progress,
cancellable, error))
{
@ -5080,15 +5109,19 @@ flatpak_dir_update (FlatpakDir *self,
/* We're pulling from a remote source, we do the network mirroring pull as a
user and hand back the resulting data to the system-helper, that trusts us
due to the GPG signatures in the repo */
FlatpakPullFlags flatpak_flags;
child_repo = flatpak_dir_create_system_child_repo (self, &child_repo_lock, error);
if (child_repo == NULL)
return FALSE;
flatpak_flags = FLATPAK_PULL_FLAGS_DOWNLOAD_EXTRA_DATA | FLATPAK_PULL_FLAGS_SIDELOAD_EXTRA_DATA;
if (checksum_or_latest != NULL)
flatpak_flags |= FLATPAK_PULL_FLAGS_ALLOW_DOWNGRADE;
if (!flatpak_dir_pull (self, remote_name, ref, rev, subpaths,
child_repo,
FLATPAK_PULL_FLAGS_DOWNLOAD_EXTRA_DATA | FLATPAK_PULL_FLAGS_SIDELOAD_EXTRA_DATA,
OSTREE_REPO_PULL_FLAGS_MIRROR,
flatpak_flags, OSTREE_REPO_PULL_FLAGS_MIRROR,
progress, cancellable, error))
return FALSE;

View File

@ -98,6 +98,7 @@ typedef enum {
FLATPAK_PULL_FLAGS_NONE = 0,
FLATPAK_PULL_FLAGS_DOWNLOAD_EXTRA_DATA = 1 << 0,
FLATPAK_PULL_FLAGS_SIDELOAD_EXTRA_DATA = 1 << 1,
FLATPAK_PULL_FLAGS_ALLOW_DOWNGRADE = 1 << 2,
} FlatpakPullFlags;
typedef enum {

View File

@ -24,7 +24,7 @@ set -euo pipefail
skip_without_bwrap
skip_without_user_xattrs
echo "1..9"
echo "1..10"
setup_repo
install_repo
@ -206,6 +206,19 @@ assert_file_has_content hello_out '^Hello world, from a sandboxUPDATED$'
echo "ok update"
ostree --repo=repos/test reset app/org.test.Hello/$ARCH/master "$OLD_COMMIT"
update_repo
if ${FLATPAK} ${U} update org.test.Hello; then
assert_not_reached "Should not be able to update to older commit"
fi
NEW_NEW_COMMIT=`${FLATPAK} ${U} info --show-commit org.test.Hello`
assert_streq "$NEW_COMMIT" "$NEW_NEW_COMMIT"
echo "ok backwards update"
DIR=`mktemp -d`
${FLATPAK} build-init ${DIR} org.test.Split org.test.Platform org.test.Platform