daemon: Add a sanitycheck(/bin/true) before we deploy a tree
This is a followup to https://github.com/projectatomic/rpm-ostree/pull/888 but more comprehensive; in the layering case, the sanitycheck runs after all the `%posttrans` scripts, so we'll get a consistent error message for the `rm -rf /` test. We also do the sanitycheck for the "pure ostree" case, as well as cases where we didn't actually layer packages (including `ex override remove` as well as simply regenerating an initrd). There's obviously a lot more we could do in a sanitycheck; as I say in the comment it's tempting to consider trying to boot systemd (in a fully volatile config), but for now let's do this. In the end of course the admin has rollback too. Closes: #892 Approved by: jlebon
This commit is contained in:
parent
ddc0f40355
commit
34b5a004a8
@ -32,6 +32,7 @@
|
||||
#include "rpmostree-rpm-util.h"
|
||||
#include "rpmostree-postprocess.h"
|
||||
#include "rpmostree-output.h"
|
||||
#include "rpmostree-scripts.h"
|
||||
#include "rpmostree-unpacker.h"
|
||||
|
||||
#include "ostree-repo.h"
|
||||
@ -1016,6 +1017,22 @@ rpmostree_sysroot_upgrader_deploy (RpmOstreeSysrootUpgrader *self,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
/* Also do a sanitycheck even if there's no local mutation; it's basically free
|
||||
* and might save someone in the future. The RPMOSTREE_SKIP_SANITYCHECK
|
||||
* environment variable is just used by test-basic.sh currently.
|
||||
*/
|
||||
if (!self->final_revision)
|
||||
{
|
||||
g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self->sysroot, new_deployment);
|
||||
glnx_fd_close int deployment_dfd = -1;
|
||||
if (!glnx_opendirat (ostree_sysroot_get_fd (self->sysroot), deployment_path, TRUE,
|
||||
&deployment_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!rpmostree_deployment_sanitycheck (deployment_dfd, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (self->final_revision)
|
||||
{
|
||||
/* Generate a temporary ref for the new deployment in case we are
|
||||
|
@ -177,6 +177,9 @@ rpmostree_treespec_new_from_keyfile (GKeyFile *keyfile,
|
||||
}
|
||||
add_canonicalized_string_array (&builder, "instlangs", "instlangs-all", keyfile);
|
||||
|
||||
if (g_key_file_get_boolean (keyfile, "tree", "skip-sanity-check", NULL))
|
||||
g_variant_builder_add (&builder, "{sv}", "skip-sanity-check", g_variant_new_boolean (TRUE));
|
||||
|
||||
{ gboolean documentation = TRUE;
|
||||
g_autofree char *value = g_key_file_get_value (keyfile, "tree", "documentation", NULL);
|
||||
|
||||
@ -2984,6 +2987,16 @@ rpmostree_context_assemble_tmprootfs (RpmOstreeContext *self,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 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
|
||||
*/
|
||||
|
||||
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))
|
||||
return FALSE;
|
||||
|
||||
if (have_systemctl)
|
||||
{
|
||||
if (renameat (tmprootfs_dfd, "usr/bin/systemctl.rpmostreesave",
|
||||
@ -2997,6 +3010,12 @@ rpmostree_context_assemble_tmprootfs (RpmOstreeContext *self,
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Also do a sanity check even if we have no layered packages */
|
||||
if (!rpmostree_deployment_sanitycheck (tmprootfs_dfd, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_clear_pointer (&ordering_ts, rpmtsFree);
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <systemd/sd-journal.h>
|
||||
#include "rpmostree-output.h"
|
||||
#include "rpmostree-bwrap.h"
|
||||
#include <err.h>
|
||||
@ -350,3 +351,35 @@ rpmostree_pre_run_sync (DnfPackage *pkg,
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Ensure that we can at least execute /usr/bin/true inside the new root.
|
||||
* See https://github.com/projectatomic/rpm-ostree/pull/888
|
||||
*
|
||||
* Currently at least on Fedora this will run through e.g. the dynamic linker
|
||||
* and hence some bits of glibc.
|
||||
*
|
||||
* We could consider doing more here, perhaps even starting systemd in a
|
||||
* volatile mode, but that could just as easily be a separate tool.
|
||||
*/
|
||||
gboolean
|
||||
rpmostree_deployment_sanitycheck (int rootfs_fd,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
/* Used by the test suite */
|
||||
if (getenv ("RPMOSTREE_SKIP_SANITYCHECK"))
|
||||
return TRUE;
|
||||
|
||||
GLNX_AUTO_PREFIX_ERROR ("sanitycheck", error);
|
||||
g_autoptr(RpmOstreeBwrap) bwrap =
|
||||
rpmostree_bwrap_new (rootfs_fd, RPMOSTREE_BWRAP_IMMUTABLE, error,
|
||||
"--ro-bind", "./usr/etc", "/etc",
|
||||
NULL);
|
||||
rpmostree_bwrap_append_child_argv (bwrap, "/usr/bin/true", NULL);
|
||||
if (!bwrap)
|
||||
return FALSE;
|
||||
if (!rpmostree_bwrap_run (bwrap, error))
|
||||
return FALSE;
|
||||
sd_journal_print (LOG_INFO, "sanitycheck(/usr/bin/true) successful");
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -64,3 +64,8 @@ rpmostree_pre_run_sync (DnfPackage *pkg,
|
||||
int rootfs_fd,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
rpmostree_deployment_sanitycheck (int rootfs_fd,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
@ -42,6 +42,7 @@ cat > foo.conf <<EOF
|
||||
ref=foo
|
||||
packages=foo
|
||||
repos=test-repo
|
||||
skip-sanity-check=true
|
||||
EOF
|
||||
|
||||
rpm-ostree ex container assemble foo.conf
|
||||
|
@ -61,5 +61,6 @@ EOF
|
||||
|
||||
# Tell rpm-ostree to connect to the session bus instead of system
|
||||
export RPMOSTREE_USE_SESSION_BUS=1
|
||||
export RPMOSTREE_SKIP_SANITYCHECK=1
|
||||
|
||||
exec dbus-run-session --config-file=${test_tmpdir}/session.conf $@
|
||||
|
@ -94,4 +94,4 @@ if vm_rpmostree install rmrf 2>err.txt; then
|
||||
fi
|
||||
vm_cmd test -f /home/testuser/somedata -a -f /etc/fstab -a -f /tmp/sometmpfile -a -f /var/tmp/sometmpfile
|
||||
# This is the error today, we may improve it later
|
||||
assert_file_has_content err.txt 'renameat(usr/bin/systemctl): No such file or directory'
|
||||
assert_file_has_content err.txt 'error: sanitycheck: Executing bwrap(/usr/bin/true)'
|
||||
|
Loading…
Reference in New Issue
Block a user