diff --git a/.gitignore b/.gitignore index 3587830..8cd2493 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -SOURCES/bubblewrap-0.1.1.tar.gz -SOURCES/rpm-ostree-client-2016.13.tar.xz +SOURCES/bubblewrap-0.1.7.tar.xz +SOURCES/rpm-ostree-client-2017.1.tar.xz diff --git a/.rpm-ostree-client.metadata b/.rpm-ostree-client.metadata index 1d1d7f7..8390388 100644 --- a/.rpm-ostree-client.metadata +++ b/.rpm-ostree-client.metadata @@ -1,2 +1,2 @@ -903322415b3e8824c6d6513a25a8b3ca03083186 SOURCES/bubblewrap-0.1.1.tar.gz -48cd727222939ba2104c85cf5084753c48c15dc5 SOURCES/rpm-ostree-client-2016.13.tar.xz +a0058efeff906bc72cb5880d37b2553d8c5430d1 SOURCES/bubblewrap-0.1.7.tar.xz +80899727c70e446b235e79705d6ee904cc399319 SOURCES/rpm-ostree-client-2017.1.tar.xz diff --git a/SOURCES/0001-Revert-selector-prefer-obsoletes-Related-RhBug-10965.patch b/SOURCES/0001-Revert-selector-prefer-obsoletes-Related-RhBug-10965.patch index 795bb72..0d95162 100644 --- a/SOURCES/0001-Revert-selector-prefer-obsoletes-Related-RhBug-10965.patch +++ b/SOURCES/0001-Revert-selector-prefer-obsoletes-Related-RhBug-10965.patch @@ -1,16 +1,4 @@ -From 1a32ea40288d88be40030665090bb2ae418cd0aa Mon Sep 17 00:00:00 2001 -From: Colin Walters -Date: Tue, 25 Oct 2016 09:53:14 -0400 -Subject: [PATCH] Revert "selector: prefer obsoletes (Related:RhBug:1096506)" - -This reverts commit 94ac2e5b980f9095faa372568a8e381e8a4523bc. ---- - data/tests/hawkey/greedy.repo | 2 -- - libdnf/hy-goal.c | 34 ++-------------------------------- - tests/hawkey/test_goal.c | 23 ----------------------- - 3 files changed, 2 insertions(+), 57 deletions(-) - -diff --git a/data/tests/hawkey/greedy.repo b/data/tests/hawkey/greedy.repo +diff --git a/libdnf/data/tests/hawkey/greedy.repo b/libdnf/data/tests/hawkey/greedy.repo index d450885..64bb85a 100644 --- a/libdnf/data/tests/hawkey/greedy.repo +++ b/libdnf/data/tests/hawkey/greedy.repo @@ -22,11 +10,11 @@ index d450885..64bb85a 100644 =Pkg: C 1 0 noarch =Prv: somereq -=Pkg: somereq 1 0 noarch -diff --git a/libdnf/hy-goal.c b/libdnf/hy-goal.c -index b404921..c50e8f5 100644 +diff --git a/libdnf/libdnf/hy-goal.c b/libdnf/libdnf/hy-goal.c +index dc05c1c..3ff1ce6 100644 --- a/libdnf/libdnf/hy-goal.c +++ b/libdnf/libdnf/hy-goal.c -@@ -523,36 +523,6 @@ filter_name2job(DnfSack *sack, const struct _Filter *f, Queue *job) +@@ -550,34 +550,6 @@ filter_name2job(DnfSack *sack, const struct _Filter *f, Queue *job) return 0; } @@ -39,8 +27,6 @@ index b404921..c50e8f5 100644 -static void -add_preferred_provide(DnfSack *sack, Queue *job, Id id) -{ -- g_autoptr(GPtrArray) plist = g_ptr_array_new_with_free_func( -- (GDestroyNotify) g_object_unref); - Pool *pool = dnf_sack_get_pool(sack); - const char *name = pool_dep2str(pool, id); - HyQuery q = hy_query_create(sack); @@ -49,7 +35,7 @@ index b404921..c50e8f5 100644 - hy_query_filter(q, HY_PKG_PROVIDES, HY_EQ, name); - hy_query_filter_package_in(q, HY_PKG_OBSOLETES, HY_NEQ, pset); - DnfPackage *pkg; -- plist = hy_query_run(q); +- g_autoptr(GPtrArray) plist = hy_query_run(q); - for (guint i = 0; i < plist->len; i++) { - pkg = g_ptr_array_index(plist, i); - queue_push2(job, SOLVER_DISFAVOR|SOLVER_SOLVABLE, @@ -63,7 +49,7 @@ index b404921..c50e8f5 100644 static int filter_provides2job(DnfSack *sack, const struct _Filter *f, Queue *job) { -@@ -568,7 +538,7 @@ filter_provides2job(DnfSack *sack, const struct _Filter *f, Queue *job) +@@ -593,7 +565,7 @@ filter_provides2job(DnfSack *sack, const struct _Filter *f, Queue *job) switch (f->cmp_type) { case HY_EQ: id = dnf_reldep_get_id (f->matches[0].reldep); @@ -72,7 +58,7 @@ index b404921..c50e8f5 100644 break; case HY_GLOB: dataiterator_init(&di, pool, 0, 0, SOLVABLE_PROVIDES, name, SEARCH_GLOB); -@@ -579,7 +549,7 @@ filter_provides2job(DnfSack *sack, const struct _Filter *f, Queue *job) +@@ -604,7 +576,7 @@ filter_provides2job(DnfSack *sack, const struct _Filter *f, Queue *job) assert(di.idp); id = *di.idp; if (!job_has(job, SOLVABLE_PROVIDES, id)) @@ -81,11 +67,11 @@ index b404921..c50e8f5 100644 dataiterator_free(&di); break; default: -diff --git a/tests/hawkey/test_goal.c b/tests/hawkey/test_goal.c -index 6217c38..ce2c8bd 100644 +diff --git a/libdnf/tests/hawkey/test_goal.c b/libdnf/tests/hawkey/test_goal.c +index 7c30097..2a98983 100644 --- a/libdnf/tests/hawkey/test_goal.c +++ b/libdnf/tests/hawkey/test_goal.c -@@ -230,28 +230,6 @@ START_TEST(test_goal_install_selector) +@@ -230,27 +230,6 @@ START_TEST(test_goal_install_selector) } END_TEST @@ -103,9 +89,8 @@ index 6217c38..ce2c8bd 100644 - assert_iueo(goal, 1, 0, 0, 0); - - GPtrArray *plist = hy_goal_list_installs(goal, NULL); -- char *nvra = dnf_package_get_nevra(g_ptr_array_index(plist, 0)); +- const char *nvra = dnf_package_get_nevra(g_ptr_array_index(plist, 0)); - ck_assert_str_eq(nvra, "B-1-0.noarch"); -- g_free(nvra); - g_ptr_array_unref(plist); - hy_goal_free(goal); -} @@ -114,7 +99,7 @@ index 6217c38..ce2c8bd 100644 START_TEST(test_goal_install_selector_err) { int rc; -@@ -1459,7 +1437,6 @@ goal_suite(void) +@@ -1456,7 +1435,6 @@ goal_suite(void) tc = tcase_create("Greedy"); tcase_add_unchecked_fixture(tc, fixture_greedy_only, teardown); tcase_add_test(tc, test_goal_run_all); @@ -122,6 +107,3 @@ index 6217c38..ce2c8bd 100644 tcase_add_test(tc, test_goal_install_weak_deps); suite_add_tcase(s, tc); --- -2.7.4 - diff --git a/SOURCES/0001-core-Do-GPG-verification-before-importing.patch b/SOURCES/0001-core-Do-GPG-verification-before-importing.patch new file mode 100644 index 0000000..a89cee8 --- /dev/null +++ b/SOURCES/0001-core-Do-GPG-verification-before-importing.patch @@ -0,0 +1,153 @@ +From 74c4068b9da7f2dff16a8ee2605d3350a6a782f6 Mon Sep 17 00:00:00 2001 +From: Colin Walters +Date: Thu, 2 Feb 2017 15:41:29 -0500 +Subject: [PATCH] core: Do GPG verification before importing + +While reading a recent conversation about GPG checking at treecompose +time, I had a sudden thought - were we actually doing verification +client side? Turned out, we aren't. That happens as part of +`dnf_transaction_commit()` which we don't use. + +That function verifies every package at one go, but for us I think it's better +to do it before "importing". We shouldn't have untrusted bits that we've +unpacked (they might have suid binaries, for one thing). + +This is an embarassing problem, but it's worth emphasizing that everyone should +be retrieving repodata at a minimum over TLS, which sets a baseline. On RHEL, we +already do pinned TLS, and there are discussions about extending that elsewhere. +--- + libdnf | 2 +- + src/libpriv/rpmostree-core.c | 12 +++++++++++- + tests/common/libvm.sh | 16 ++++++++++++++++ + tests/vmcheck/test-layering-gpg.sh | 37 +++++++++++++++++++++++++++++++++++++ + 4 files changed, 65 insertions(+), 2 deletions(-) + create mode 100755 tests/vmcheck/test-layering-gpg.sh + +diff --git a/src/libpriv/rpmostree-core.c b/src/libpriv/rpmostree-core.c +index 2daaa48..0b4a3ab 100644 +--- a/src/libpriv/rpmostree-core.c ++++ b/src/libpriv/rpmostree-core.c +@@ -1152,18 +1152,25 @@ import_one_package (RpmOstreeContext *self, + g_autofree char *ostree_commit = NULL; + glnx_unref_object RpmOstreeUnpacker *unpacker = NULL; + g_autofree char *pkg_path; ++ DnfRepo *pkg_repo; + int flags = 0; + ++ pkg_repo = dnf_package_get_repo (pkg); ++ + if (pkg_is_local (pkg)) + pkg_path = g_strdup (dnf_package_get_filename (pkg)); + else + { + const char *pkg_location = dnf_package_get_location (pkg); + pkg_path = +- g_build_filename (dnf_repo_get_location (dnf_package_get_repo (pkg)), ++ g_build_filename (dnf_repo_get_location (pkg_repo), + "packages", glnx_basename (pkg_location), NULL); + } + ++ /* Verify signatures if enabled */ ++ if (!dnf_transaction_gpgcheck_package (dnf_context_get_transaction (hifctx), pkg, error)) ++ goto out; ++ + flags = RPMOSTREE_UNPACKER_FLAGS_OSTREE_CONVENTION; + if (self->unprivileged) + flags |= RPMOSTREE_UNPACKER_FLAGS_UNPRIVILEGED; +@@ -1220,6 +1227,9 @@ rpmostree_context_import (RpmOstreeContext *self, + + g_return_val_if_fail (get_pkgcache_repo (self) != NULL, FALSE); + ++ if (!dnf_transaction_import_keys (dnf_context_get_transaction (hifctx), error)) ++ goto out; ++ + { + glnx_unref_object DnfState *hifstate = dnf_state_new (); + dnf_state_set_number_steps (hifstate, install->packages_to_import->len); +diff --git a/tests/common/libvm.sh b/tests/common/libvm.sh +index 3b7cb35..bbbcba2 100644 +--- a/tests/common/libvm.sh ++++ b/tests/common/libvm.sh +@@ -51,6 +51,11 @@ vm_cmd() { + $SSH "$@" + } + ++# Delete anything which we might change between runs ++vm_clean_caches() { ++ vm_cmd rm /ostree/repo/extensions/rpmostree/pkgcache/refs/heads/* -rf ++} ++ + # run rpm-ostree in vm + # - $@ args + vm_rpmostree() { +@@ -68,6 +73,7 @@ vm_send() { + + # copy the test repo to the vm + vm_send_test_repo() { ++ gpgcheck=${1:-0} + vm_cmd rm -rf /tmp/vmcheck + vm_send /tmp/vmcheck ${commondir}/compose/yum/repo + +@@ -77,6 +83,16 @@ name=test-repo + baseurl=file:///tmp/vmcheck/repo + EOF + ++ if [ $gpgcheck -eq 1 ]; then ++ cat >> vmcheck.repo <> vmcheck.repo ++ fi ++ + vm_send /etc/yum.repos.d vmcheck.repo + } + +diff --git a/tests/vmcheck/test-layering-gpg.sh b/tests/vmcheck/test-layering-gpg.sh +new file mode 100755 +index 0000000..6b66a79 +--- /dev/null ++++ b/tests/vmcheck/test-layering-gpg.sh +@@ -0,0 +1,37 @@ ++#!/bin/bash ++# ++# Copyright (C) 2017 Red Hat, Inc. ++# ++# This library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public ++# License as published by the Free Software Foundation; either ++# version 2 of the License, or (at your option) any later version. ++# ++# This library is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public ++# License along with this library; if not, write to the ++# Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++# Boston, MA 02111-1307, USA. ++ ++set -e ++ ++. ${commondir}/libtest.sh ++. ${commondir}/libvm.sh ++ ++set -x ++ ++vm_send_test_repo 1 ++vm_clean_caches ++ ++# make sure the package is not already layered ++vm_assert_layered_pkg foo absent ++ ++if vm_rpmostree pkg-add foo-1.0 2>err.txt; then ++ assert_not_reached "Installed unsigned package" ++fi ++assert_file_has_content err.txt 'package not signed: foo' ++echo "ok failed to install unsigned package" +-- +2.9.3 + diff --git a/SOURCES/0001-daemon-Avoid-erroring-out-on-startup-status-with-ori.patch b/SOURCES/0001-daemon-Avoid-erroring-out-on-startup-status-with-ori.patch new file mode 100644 index 0000000..7eb621d --- /dev/null +++ b/SOURCES/0001-daemon-Avoid-erroring-out-on-startup-status-with-ori.patch @@ -0,0 +1,109 @@ +From c48a889da09af0c2cc9d540fa5f3868d6f239e3e Mon Sep 17 00:00:00 2001 +From: Colin Walters +Date: Mon, 13 Feb 2017 21:01:31 -0500 +Subject: [PATCH] daemon: Avoid erroring out on startup/status with origin + unconfigured-state + +As part of an earlier cleanup of origin parsing, we started checking +the origin `unconfigured-state` even just starting the daemon, which +is kind of bad. + +It's tempting to flip the default for the parser so that we *only* check +unconfigured state if we go to upgrade, but let's not do that in this patch. + +Closes: #626 +Approved by: jlebon +--- + src/daemon/rpmostree-sysroot-upgrader.c | 3 ++- + src/daemon/rpmostreed-deployment-utils.c | 6 ++++-- + src/daemon/rpmostreed-os.c | 3 ++- + tests/check/test-basic.sh | 14 +++++++++++++- + 4 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/src/daemon/rpmostree-sysroot-upgrader.c b/src/daemon/rpmostree-sysroot-upgrader.c +index edadde0..cdb90d4 100644 +--- a/src/daemon/rpmostree-sysroot-upgrader.c ++++ b/src/daemon/rpmostree-sysroot-upgrader.c +@@ -1321,7 +1321,8 @@ clean_pkgcache_orphans (RpmOstreeSysrootUpgrader *self, + OstreeDeployment *deployment = deployments->pdata[i]; + g_autoptr(RpmOstreeOrigin) origin = NULL; + +- origin = rpmostree_origin_parse_deployment (deployment, error); ++ origin = rpmostree_origin_parse_deployment_ex (deployment, RPMOSTREE_ORIGIN_PARSE_FLAGS_IGNORE_UNCONFIGURED, ++ error); + if (!origin) + return FALSE; + +diff --git a/src/daemon/rpmostreed-deployment-utils.c b/src/daemon/rpmostreed-deployment-utils.c +index 9b2fb9a..43c814f 100644 +--- a/src/daemon/rpmostreed-deployment-utils.c ++++ b/src/daemon/rpmostreed-deployment-utils.c +@@ -185,7 +185,8 @@ rpmostreed_deployment_generate_variant (OstreeDeployment *deployment, + + id = rpmostreed_deployment_generate_id (deployment); + +- origin = rpmostree_origin_parse_deployment (deployment, error); ++ origin = rpmostree_origin_parse_deployment_ex (deployment, RPMOSTREE_ORIGIN_PARSE_FLAGS_IGNORE_UNCONFIGURED, ++ error); + if (!origin) + return NULL; + +@@ -254,7 +255,8 @@ rpmostreed_commit_generate_cached_details_variant (OstreeDeployment *deployment, + { + g_autoptr(RpmOstreeOrigin) origin = NULL; + +- origin = rpmostree_origin_parse_deployment (deployment, error); ++ origin = rpmostree_origin_parse_deployment_ex (deployment, RPMOSTREE_ORIGIN_PARSE_FLAGS_IGNORE_UNCONFIGURED, ++ error); + if (!origin) + return NULL; + origin_refspec = g_strdup (rpmostree_origin_get_refspec (origin)); +diff --git a/src/daemon/rpmostreed-os.c b/src/daemon/rpmostreed-os.c +index ded637d..3fde7da 100644 +--- a/src/daemon/rpmostreed-os.c ++++ b/src/daemon/rpmostreed-os.c +@@ -1166,7 +1166,8 @@ rpmostreed_os_load_internals (RpmostreedOS *self, GError **error) + g_autoptr(RpmOstreeOrigin) origin = NULL; + + /* Don't fail here for unknown origin types */ +- origin = rpmostree_origin_parse_deployment (merge_deployment, NULL); ++ origin = rpmostree_origin_parse_deployment_ex (merge_deployment, RPMOSTREE_ORIGIN_PARSE_FLAGS_IGNORE_UNCONFIGURED, ++ NULL); + if (origin) + { + cached_update = rpmostreed_commit_generate_cached_details_variant (merge_deployment, +diff --git a/tests/check/test-basic.sh b/tests/check/test-basic.sh +index 8b7baa6..670a668 100755 +--- a/tests/check/test-basic.sh ++++ b/tests/check/test-basic.sh +@@ -24,7 +24,7 @@ export RPMOSTREE_SUPPRESS_REQUIRES_ROOT_CHECK=yes + + ensure_dbus + +-echo "1..14" ++echo "1..15" + + setup_os_repository "archive-z2" "syslinux" + +@@ -145,6 +145,18 @@ $OSTREE remote add secureos file://$(pwd)/testos-repo + rpm-ostree rebase --os=testos secureos:$branch gpg-signed + echo "ok deploy from remote with unsigned and signed commits" + ++originpath=$(ostree admin --sysroot=sysroot --print-current-dir).origin ++echo "unconfigured-state=Access to TestOS requires ONE BILLION DOLLARS" >> ${originpath} ++pid=$(pgrep -u $(id -u) -f 'rpm-ostree.*daemon') ++test -n "${pid}" || assert_not_reached "failed to find rpm-ostree pid" ++kill -9 ${pid} ++rpm-ostree status ++if rpm-ostree upgrade --os=testos 2>err.txt; then ++ assert_not_reached "Upgraded from unconfigured-state" ++fi ++assert_file_has_content err.txt 'ONE BILLION DOLLARS' ++echo "ok unconfigured status" ++ + # Ensure it returns an error when passing a wrong option. + rpm-ostree --help | awk '/^$/ {in_commands=0} {if(in_commands==1){print $0}} /^Builtin Commands:/ {in_commands=1}' > commands + while read command; do +-- +2.9.3 + diff --git a/SOURCES/0001-unpacker-support-root-owned-var-run-files.patch b/SOURCES/0001-unpacker-support-root-owned-var-run-files.patch new file mode 100644 index 0000000..8c7c248 --- /dev/null +++ b/SOURCES/0001-unpacker-support-root-owned-var-run-files.patch @@ -0,0 +1,86 @@ +From 8cf071127e670671065d041f2cb678cdc303b9c1 Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon +Date: Mon, 13 Feb 2017 11:32:19 -0500 +Subject: [PATCH 1/2] unpacker: support root-owned /var & /run files + +I'm not sure why we weren't doing this before, but we need to also +support files in /var and /run that are owned by root. + +Related: RHBZ#1421781 + +Closes: #622 +Approved by: cgwalters +--- + src/libpriv/rpmostree-unpacker.c | 9 +++++---- + tests/common/compose/yum/nonrootcap.spec | 4 ++++ + tests/vmcheck/test-layering-non-root-caps.sh | 6 +++++- + 3 files changed, 14 insertions(+), 5 deletions(-) + +diff --git a/src/libpriv/rpmostree-unpacker.c b/src/libpriv/rpmostree-unpacker.c +index 34e133a..98586d9 100644 +--- a/src/libpriv/rpmostree-unpacker.c ++++ b/src/libpriv/rpmostree-unpacker.c +@@ -594,11 +594,12 @@ compose_filter_cb (OstreeRepo *repo, + + get_rpmfi_override (self, path, &user, &group, NULL); + +- /* First, look for non-root paths in /run and /var */ +- if ((user != NULL || group != NULL) && +- (g_str_has_prefix (path, "/run/") || g_str_has_prefix (path, "/var/"))) ++ /* convert /run and /var entries to tmpfiles.d */ ++ if (g_str_has_prefix (path, "/run/") || ++ g_str_has_prefix (path, "/var/")) + { +- append_tmpfiles_d (self, path, file_info, user, group); ++ append_tmpfiles_d (self, path, file_info, ++ user ?: "root", group ?: "root"); + return OSTREE_REPO_COMMIT_FILTER_SKIP; + } + else if (!error_was_set) +diff --git a/tests/common/compose/yum/nonrootcap.spec b/tests/common/compose/yum/nonrootcap.spec +index 8f9dead..be5959d 100644 +--- a/tests/common/compose/yum/nonrootcap.spec ++++ b/tests/common/compose/yum/nonrootcap.spec +@@ -38,6 +38,8 @@ mkdir -p %{buildroot}/usr/bin + install *.sh %{buildroot}/usr/bin + mkdir -p %{buildroot}/var/lib/nonrootcap + mkdir -p %{buildroot}/run/nonrootcap ++mkdir -p %{buildroot}/var/lib/nonrootcap-rootowned ++mkdir -p %{buildroot}/run/nonrootcap-rootowned + + %clean + rm -rf %{buildroot} +@@ -53,6 +55,8 @@ rm -rf %{buildroot} + %attr(4775, nrcuser, nrcgroup) %caps(cap_net_bind_service=ep) /usr/bin/nrc-usergroupcaps-setuid.sh + %attr(-, nrcuser, nrcgroup) /var/lib/nonrootcap + %attr(-, nrcuser, nrcgroup) /run/nonrootcap ++/var/lib/nonrootcap-rootowned ++/run/nonrootcap-rootowned + + %changelog + * Wed Jan 05 2017 Jonathan Lebon 1.0-1 +diff --git a/tests/vmcheck/test-layering-non-root-caps.sh b/tests/vmcheck/test-layering-non-root-caps.sh +index aa9991c..6cba6e2 100755 +--- a/tests/vmcheck/test-layering-non-root-caps.sh ++++ b/tests/vmcheck/test-layering-non-root-caps.sh +@@ -51,7 +51,9 @@ if ! vm_has_files /usr/bin/nrc-none.sh \ + /usr/bin/nrc-usergroup.sh \ + /usr/bin/nrc-usergroupcaps.sh \ + /var/lib/nonrootcap \ +- /run/nonrootcap; then ++ /run/nonrootcap \ ++ /var/lib/nonrootcap-rootowned \ ++ /run/nonrootcap-rootowned; then + assert_not_reached "not all files were layered" + fi + echo "ok all files layered" +@@ -96,4 +98,6 @@ check_file /usr/bin/nrc-usergroupcaps-setuid.sh nrcuser nrcgroup "cap_net_bind_s + vm_cmd test -u /usr/bin/nrc-usergroupcaps-setuid.sh + check_file /var/lib/nonrootcap nrcuser nrcgroup + check_file /run/nonrootcap nrcuser nrcgroup ++check_file /var/lib/nonrootcap-rootowned root root ++check_file /run/nonrootcap-rootowned root root + echo "ok correct user/group and fcaps" +-- +2.10.2 + diff --git a/SOURCES/libdnf-gpg.patch b/SOURCES/libdnf-gpg.patch new file mode 100644 index 0000000..4b9bac4 --- /dev/null +++ b/SOURCES/libdnf-gpg.patch @@ -0,0 +1,318 @@ +From b2ded5a4da58940159f5d337e9e29c5de5cc0f7a Mon Sep 17 00:00:00 2001 +From: Colin Walters +Date: Thu, 2 Feb 2017 10:00:06 -0500 +Subject: [PATCH 1/2] repo: Enable GPG by default + +This increases compatibility with dnf/yum. It was very surprising to me that we +didn't do this. Most repos do seem to use `gpgcheck=1`, but I'm fairly certain +I've seen repo configs in the wild that actually depend on it, though after +looking at a few (ceph, postgres), I can't find one yet. + +Still, I think it's worth making this change. I suspect very few people will +edit `/etc/yum/yum.conf` to globally disable GPG checking, versus disabling it +per repository. +--- + libdnf/dnf-repo.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/libdnf/dnf-repo.c b/libdnf/dnf-repo.c +index 08e0d8b..017c82d 100644 +--- a/libdnf/libdnf/dnf-repo.c ++++ b/libdnf/libdnf/dnf-repo.c +@@ -858,7 +858,16 @@ dnf_repo_set_keyfile_data(DnfRepo *repo, GError **error) + /* gpgkey is optional for gpgcheck=1, but required for repo_gpgcheck=1 */ + g_free(priv->gpgkey); + priv->gpgkey = g_key_file_get_string(priv->keyfile, priv->id, "gpgkey", NULL); +- priv->gpgcheck_pkgs = dnf_repo_get_boolean(priv->keyfile, priv->id, "gpgcheck", NULL); ++ /* Currently, we don't have a global configuration file. The way this worked in yum ++ * is that the yum package enabled gpgcheck=1 by default in /etc/yum.conf. Basically, ++ * I don't think many people changed that. It's just saner to disable it in the individual ++ * repo files as required. To claim compatibility with yum repository files, I think ++ * we need to basically hard code the yum.conf defaults here. ++ */ ++ if (!g_key_file_has_key (priv->keyfile, priv->id, "gpgcheck", NULL)) ++ priv->gpgcheck_pkgs = TRUE; ++ else ++ priv->gpgcheck_pkgs = dnf_repo_get_boolean(priv->keyfile, priv->id, "gpgcheck", NULL); + priv->gpgcheck_md = dnf_repo_get_boolean(priv->keyfile, priv->id, "repo_gpgcheck", NULL); + if (priv->gpgcheck_md && priv->gpgkey == NULL) { + g_set_error_literal(error, +-- +2.9.3 + + +From 0d68ebac7d39a9278ebb5259c4912efa55c080da Mon Sep 17 00:00:00 2001 +From: Colin Walters +Date: Tue, 31 Jan 2017 17:14:37 -0500 +Subject: [PATCH 2/2] transaction: Export parts of the GPG functionality + +rpm-ostree doesn't use `dnf_transaction_commit()`, because it uses libostree to +store the RPMs, and bubblewrap to run `%post`s. However, we do need the GPG +functionality. +--- + libdnf/libdnf/dnf-transaction.c | 193 ++++++++++++++++++++++++++++------------------- + libdnf/libdnf/dnf-transaction.h | 11 +++ + 2 files changed, 127 insertions(+), 77 deletions(-) + +diff --git a/libdnf/libdnf/dnf-transaction.c b/libdnf/libdnf/dnf-transaction.c +index 62fcc51..dd73245 100644 +--- a/libdnf/libdnf/dnf-transaction.c ++++ b/libdnf/libdnf/dnf-transaction.c +@@ -328,17 +328,88 @@ dnf_transaction_ensure_repo_list(DnfTransaction *transaction, + return TRUE; + } + ++gboolean ++dnf_transaction_gpgcheck_package (DnfTransaction *transaction, ++ DnfPackage *pkg, ++ GError **error) ++{ ++ DnfTransactionPrivate *priv = GET_PRIVATE(transaction); ++ GError *error_local = NULL; ++ DnfRepo *repo; ++ const gchar *fn; ++ ++ /* ensure the filename is set */ ++ if (!dnf_transaction_ensure_repo(transaction, pkg, error)) { ++ g_prefix_error(error, "Failed to check untrusted: "); ++ return FALSE; ++ } ++ ++ /* find the location of the local file */ ++ fn = dnf_package_get_filename(pkg); ++ if (fn == NULL) { ++ g_set_error(error, ++ DNF_ERROR, ++ DNF_ERROR_FILE_NOT_FOUND, ++ "Downloaded file for %s not found", ++ dnf_package_get_name(pkg)); ++ return FALSE; ++ } ++ ++ /* check file */ ++ if (!dnf_keyring_check_untrusted_file(priv->keyring, fn, &error_local)) { ++ ++ /* probably an i/o error */ ++ if (!g_error_matches(error_local, ++ DNF_ERROR, ++ DNF_ERROR_GPG_SIGNATURE_INVALID)) { ++ g_propagate_error(error, error_local); ++ return FALSE; ++ } ++ ++ /* if the repo is signed this is ALWAYS an error */ ++ repo = dnf_package_get_repo(pkg); ++ if (repo != NULL && dnf_repo_get_gpgcheck(repo)) { ++ g_set_error(error, ++ DNF_ERROR, ++ DNF_ERROR_FILE_INVALID, ++ "package %s cannot be verified " ++ "and repo %s is GPG enabled: %s", ++ dnf_package_get_nevra(pkg), ++ dnf_repo_get_id(repo), ++ error_local->message); ++ g_error_free(error_local); ++ return FALSE; ++ } ++ ++ /* we can only install signed packages in this mode */ ++ if ((priv->flags & DNF_TRANSACTION_FLAG_ONLY_TRUSTED) > 0) { ++ g_propagate_error(error, error_local); ++ return FALSE; ++ } ++ ++ /* we can install unsigned packages */ ++ g_warning("ignoring as allow-untrusted: %s", ++ error_local->message); ++ g_clear_error(&error_local); ++ } ++ ++ return TRUE; ++} ++ + /** + * dnf_transaction_check_untrusted: ++ * @transaction: Transaction ++ * @goal: Target goal ++ * @error: Error ++ * ++ * Verify GPG signatures for all pending packages to be changed as part ++ * of @goal. + */ +-static gboolean ++gboolean + dnf_transaction_check_untrusted(DnfTransaction *transaction, + HyGoal goal, + GError **error) + { +- DnfTransactionPrivate *priv = GET_PRIVATE(transaction); +- DnfPackage *pkg; +- const gchar *fn; + guint i; + g_autoptr(GPtrArray) install = NULL; + +@@ -354,64 +425,10 @@ dnf_transaction_check_untrusted(DnfTransaction *transaction, + + /* find any packages in untrusted repos */ + for (i = 0; i < install->len; i++) { +- GError *error_local = NULL; +- DnfRepo *repo; +- pkg = g_ptr_array_index(install, i); ++ DnfPackage *pkg = g_ptr_array_index(install, i); + +- /* ensure the filename is set */ +- if (!dnf_transaction_ensure_repo(transaction, pkg, error)) { +- g_prefix_error(error, "Failed to check untrusted: "); ++ if (!dnf_transaction_gpgcheck_package (transaction, pkg, error)) + return FALSE; +- } +- +- /* find the location of the local file */ +- fn = dnf_package_get_filename(pkg); +- if (fn == NULL) { +- g_set_error(error, +- DNF_ERROR, +- DNF_ERROR_FILE_NOT_FOUND, +- "Downloaded file for %s not found", +- dnf_package_get_name(pkg)); +- return FALSE; +- } +- +- /* check file */ +- if (!dnf_keyring_check_untrusted_file(priv->keyring, fn, &error_local)) { +- +- /* probably an i/o error */ +- if (!g_error_matches(error_local, +- DNF_ERROR, +- DNF_ERROR_GPG_SIGNATURE_INVALID)) { +- g_propagate_error(error, error_local); +- return FALSE; +- } +- +- /* if the repo is signed this is ALWAYS an error */ +- repo = dnf_package_get_repo(pkg); +- if (repo != NULL && dnf_repo_get_gpgcheck(repo)) { +- g_set_error(error, +- DNF_ERROR, +- DNF_ERROR_FILE_INVALID, +- "package %s cannot be verified " +- "and repo %s is GPG enabled: %s", +- dnf_package_get_nevra(pkg), +- dnf_repo_get_id(repo), +- error_local->message); +- g_error_free(error_local); +- return FALSE; +- } +- +- /* we can only install signed packages in this mode */ +- if ((priv->flags & DNF_TRANSACTION_FLAG_ONLY_TRUSTED) > 0) { +- g_propagate_error(error, error_local); +- return FALSE; +- } +- +- /* we can install unsigned packages */ +- g_debug("ignoring as allow-untrusted: %s", +- error_local->message); +- g_clear_error(&error_local); +- } + } + return TRUE; + } +@@ -1167,6 +1184,44 @@ dnf_transaction_reset(DnfTransaction *transaction) + } + + /** ++ * dnf_transaction_import_keys: ++ * @transaction: a #DnfTransaction instance. ++ * @error: A #GError or %NULL ++ * ++ * Imports all keys from /etc/pki/rpm-gpg as well as any ++ * downloaded per-repo keys. Note this is called automatically ++ * by dnf_transaction_commit(). ++ **/ ++gboolean ++dnf_transaction_import_keys(DnfTransaction *transaction, ++ GError **error) ++{ ++ guint i; ++ ++ DnfTransactionPrivate *priv = GET_PRIVATE(transaction); ++ /* import all system wide GPG keys */ ++ if (!dnf_keyring_add_public_keys(priv->keyring, error)) ++ return FALSE; ++ ++ /* import downloaded repo GPG keys */ ++ for (i = 0; i < priv->repos->len; i++) { ++ DnfRepo *repo = g_ptr_array_index(priv->repos, i); ++ const gchar *pubkey; ++ ++ /* does this file actually exist */ ++ pubkey = dnf_repo_get_public_key(repo); ++ if (g_file_test(pubkey, G_FILE_TEST_EXISTS)) { ++ /* import */ ++ if (!dnf_keyring_add_public_key(priv->keyring, pubkey, error)) ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++} ++ ++ ++/** + * dnf_transaction_commit: + * @transaction: a #DnfTransaction instance. + * @goal: A #HyGoal +@@ -1237,26 +1292,10 @@ dnf_transaction_commit(DnfTransaction *transaction, + if (!ret) + goto out; + +- /* import all system wide GPG keys */ +- ret = dnf_keyring_add_public_keys(priv->keyring, error); ++ ret = dnf_transaction_import_keys(transaction, error); + if (!ret) + goto out; + +- /* import downloaded repo GPG keys */ +- for (i = 0; i < priv->repos->len; i++) { +- DnfRepo *repo = g_ptr_array_index(priv->repos, i); +- const gchar *pubkey; +- +- /* does this file actually exist */ +- pubkey = dnf_repo_get_public_key(repo); +- if (g_file_test(pubkey, G_FILE_TEST_EXISTS)) { +- /* import */ +- ret = dnf_keyring_add_public_key(priv->keyring, pubkey, error); +- if (!ret) +- goto out; +- } +- } +- + /* find any packages without valid GPG signatures */ + ret = dnf_transaction_check_untrusted(transaction, goal, error); + if (!ret) +diff --git a/libdnf/libdnf/dnf-transaction.h b/libdnf/libdnf/dnf-transaction.h +index 6131374..84d1365 100644 +--- a/libdnf/libdnf/dnf-transaction.h ++++ b/libdnf/libdnf/dnf-transaction.h +@@ -95,6 +95,17 @@ gboolean dnf_transaction_depsolve (DnfTransaction *transac + gboolean dnf_transaction_download (DnfTransaction *transaction, + DnfState *state, + GError **error); ++ ++gboolean dnf_transaction_import_keys (DnfTransaction *transaction, ++ GError **error); ++ ++gboolean dnf_transaction_gpgcheck_package (DnfTransaction *transaction, ++ DnfPackage *pkg, ++ GError **error); ++gboolean dnf_transaction_check_untrusted (DnfTransaction *transaction, ++ HyGoal goal, ++ GError **error); ++ + gboolean dnf_transaction_commit (DnfTransaction *transaction, + HyGoal goal, + DnfState *state, +-- +2.9.3 + diff --git a/SPECS/rpm-ostree-client.spec b/SPECS/rpm-ostree-client.spec index 47cb900..2d1306e 100644 --- a/SPECS/rpm-ostree-client.spec +++ b/SPECS/rpm-ostree-client.spec @@ -1,16 +1,20 @@ -%global bubblewrap_version 0.1.1 +%global bubblewrap_version 0.1.7 Summary: Client side upgrade program Name: rpm-ostree-client -Version: 2016.13 -Release: 1.atomic%{?dist} +Version: 2017.1 +Release: 6.atomic%{?dist} #VCS: https://github.com/cgwalters/rpm-ostree # This tarball is generated via "make -f Makefile.dist-packaging dist-snapshot-without-compose-tooling" Source0: rpm-ostree-client-%{version}.tar.xz License: LGPLv2+ URL: https://github.com/projectatomic/rpm-ostree -Source1: bubblewrap-%{bubblewrap_version}.tar.gz +Source1: https://github.com/projectatomic/bubblewrap/releases/download/v%{bubblewrap_version}/bubblewrap-%{bubblewrap_version}.tar.xz Patch1: 0001-Revert-selector-prefer-obsoletes-Related-RhBug-10965.patch +Patch2: 0001-unpacker-support-root-owned-var-run-files.patch +Patch3: 0001-daemon-Avoid-erroring-out-on-startup-status-with-ori.patch +Patch4: libdnf-gpg.patch +Patch5: 0001-core-Do-GPG-verification-before-importing.patch Requires: ostree-fuse @@ -20,10 +24,9 @@ BuildRequires: autoconf automake libtool git BuildRequires: chrpath BuildRequires: gtk-doc BuildRequires: gnome-common -BuildRequires: gobject-introspection +BuildRequires: gobject-introspection-devel # Core requirements BuildRequires: pkgconfig(ostree-1) >= 2015.1 -BuildRequires: pkgconfig(libgsystem) BuildRequires: pkgconfig(json-glib-1.0) BuildRequires: pkgconfig(rpm) BuildRequires: pkgconfig(libarchive) @@ -63,7 +66,7 @@ tar xf %{SOURCE1} %build (cd bubblewrap-%{bubblewrap_version} && - env NOCONFIGURE=1 ./autogen.sh && + if ! test -x configure; then NOCONFIGURE=1 ./autogen.sh; fi && %configure --disable-silent-rules make %{?_smp_mflags} ) @@ -121,6 +124,22 @@ python autofiles.py > files \ %doc COPYING README.md %changelog +* Tue Feb 14 2017 Colin Walters - 2017.1-6.atomic +- Add patch to do GPG checking before importing/installing RPMs +- Resolves: #1422157 + +* Tue Feb 14 2017 Colin Walters - 2017.1-5.atomic +- Backport patch for unconfigured-state handling +- Resolves: #1421867 + +* Mon Feb 13 2017 Jonathan Lebon - 2017.1-4.atomic +- Resolves: #1421781 + +* Tue Jan 24 2017 Colin Walters - 2017.1-3.atomic +- New upstream version + Resolves: #1416089 +- Bump bubblewrap to latest release too + * Mon Dec 12 2016 walters@redhat.com - 2016.13-1.atomic - New upstream version - Resolves: #1403933