libpriv/scripts: Add rpmdb query sanity checks

Make sure we can open and query the rpmdb when creating new deployments.
This should help filter out cases where somehow librpm failed to
actually write the rpmdb but didn't error out.

This requires splitting the sanity checking in two so that we still get
that nice error first on scripts that do `rm -rf`.

See: #1566

Closes: #1584
Approved by: cgwalters
This commit is contained in:
Jonathan Lebon 2018-09-26 12:22:31 -04:00 committed by Atomic Bot
parent 16b005bd56
commit 2e3d4b72a1
4 changed files with 88 additions and 12 deletions

View File

@ -1332,7 +1332,7 @@ rpmostree_sysroot_upgrader_deploy (RpmOstreeSysrootUpgrader *self,
&deployment_dfd, error))
return FALSE;
if (!rpmostree_deployment_sanitycheck (deployment_dfd, cancellable, error))
if (!rpmostree_deployment_sanitycheck_true (deployment_dfd, cancellable, error))
return FALSE;
}
else

View File

@ -3806,6 +3806,9 @@ rpmostree_context_assemble (RpmOstreeContext *self,
if (!rpmostree_rootfs_prepare_links (tmprootfs_dfd, cancellable, error))
return FALSE;
gboolean skip_sanity_check = FALSE;
g_variant_dict_lookup (self->spec->dict, "skip-sanity-check", "b", &skip_sanity_check);
/* NB: we're not running scripts right now for removals, so this is only for overlays and
* replacements */
if (overlays->len > 0 || overrides_replace->len > 0)
@ -3978,11 +3981,10 @@ rpmostree_context_assemble (RpmOstreeContext *self,
/* We want this to be the first error message if something went wrong
* with a script; see https://github.com/projectatomic/rpm-ostree/pull/888
* (otherwise, on a script that did `rm -rf`, we'd fail first on the renameat below)
*/
gboolean skip_sanity_check = FALSE;
g_variant_dict_lookup (self->spec->dict, "skip-sanity-check", "b", &skip_sanity_check);
if (!skip_sanity_check &&
!rpmostree_deployment_sanitycheck (tmprootfs_dfd, cancellable, error))
!rpmostree_deployment_sanitycheck_true (tmprootfs_dfd, cancellable, error))
return FALSE;
if (have_systemctl)
@ -3997,12 +3999,12 @@ rpmostree_context_assemble (RpmOstreeContext *self,
if (!rpmostree_passwd_complete_rpm_layering (tmprootfs_dfd, error))
return FALSE;
}
}
else
{
/* Also do a sanity check even if we have no layered packages */
if (!rpmostree_deployment_sanitycheck (tmprootfs_dfd, cancellable, error))
if (!skip_sanity_check &&
!rpmostree_deployment_sanitycheck_true (tmprootfs_dfd, cancellable, error))
return FALSE;
}
@ -4104,6 +4106,14 @@ rpmostree_context_assemble (RpmOstreeContext *self,
rpmostree_output_task_end ("done");
/* And now also sanity check the rpmdb */
if (!skip_sanity_check)
{
if (!rpmostree_deployment_sanitycheck_rpmdb (tmprootfs_dfd, overlays,
overrides_replace, cancellable, error))
return FALSE;
}
return TRUE;
}

View File

@ -30,6 +30,7 @@
#include "libglnx.h"
#include "rpmostree-scripts.h"
#include "rpmostree-rpm-util.h"
#define RPMOSTREE_MESSAGE_PREPOST SD_ID128_MAKE(42,d3,72,22,dc,a2,4a,3b,9d,30,ce,d4,bb,bc,ac,d2)
#define RPMOSTREE_MESSAGE_FILETRIGGER SD_ID128_MAKE(ef,dd,0e,4e,79,ca,45,d3,88,76,ac,45,e1,28,23,68)
@ -938,9 +939,9 @@ rpmostree_transfiletriggers_run_sync (Header hdr,
* volatile mode, but that could just as easily be a separate tool.
*/
gboolean
rpmostree_deployment_sanitycheck (int rootfs_fd,
GCancellable *cancellable,
GError **error)
rpmostree_deployment_sanitycheck_true (int rootfs_fd,
GCancellable *cancellable,
GError **error)
{
/* Used by the test suite */
if (getenv ("RPMOSTREE_SKIP_SANITYCHECK"))
@ -956,6 +957,64 @@ rpmostree_deployment_sanitycheck (int rootfs_fd,
rpmostree_bwrap_append_child_argv (bwrap, "/usr/bin/true", NULL);
if (!rpmostree_bwrap_run (bwrap, cancellable, error))
return FALSE;
sd_journal_print (LOG_INFO, "sanitycheck(/usr/bin/true) successful");
return TRUE;
}
static gboolean
verify_packages_in_sack (DnfSack *sack,
GPtrArray *pkgs,
GError **error)
{
if (!pkgs || pkgs->len == 0)
return TRUE;
for (guint i = 0; i < pkgs->len; i++)
{
DnfPackage *pkg = pkgs->pdata[i];
const char *nevra = dnf_package_get_nevra (pkg);
if (!rpmostree_sack_has_subject (sack, nevra))
return glnx_throw (error, "Didn't find package '%s'", nevra);
}
return TRUE;
}
/* Check that we can load the rpmdb. See
* https://github.com/projectatomic/rpm-ostree/issues/1566.
*
* This is split out of the one above for practical reasons: the check above runs right
* after scripts are executed to give a nicer error if the scripts did `rm -rf`.
*/
gboolean
rpmostree_deployment_sanitycheck_rpmdb (int rootfs_fd,
/* just allow two args to avoid allocating */
GPtrArray *overlays,
GPtrArray *overrides,
GCancellable *cancellable,
GError **error)
{
g_autoptr(RpmOstreeRefSack) sack = rpmostree_get_refsack_for_root (rootfs_fd, ".", error);
if (!sack)
return FALSE;
if ((overlays && overlays->len > 0) || (overrides && overrides->len > 0))
{
if (!verify_packages_in_sack (sack->sack, overlays, error) ||
!verify_packages_in_sack (sack->sack, overrides, error))
return FALSE;
}
else
{
/* OK, let's just sanity check that there are *some* packages in the rpmdb */
hy_autoquery HyQuery query = hy_query_create (sack->sack);
hy_query_filter (query, HY_PKG_REPONAME, HY_EQ, HY_SYSTEM_REPO_NAME);
g_autoptr(GPtrArray) pkgs = hy_query_run (query);
if (pkgs->len == 0)
return glnx_throw (error, "No packages found in rpmdb!");
}
sd_journal_print (LOG_INFO, "sanitycheck(rpmdb) successful");
return TRUE;
}

View File

@ -75,6 +75,13 @@ rpmostree_transfiletriggers_run_sync (Header hdr,
GError **error);
gboolean
rpmostree_deployment_sanitycheck (int rootfs_fd,
GCancellable *cancellable,
GError **error);
rpmostree_deployment_sanitycheck_true (int rootfs_fd,
GCancellable *cancellable,
GError **error);
gboolean
rpmostree_deployment_sanitycheck_rpmdb (int rootfs_fd,
GPtrArray *overlays,
GPtrArray *overrides,
GCancellable *cancellable,
GError **error);