mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-10 01:17:44 +03:00
dissect: support single-filesystem verity images with external verity hash
dm-verity support in dissect-image at the moment is restricted to GPT volumes. If the image a single-filesystem type without a partition table (eg: squashfs) and a roothash/verity file are passed, set the verity flag and mark as read-only.
This commit is contained in:
parent
b1806441bb
commit
e7cbe5cb9e
@ -302,6 +302,10 @@
|
|||||||
hash partitions are set up if the root hash for them is specified using the <option>--root-hash=</option>
|
hash partitions are set up if the root hash for them is specified using the <option>--root-hash=</option>
|
||||||
option.</para>
|
option.</para>
|
||||||
|
|
||||||
|
<para>Single file system images (i.e. file systems without a surrounding partition table) can be opened using
|
||||||
|
dm-verity if the integrity data is passed using the <option>--root-hash=</option> and
|
||||||
|
<option>--verity-data=</option> options.</para>
|
||||||
|
|
||||||
<para>Any other partitions, such as foreign partitions or swap partitions are not mounted. May not be specified
|
<para>Any other partitions, such as foreign partitions or swap partitions are not mounted. May not be specified
|
||||||
together with <option>--directory=</option>, <option>--template=</option>.</para></listitem>
|
together with <option>--directory=</option>, <option>--template=</option>.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -390,8 +394,20 @@
|
|||||||
project='man-pages'><refentrytitle>xattr</refentrytitle><manvolnum>7</manvolnum></citerefentry>), then the root
|
project='man-pages'><refentrytitle>xattr</refentrytitle><manvolnum>7</manvolnum></citerefentry>), then the root
|
||||||
hash is read from it, also as formatted hexadecimal characters. If the extended file attribute is not found (or
|
hash is read from it, also as formatted hexadecimal characters. If the extended file attribute is not found (or
|
||||||
is not supported by the underlying file system), but a file with the <filename>.roothash</filename> suffix is
|
is not supported by the underlying file system), but a file with the <filename>.roothash</filename> suffix is
|
||||||
found next to the image file, bearing otherwise the same name, the root hash is read from it and automatically
|
found next to the image file, bearing otherwise the same name (except if the image has the
|
||||||
used, also as formatted hexadecimal characters.</para></listitem>
|
<filename>.raw</filename> suffix, in which case the root hash file must not have it in its name), the root hash
|
||||||
|
is read from it and automatically used, also as formatted hexadecimal characters.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--verity-data=</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Takes the path to a data integrity (dm-verity) file. This option enables data integrity checks
|
||||||
|
using dm-verity, if a root-hash is passed and if the used image itself does not contains the integrity data.
|
||||||
|
The integrity data must be matched by the root hash. If this option is not specified, but a file with the
|
||||||
|
<filename>.verity</filename> suffix is found next to the image file, bearing otherwise the same name (except if
|
||||||
|
the image has the <filename>.raw</filename> suffix, in which case the verity data file must not have it in its name),
|
||||||
|
the verity data is read from it and automatically used.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
@ -1264,6 +1264,7 @@ int setup_namespace(
|
|||||||
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
||||||
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
||||||
_cleanup_free_ void *root_hash = NULL;
|
_cleanup_free_ void *root_hash = NULL;
|
||||||
|
_cleanup_free_ char *verity_data = NULL;
|
||||||
MountEntry *m = NULL, *mounts = NULL;
|
MountEntry *m = NULL, *mounts = NULL;
|
||||||
size_t n_mounts, root_hash_size = 0;
|
size_t n_mounts, root_hash_size = 0;
|
||||||
bool require_prefix = false;
|
bool require_prefix = false;
|
||||||
@ -1294,15 +1295,16 @@ int setup_namespace(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to create loop device for root image: %m");
|
return log_debug_errno(r, "Failed to create loop device for root image: %m");
|
||||||
|
|
||||||
r = root_hash_load(root_image, &root_hash, &root_hash_size);
|
r = verity_metadata_load(root_image, &root_hash, &root_hash_size, &verity_data);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to load root hash: %m");
|
return log_debug_errno(r, "Failed to load root hash: %m");
|
||||||
|
dissect_image_flags |= verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
|
||||||
|
|
||||||
r = dissect_image(loop_device->fd, root_hash, root_hash_size, dissect_image_flags, &dissected_image);
|
r = dissect_image(loop_device->fd, root_hash, root_hash_size, verity_data, dissect_image_flags, &dissected_image);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to dissect image: %m");
|
return log_debug_errno(r, "Failed to dissect image: %m");
|
||||||
|
|
||||||
r = dissected_image_decrypt(dissected_image, NULL, root_hash, root_hash_size, dissect_image_flags, &decrypted_image);
|
r = dissected_image_decrypt(dissected_image, NULL, root_hash, root_hash_size, verity_data, dissect_image_flags, &decrypted_image);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to decrypt dissected image: %m");
|
return log_debug_errno(r, "Failed to decrypt dissected image: %m");
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "loop-util.h"
|
#include "loop-util.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
|
#include "path-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "user-util.h"
|
#include "user-util.h"
|
||||||
@ -25,21 +26,25 @@ static const char *arg_image = NULL;
|
|||||||
static const char *arg_path = NULL;
|
static const char *arg_path = NULL;
|
||||||
static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK;
|
static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK;
|
||||||
static void *arg_root_hash = NULL;
|
static void *arg_root_hash = NULL;
|
||||||
|
static char *arg_verity_data = NULL;
|
||||||
static size_t arg_root_hash_size = 0;
|
static size_t arg_root_hash_size = 0;
|
||||||
|
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep);
|
||||||
|
STATIC_DESTRUCTOR_REGISTER(arg_verity_data, freep);
|
||||||
|
|
||||||
static void help(void) {
|
static void help(void) {
|
||||||
printf("%s [OPTIONS...] IMAGE\n"
|
printf("%s [OPTIONS...] IMAGE\n"
|
||||||
"%s [OPTIONS...] --mount IMAGE PATH\n"
|
"%s [OPTIONS...] --mount IMAGE PATH\n"
|
||||||
"Dissect a file system OS image.\n\n"
|
"Dissect a file system OS image.\n\n"
|
||||||
" -h --help Show this help\n"
|
" -h --help Show this help\n"
|
||||||
" --version Show package version\n"
|
" --version Show package version\n"
|
||||||
" -m --mount Mount the image to the specified directory\n"
|
" -m --mount Mount the image to the specified directory\n"
|
||||||
" -r --read-only Mount read-only\n"
|
" -r --read-only Mount read-only\n"
|
||||||
" --fsck=BOOL Run fsck before mounting\n"
|
" --fsck=BOOL Run fsck before mounting\n"
|
||||||
" --discard=MODE Choose 'discard' mode (disabled, loop, all, crypto)\n"
|
" --discard=MODE Choose 'discard' mode (disabled, loop, all, crypto)\n"
|
||||||
" --root-hash=HASH Specify root hash for verity\n",
|
" --root-hash=HASH Specify root hash for verity\n"
|
||||||
|
" --verity-data=PATH Specify data file with hash tree for verity if it is\n"
|
||||||
|
" not embedded in IMAGE\n",
|
||||||
program_invocation_short_name,
|
program_invocation_short_name,
|
||||||
program_invocation_short_name);
|
program_invocation_short_name);
|
||||||
}
|
}
|
||||||
@ -51,16 +56,18 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
ARG_DISCARD,
|
ARG_DISCARD,
|
||||||
ARG_ROOT_HASH,
|
ARG_ROOT_HASH,
|
||||||
ARG_FSCK,
|
ARG_FSCK,
|
||||||
|
ARG_VERITY_DATA,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "version", no_argument, NULL, ARG_VERSION },
|
{ "version", no_argument, NULL, ARG_VERSION },
|
||||||
{ "mount", no_argument, NULL, 'm' },
|
{ "mount", no_argument, NULL, 'm' },
|
||||||
{ "read-only", no_argument, NULL, 'r' },
|
{ "read-only", no_argument, NULL, 'r' },
|
||||||
{ "discard", required_argument, NULL, ARG_DISCARD },
|
{ "discard", required_argument, NULL, ARG_DISCARD },
|
||||||
{ "root-hash", required_argument, NULL, ARG_ROOT_HASH },
|
{ "root-hash", required_argument, NULL, ARG_ROOT_HASH },
|
||||||
{ "fsck", required_argument, NULL, ARG_FSCK },
|
{ "fsck", required_argument, NULL, ARG_FSCK },
|
||||||
|
{ "verity-data", required_argument, NULL, ARG_VERITY_DATA },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -127,6 +134,12 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ARG_VERITY_DATA:
|
||||||
|
r = parse_path_argument_and_warn(optarg, false, &arg_verity_data);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
break;
|
||||||
|
|
||||||
case ARG_FSCK:
|
case ARG_FSCK:
|
||||||
r = parse_boolean(optarg);
|
r = parse_boolean(optarg);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -188,13 +201,13 @@ static int run(int argc, char *argv[]) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to set up loopback device: %m");
|
return log_error_errno(r, "Failed to set up loopback device: %m");
|
||||||
|
|
||||||
if (!arg_root_hash) {
|
r = verity_metadata_load(arg_image, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
|
||||||
r = root_hash_load(arg_image, &arg_root_hash, &arg_root_hash_size);
|
arg_verity_data ? NULL : &arg_verity_data);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read root hash file for %s: %m", arg_image);
|
return log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
|
||||||
}
|
arg_flags |= arg_verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
|
||||||
|
|
||||||
r = dissect_image_and_warn(d->fd, arg_image, arg_root_hash, arg_root_hash_size, arg_flags, &m);
|
r = dissect_image_and_warn(d->fd, arg_image, arg_root_hash, arg_root_hash_size, arg_verity_data, arg_flags, &m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -205,7 +218,6 @@ static int run(int argc, char *argv[]) {
|
|||||||
|
|
||||||
for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
|
for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
|
||||||
DissectedPartition *p = m->partitions + i;
|
DissectedPartition *p = m->partitions + i;
|
||||||
int k;
|
|
||||||
|
|
||||||
if (!p->found)
|
if (!p->found)
|
||||||
continue;
|
continue;
|
||||||
@ -223,9 +235,8 @@ static int run(int argc, char *argv[]) {
|
|||||||
if (p->architecture != _ARCHITECTURE_INVALID)
|
if (p->architecture != _ARCHITECTURE_INVALID)
|
||||||
printf(" for %s", architecture_to_string(p->architecture));
|
printf(" for %s", architecture_to_string(p->architecture));
|
||||||
|
|
||||||
k = PARTITION_VERITY_OF(i);
|
if (dissected_image_can_do_verity(m, i))
|
||||||
if (k >= 0)
|
printf(" %s verity", dissected_image_has_verity(m, i) ? "with" : "without");
|
||||||
printf(" %s verity", m->partitions[k].found ? "with" : "without");
|
|
||||||
|
|
||||||
if (p->partno >= 0)
|
if (p->partno >= 0)
|
||||||
printf(" on partition #%i", p->partno);
|
printf(" on partition #%i", p->partno);
|
||||||
@ -268,7 +279,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case ACTION_MOUNT:
|
case ACTION_MOUNT:
|
||||||
r = dissected_image_decrypt_interactively(m, NULL, arg_root_hash, arg_root_hash_size, arg_flags, &di);
|
r = dissected_image_decrypt_interactively(m, NULL, arg_root_hash, arg_root_hash_size, arg_verity_data, arg_flags, &di);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -665,7 +665,7 @@ static int enumerate_partitions(dev_t devnum) {
|
|||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = dissect_image(fd, NULL, 0, DISSECT_IMAGE_GPT_ONLY|DISSECT_IMAGE_NO_UDEV, &m);
|
r = dissect_image(fd, NULL, 0, NULL, DISSECT_IMAGE_GPT_ONLY|DISSECT_IMAGE_NO_UDEV, &m);
|
||||||
if (r == -ENOPKG) {
|
if (r == -ENOPKG) {
|
||||||
log_debug_errno(r, "No suitable partition table found, ignoring.");
|
log_debug_errno(r, "No suitable partition table found, ignoring.");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -199,6 +199,7 @@ static bool arg_use_cgns = true;
|
|||||||
static unsigned long arg_clone_ns_flags = CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS;
|
static unsigned long arg_clone_ns_flags = CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS;
|
||||||
static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO|MOUNT_APPLY_TMPFS_TMP;
|
static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO|MOUNT_APPLY_TMPFS_TMP;
|
||||||
static void *arg_root_hash = NULL;
|
static void *arg_root_hash = NULL;
|
||||||
|
static char *arg_verity_data = NULL;
|
||||||
static size_t arg_root_hash_size = 0;
|
static size_t arg_root_hash_size = 0;
|
||||||
static char **arg_syscall_whitelist = NULL;
|
static char **arg_syscall_whitelist = NULL;
|
||||||
static char **arg_syscall_blacklist = NULL;
|
static char **arg_syscall_blacklist = NULL;
|
||||||
@ -242,6 +243,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_property, strv_freep);
|
|||||||
STATIC_DESTRUCTOR_REGISTER(arg_property_message, sd_bus_message_unrefp);
|
STATIC_DESTRUCTOR_REGISTER(arg_property_message, sd_bus_message_unrefp);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_parameters, strv_freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_parameters, strv_freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep);
|
||||||
|
STATIC_DESTRUCTOR_REGISTER(arg_verity_data, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_syscall_whitelist, strv_freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_syscall_whitelist, strv_freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_syscall_blacklist, strv_freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_syscall_blacklist, strv_freep);
|
||||||
#if HAVE_SECCOMP
|
#if HAVE_SECCOMP
|
||||||
@ -303,6 +305,7 @@ static int help(void) {
|
|||||||
" --read-only Mount the root directory read-only\n"
|
" --read-only Mount the root directory read-only\n"
|
||||||
" --volatile[=MODE] Run the system in volatile mode\n"
|
" --volatile[=MODE] Run the system in volatile mode\n"
|
||||||
" --root-hash=HASH Specify verity root hash for root disk image\n"
|
" --root-hash=HASH Specify verity root hash for root disk image\n"
|
||||||
|
" --verity-data=PATH Specify hash device for verity\n"
|
||||||
" --pivot-root=PATH[:PATH]\n"
|
" --pivot-root=PATH[:PATH]\n"
|
||||||
" Pivot root to given directory in the container\n\n"
|
" Pivot root to given directory in the container\n\n"
|
||||||
"%3$sExecution:%4$s\n"
|
"%3$sExecution:%4$s\n"
|
||||||
@ -663,6 +666,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
ARG_PIPE,
|
ARG_PIPE,
|
||||||
ARG_OCI_BUNDLE,
|
ARG_OCI_BUNDLE,
|
||||||
ARG_NO_PAGER,
|
ARG_NO_PAGER,
|
||||||
|
ARG_VERITY_DATA,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
@ -728,6 +732,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
{ "pipe", no_argument, NULL, ARG_PIPE },
|
{ "pipe", no_argument, NULL, ARG_PIPE },
|
||||||
{ "oci-bundle", required_argument, NULL, ARG_OCI_BUNDLE },
|
{ "oci-bundle", required_argument, NULL, ARG_OCI_BUNDLE },
|
||||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||||
|
{ "verity-data", required_argument, NULL, ARG_VERITY_DATA },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1316,6 +1321,12 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ARG_VERITY_DATA:
|
||||||
|
r = parse_path_argument_and_warn(optarg, false, &arg_verity_data);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
break;
|
||||||
|
|
||||||
case ARG_SYSTEM_CALL_FILTER: {
|
case ARG_SYSTEM_CALL_FILTER: {
|
||||||
bool negative;
|
bool negative;
|
||||||
const char *items;
|
const char *items;
|
||||||
@ -5080,6 +5091,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
DissectImageFlags dissect_image_flags = DISSECT_IMAGE_REQUIRE_ROOT | DISSECT_IMAGE_RELAX_VAR_CHECK;
|
||||||
assert(arg_image);
|
assert(arg_image);
|
||||||
assert(!arg_template);
|
assert(!arg_template);
|
||||||
|
|
||||||
@ -5129,13 +5141,13 @@ static int run(int argc, char *argv[]) {
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!arg_root_hash) {
|
r = verity_metadata_load(arg_image, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
|
||||||
r = root_hash_load(arg_image, &arg_root_hash, &arg_root_hash_size);
|
arg_verity_data ? NULL : &arg_verity_data);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error_errno(r, "Failed to load root hash file for %s: %m", arg_image);
|
log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
dissect_image_flags |= arg_verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mkdtemp(tmprootdir)) {
|
if (!mkdtemp(tmprootdir)) {
|
||||||
@ -5161,7 +5173,8 @@ static int run(int argc, char *argv[]) {
|
|||||||
loop->fd,
|
loop->fd,
|
||||||
arg_image,
|
arg_image,
|
||||||
arg_root_hash, arg_root_hash_size,
|
arg_root_hash, arg_root_hash_size,
|
||||||
DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK,
|
arg_verity_data,
|
||||||
|
dissect_image_flags,
|
||||||
&dissected_image);
|
&dissected_image);
|
||||||
if (r == -ENOPKG) {
|
if (r == -ENOPKG) {
|
||||||
/* dissected_image_and_warn() already printed a brief error message. Extend on that with more details */
|
/* dissected_image_and_warn() already printed a brief error message. Extend on that with more details */
|
||||||
@ -5179,7 +5192,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
if (!arg_root_hash && dissected_image->can_verity)
|
if (!arg_root_hash && dissected_image->can_verity)
|
||||||
log_notice("Note: image %s contains verity information, but no root hash specified! Proceeding without integrity checking.", arg_image);
|
log_notice("Note: image %s contains verity information, but no root hash specified! Proceeding without integrity checking.", arg_image);
|
||||||
|
|
||||||
r = dissected_image_decrypt_interactively(dissected_image, NULL, arg_root_hash, arg_root_hash_size, 0, &decrypted_image);
|
r = dissected_image_decrypt_interactively(dissected_image, NULL, arg_root_hash, arg_root_hash_size, arg_verity_data, 0, &decrypted_image);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
|
@ -380,7 +380,7 @@ static int portable_extract_by_path(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to create temporary directory: %m");
|
return log_debug_errno(r, "Failed to create temporary directory: %m");
|
||||||
|
|
||||||
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
|
r = dissect_image(d->fd, NULL, 0, NULL, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
|
||||||
if (r == -ENOPKG)
|
if (r == -ENOPKG)
|
||||||
sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Couldn't identify a suitable partition table or file system in '%s'.", path);
|
sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Couldn't identify a suitable partition table or file system in '%s'.", path);
|
||||||
else if (r == -EADDRNOTAVAIL)
|
else if (r == -EADDRNOTAVAIL)
|
||||||
|
@ -307,6 +307,7 @@ int dissect_image(
|
|||||||
int fd,
|
int fd,
|
||||||
const void *root_hash,
|
const void *root_hash,
|
||||||
size_t root_hash_size,
|
size_t root_hash_size,
|
||||||
|
const char *verity_data,
|
||||||
DissectImageFlags flags,
|
DissectImageFlags flags,
|
||||||
DissectedImage **ret) {
|
DissectedImage **ret) {
|
||||||
|
|
||||||
@ -329,6 +330,7 @@ int dissect_image(
|
|||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
assert(root_hash || root_hash_size == 0);
|
assert(root_hash || root_hash_size == 0);
|
||||||
|
assert(!((flags & DISSECT_IMAGE_GPT_ONLY) && (flags & DISSECT_IMAGE_NO_PARTITION_TABLE)));
|
||||||
|
|
||||||
/* Probes a disk image, and returns information about what it found in *ret.
|
/* Probes a disk image, and returns information about what it found in *ret.
|
||||||
*
|
*
|
||||||
@ -391,8 +393,9 @@ int dissect_image(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!(flags & DISSECT_IMAGE_GPT_ONLY) &&
|
if ((!(flags & DISSECT_IMAGE_GPT_ONLY) &&
|
||||||
(flags & DISSECT_IMAGE_REQUIRE_ROOT)) {
|
(flags & DISSECT_IMAGE_REQUIRE_ROOT)) ||
|
||||||
|
(flags & DISSECT_IMAGE_NO_PARTITION_TABLE)) {
|
||||||
const char *usage = NULL;
|
const char *usage = NULL;
|
||||||
|
|
||||||
(void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL);
|
(void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL);
|
||||||
@ -413,9 +416,13 @@ int dissect_image(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
m->single_file_system = true;
|
||||||
|
m->verity = root_hash && verity_data;
|
||||||
|
m->can_verity = !!verity_data;
|
||||||
|
|
||||||
m->partitions[PARTITION_ROOT] = (DissectedPartition) {
|
m->partitions[PARTITION_ROOT] = (DissectedPartition) {
|
||||||
.found = true,
|
.found = true,
|
||||||
.rw = true,
|
.rw = !m->verity,
|
||||||
.partno = -1,
|
.partno = -1,
|
||||||
.architecture = _ARCHITECTURE_INVALID,
|
.architecture = _ARCHITECTURE_INVALID,
|
||||||
.fstype = TAKE_PTR(t),
|
.fstype = TAKE_PTR(t),
|
||||||
@ -1215,6 +1222,7 @@ static int verity_partition(
|
|||||||
DissectedPartition *v,
|
DissectedPartition *v,
|
||||||
const void *root_hash,
|
const void *root_hash,
|
||||||
size_t root_hash_size,
|
size_t root_hash_size,
|
||||||
|
const char *verity_data,
|
||||||
DissectImageFlags flags,
|
DissectImageFlags flags,
|
||||||
DecryptedImage *d) {
|
DecryptedImage *d) {
|
||||||
|
|
||||||
@ -1223,18 +1231,20 @@ static int verity_partition(
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
assert(v);
|
assert(v || verity_data);
|
||||||
|
|
||||||
if (!root_hash)
|
if (!root_hash)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!m->found || !m->node || !m->fstype)
|
if (!m->found || !m->node || !m->fstype)
|
||||||
return 0;
|
return 0;
|
||||||
if (!v->found || !v->node || !v->fstype)
|
if (!verity_data) {
|
||||||
return 0;
|
if (!v->found || !v->node || !v->fstype)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (!streq(v->fstype, "DM_verity_hash"))
|
if (!streq(v->fstype, "DM_verity_hash"))
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
r = make_dm_name_and_node(m->node, "-verity", &name, &node);
|
r = make_dm_name_and_node(m->node, "-verity", &name, &node);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1243,7 +1253,7 @@ static int verity_partition(
|
|||||||
if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1))
|
if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = crypt_init(&cd, v->node);
|
r = crypt_init(&cd, verity_data ?: v->node);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -1276,6 +1286,7 @@ int dissected_image_decrypt(
|
|||||||
const char *passphrase,
|
const char *passphrase,
|
||||||
const void *root_hash,
|
const void *root_hash,
|
||||||
size_t root_hash_size,
|
size_t root_hash_size,
|
||||||
|
const char *verity_data,
|
||||||
DissectImageFlags flags,
|
DissectImageFlags flags,
|
||||||
DecryptedImage **ret) {
|
DecryptedImage **ret) {
|
||||||
|
|
||||||
@ -1322,7 +1333,7 @@ int dissected_image_decrypt(
|
|||||||
|
|
||||||
k = PARTITION_VERITY_OF(i);
|
k = PARTITION_VERITY_OF(i);
|
||||||
if (k >= 0) {
|
if (k >= 0) {
|
||||||
r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, flags, d);
|
r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, verity_data, flags, d);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -1347,6 +1358,7 @@ int dissected_image_decrypt_interactively(
|
|||||||
const char *passphrase,
|
const char *passphrase,
|
||||||
const void *root_hash,
|
const void *root_hash,
|
||||||
size_t root_hash_size,
|
size_t root_hash_size,
|
||||||
|
const char *verity_data,
|
||||||
DissectImageFlags flags,
|
DissectImageFlags flags,
|
||||||
DecryptedImage **ret) {
|
DecryptedImage **ret) {
|
||||||
|
|
||||||
@ -1357,7 +1369,7 @@ int dissected_image_decrypt_interactively(
|
|||||||
n--;
|
n--;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
r = dissected_image_decrypt(m, passphrase, root_hash, root_hash_size, flags, ret);
|
r = dissected_image_decrypt(m, passphrase, root_hash, root_hash_size, verity_data, flags, ret);
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
return r;
|
return r;
|
||||||
if (r == -EKEYREJECTED)
|
if (r == -EKEYREJECTED)
|
||||||
@ -1409,56 +1421,85 @@ int decrypted_image_relinquish(DecryptedImage *d) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int root_hash_load(const char *image, void **ret, size_t *ret_size) {
|
int verity_metadata_load(const char *image, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data) {
|
||||||
_cleanup_free_ char *text = NULL;
|
_cleanup_free_ char *verity_filename = NULL;
|
||||||
_cleanup_free_ void *k = NULL;
|
_cleanup_free_ void *roothash_decoded = NULL;
|
||||||
size_t l;
|
size_t roothash_decoded_size = 0;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(image);
|
assert(image);
|
||||||
assert(ret);
|
|
||||||
assert(ret_size);
|
|
||||||
|
|
||||||
if (is_device_path(image)) {
|
if (is_device_path(image)) {
|
||||||
/* If we are asked to load the root hash for a device node, exit early */
|
/* If we are asked to load the root hash for a device node, exit early */
|
||||||
*ret = NULL;
|
if (ret_roothash)
|
||||||
*ret_size = 0;
|
*ret_roothash = NULL;
|
||||||
|
if (ret_roothash_size)
|
||||||
|
*ret_roothash_size = 0;
|
||||||
|
if (ret_verity_data)
|
||||||
|
*ret_verity_data = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = getxattr_malloc(image, "user.verity.roothash", &text, true);
|
if (ret_verity_data) {
|
||||||
if (r < 0) {
|
char *e;
|
||||||
char *fn, *e, *n;
|
|
||||||
|
|
||||||
if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT))
|
verity_filename = new(char, strlen(image) + STRLEN(".verity") + 1);
|
||||||
return r;
|
if (!verity_filename)
|
||||||
|
return -ENOMEM;
|
||||||
fn = newa(char, strlen(image) + STRLEN(".roothash") + 1);
|
strcpy(verity_filename, image);
|
||||||
n = stpcpy(fn, image);
|
e = endswith(verity_filename, ".raw");
|
||||||
e = endswith(fn, ".raw");
|
|
||||||
if (e)
|
if (e)
|
||||||
n = e;
|
strcpy(e, ".verity");
|
||||||
|
else
|
||||||
|
strcat(verity_filename, ".verity");
|
||||||
|
|
||||||
strcpy(n, ".roothash");
|
r = access(verity_filename, F_OK);
|
||||||
|
if (r < 0) {
|
||||||
r = read_one_line_file(fn, &text);
|
if (errno != ENOENT)
|
||||||
if (r == -ENOENT) {
|
return -errno;
|
||||||
*ret = NULL;
|
verity_filename = mfree(verity_filename);
|
||||||
*ret_size = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r = unhexmem(text, strlen(text), &k, &l);
|
if (ret_roothash) {
|
||||||
if (r < 0)
|
_cleanup_free_ char *text = NULL;
|
||||||
return r;
|
assert(ret_roothash_size);
|
||||||
if (l < sizeof(sd_id128_t))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
*ret = TAKE_PTR(k);
|
r = getxattr_malloc(image, "user.verity.roothash", &text, true);
|
||||||
*ret_size = l;
|
if (r < 0) {
|
||||||
|
char *fn, *e, *n;
|
||||||
|
|
||||||
|
if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT))
|
||||||
|
return r;
|
||||||
|
|
||||||
|
fn = newa(char, strlen(image) + STRLEN(".roothash") + 1);
|
||||||
|
n = stpcpy(fn, image);
|
||||||
|
e = endswith(fn, ".raw");
|
||||||
|
if (e)
|
||||||
|
n = e;
|
||||||
|
|
||||||
|
strcpy(n, ".roothash");
|
||||||
|
|
||||||
|
r = read_one_line_file(fn, &text);
|
||||||
|
if (r < 0 && r != -ENOENT)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text) {
|
||||||
|
r = unhexmem(text, strlen(text), &roothash_decoded, &roothash_decoded_size);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (roothash_decoded_size < sizeof(sd_id128_t))
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret_roothash) {
|
||||||
|
*ret_roothash = TAKE_PTR(roothash_decoded);
|
||||||
|
*ret_roothash_size = roothash_decoded_size;
|
||||||
|
}
|
||||||
|
if (ret_verity_data)
|
||||||
|
*ret_verity_data = TAKE_PTR(verity_filename);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -1617,6 +1658,7 @@ int dissect_image_and_warn(
|
|||||||
const char *name,
|
const char *name,
|
||||||
const void *root_hash,
|
const void *root_hash,
|
||||||
size_t root_hash_size,
|
size_t root_hash_size,
|
||||||
|
const char *verity_data,
|
||||||
DissectImageFlags flags,
|
DissectImageFlags flags,
|
||||||
DissectedImage **ret) {
|
DissectedImage **ret) {
|
||||||
|
|
||||||
@ -1631,7 +1673,7 @@ int dissect_image_and_warn(
|
|||||||
name = buffer;
|
name = buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = dissect_image(fd, root_hash, root_hash_size, flags, ret);
|
r = dissect_image(fd, root_hash, root_hash_size, verity_data, flags, ret);
|
||||||
|
|
||||||
switch (r) {
|
switch (r) {
|
||||||
|
|
||||||
@ -1661,6 +1703,23 @@ int dissect_image_and_warn(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator) {
|
||||||
|
if (image->single_file_system)
|
||||||
|
return partition_designator == PARTITION_ROOT && image->can_verity;
|
||||||
|
|
||||||
|
return PARTITION_VERITY_OF(partition_designator) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator) {
|
||||||
|
int k;
|
||||||
|
|
||||||
|
if (image->single_file_system)
|
||||||
|
return partition_designator == PARTITION_ROOT && image->verity;
|
||||||
|
|
||||||
|
k = PARTITION_VERITY_OF(partition_designator);
|
||||||
|
return k >= 0 && image->partitions[k].found;
|
||||||
|
}
|
||||||
|
|
||||||
static const char *const partition_designator_table[] = {
|
static const char *const partition_designator_table[] = {
|
||||||
[PARTITION_ROOT] = "root",
|
[PARTITION_ROOT] = "root",
|
||||||
[PARTITION_ROOT_SECONDARY] = "root-secondary",
|
[PARTITION_ROOT_SECONDARY] = "root-secondary",
|
||||||
|
@ -63,12 +63,14 @@ typedef enum DissectImageFlags {
|
|||||||
DISSECT_IMAGE_NO_UDEV = 1 << 9, /* Don't wait for udev initializing things */
|
DISSECT_IMAGE_NO_UDEV = 1 << 9, /* Don't wait for udev initializing things */
|
||||||
DISSECT_IMAGE_RELAX_VAR_CHECK = 1 << 10, /* Don't insist that the UUID of /var is hashed from /etc/machine-id */
|
DISSECT_IMAGE_RELAX_VAR_CHECK = 1 << 10, /* Don't insist that the UUID of /var is hashed from /etc/machine-id */
|
||||||
DISSECT_IMAGE_FSCK = 1 << 11, /* File system check the partition before mounting (no effect when combined with DISSECT_IMAGE_READ_ONLY) */
|
DISSECT_IMAGE_FSCK = 1 << 11, /* File system check the partition before mounting (no effect when combined with DISSECT_IMAGE_READ_ONLY) */
|
||||||
|
DISSECT_IMAGE_NO_PARTITION_TABLE = 1 << 12, /* Only recognize single file system images */
|
||||||
} DissectImageFlags;
|
} DissectImageFlags;
|
||||||
|
|
||||||
struct DissectedImage {
|
struct DissectedImage {
|
||||||
bool encrypted:1;
|
bool encrypted:1;
|
||||||
bool verity:1; /* verity available and usable */
|
bool verity:1; /* verity available and usable */
|
||||||
bool can_verity:1; /* verity available, but not necessarily used */
|
bool can_verity:1; /* verity available, but not necessarily used */
|
||||||
|
bool single_file_system:1; /* MBR/GPT or single file system */
|
||||||
|
|
||||||
DissectedPartition partitions[_PARTITION_DESIGNATOR_MAX];
|
DissectedPartition partitions[_PARTITION_DESIGNATOR_MAX];
|
||||||
|
|
||||||
@ -79,14 +81,14 @@ struct DissectedImage {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int probe_filesystem(const char *node, char **ret_fstype);
|
int probe_filesystem(const char *node, char **ret_fstype);
|
||||||
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret);
|
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, const char *verity_data, DissectImageFlags flags, DissectedImage **ret);
|
||||||
int dissect_image_and_warn(int fd, const char *name, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret);
|
int dissect_image_and_warn(int fd, const char *name, const void *root_hash, size_t root_hash_size, const char *verity_data, DissectImageFlags flags, DissectedImage **ret);
|
||||||
|
|
||||||
DissectedImage* dissected_image_unref(DissectedImage *m);
|
DissectedImage* dissected_image_unref(DissectedImage *m);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
|
||||||
|
|
||||||
int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DecryptedImage **ret);
|
int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, const char *verity_data, DissectImageFlags flags, DecryptedImage **ret);
|
||||||
int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DecryptedImage **ret);
|
int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, const char *verity_data, DissectImageFlags flags, DecryptedImage **ret);
|
||||||
int dissected_image_mount(DissectedImage *m, const char *dest, uid_t uid_shift, DissectImageFlags flags);
|
int dissected_image_mount(DissectedImage *m, const char *dest, uid_t uid_shift, DissectImageFlags flags);
|
||||||
|
|
||||||
int dissected_image_acquire_metadata(DissectedImage *m);
|
int dissected_image_acquire_metadata(DissectedImage *m);
|
||||||
@ -98,4 +100,6 @@ int decrypted_image_relinquish(DecryptedImage *d);
|
|||||||
const char* partition_designator_to_string(int i) _const_;
|
const char* partition_designator_to_string(int i) _const_;
|
||||||
int partition_designator_from_string(const char *name) _pure_;
|
int partition_designator_from_string(const char *name) _pure_;
|
||||||
|
|
||||||
int root_hash_load(const char *image, void **ret, size_t *ret_size);
|
int verity_metadata_load(const char *image, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data);
|
||||||
|
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator);
|
||||||
|
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator);
|
||||||
|
@ -1171,7 +1171,7 @@ int image_read_metadata(Image *i) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
|
r = dissect_image(d->fd, NULL, 0, NULL, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ int main(int argc, char *argv[]) {
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
|
r = dissect_image(d->fd, NULL, 0, NULL, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error_errno(r, "Failed to dissect image: %m");
|
log_error_errno(r, "Failed to dissect image: %m");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
1
test/TEST-50-DISSECT/Makefile
Symbolic link
1
test/TEST-50-DISSECT/Makefile
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../TEST-01-BASIC/Makefile
|
34
test/TEST-50-DISSECT/test.sh
Executable file
34
test/TEST-50-DISSECT/test.sh
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
|
||||||
|
# ex: ts=8 sw=4 sts=4 et filetype=sh
|
||||||
|
set -e
|
||||||
|
TEST_DESCRIPTION="test systemd-dissect"
|
||||||
|
IMAGE_NAME="dissect"
|
||||||
|
TEST_NO_NSPAWN=1
|
||||||
|
|
||||||
|
. $TEST_BASE_DIR/test-functions
|
||||||
|
|
||||||
|
command -v mksquashfs >/dev/null 2>&1 || exit 0
|
||||||
|
command -v veritysetup >/dev/null 2>&1 || exit 0
|
||||||
|
|
||||||
|
# Need loop devices for systemd-dissect
|
||||||
|
test_create_image() {
|
||||||
|
create_empty_image_rootdir
|
||||||
|
|
||||||
|
# Create what will eventually be our root filesystem onto an overlay
|
||||||
|
# If some pieces are missing from the host, skip rather than fail
|
||||||
|
(
|
||||||
|
LOG_LEVEL=5
|
||||||
|
setup_basic_environment
|
||||||
|
mask_supporting_services
|
||||||
|
|
||||||
|
instmods loop =block
|
||||||
|
instmods squashfs =squashfs
|
||||||
|
instmods dm_verity =md
|
||||||
|
generate_module_dependencies
|
||||||
|
inst_binary mksquashfs
|
||||||
|
inst_binary veritysetup
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
do_test "$@" 50
|
7
test/units/testsuite-50.service
Normal file
7
test/units/testsuite-50.service
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=TEST-50-DISSECT
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStartPre=rm -f /failed /testok
|
||||||
|
ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
|
||||||
|
Type=oneshot
|
31
test/units/testsuite-50.sh
Executable file
31
test/units/testsuite-50.sh
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
|
||||||
|
# ex: ts=8 sw=4 sts=4 et filetype=sh
|
||||||
|
set -ex
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
cd /tmp
|
||||||
|
|
||||||
|
image=$(mktemp -d -t -p /tmp tmp.XXXXXX)
|
||||||
|
if [ -z "${image}" ] || [ ! -d "${image}" ]; then
|
||||||
|
echo "Could not create temporary directory with mktemp under /tmp"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p ${image}/usr/lib ${image}/etc
|
||||||
|
cp /usr/lib/os-release ${image}/usr/lib/
|
||||||
|
cp /etc/machine-id /etc/os-release ${image}/etc/
|
||||||
|
mksquashfs ${image} ${image}.raw
|
||||||
|
veritysetup format ${image}.raw ${image}.verity | grep '^Root hash:' | cut -f2 | tr -d '\n' > ${image}.roothash
|
||||||
|
|
||||||
|
/usr/lib/systemd/systemd-dissect ${image}.raw | grep -q -F "Found read-only 'root' partition of type squashfs with verity"
|
||||||
|
/usr/lib/systemd/systemd-dissect ${image}.raw | grep -q -F -f /usr/lib/os-release
|
||||||
|
|
||||||
|
mv ${image}.verity ${image}.fooverity
|
||||||
|
mv ${image}.roothash ${image}.foohash
|
||||||
|
/usr/lib/systemd/systemd-dissect ${image}.raw --root-hash=`cat ${image}.foohash` --verity-data=${image}.fooverity | grep -q -F "Found read-only 'root' partition of type squashfs with verity"
|
||||||
|
/usr/lib/systemd/systemd-dissect ${image}.raw --root-hash=`cat ${image}.foohash` --verity-data=${image}.fooverity | grep -q -F -f /usr/lib/os-release
|
||||||
|
|
||||||
|
echo OK > /testok
|
||||||
|
|
||||||
|
exit 0
|
Loading…
Reference in New Issue
Block a user