summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Boccassi <luca.boccassi@microsoft.com>2020-06-03 09:50:45 +0100
committerLennart Poettering <lennart@poettering.net>2020-06-23 10:50:09 +0200
commit0389f4fa81e93be298721ce699889161fbe4046b (patch)
treed360812ea22f1762eb0f1e63d6f6d663e3404031
parent6fe01ced0e081a9a1d9d484b4bd87a9ae567ae19 (diff)
downloadsystemd-0389f4fa81e93be298721ce699889161fbe4046b.tar.gz
core: add RootHash and RootVerity service parameters
Allow to explicitly pass root hash (explicitly or as a file) and verity device/file as unit options. Take precedence over implicit checks.
-rw-r--r--man/systemd.exec.xml37
-rw-r--r--src/core/dbus-execute.c71
-rw-r--r--src/core/execute.c19
-rw-r--r--src/core/execute.h4
-rw-r--r--src/core/load-fragment-gperf.gperf.m42
-rw-r--r--src/core/load-fragment.c59
-rw-r--r--src/core/load-fragment.h1
-rw-r--r--src/core/namespace.c16
-rw-r--r--src/core/namespace.h4
-rw-r--r--src/dissect/dissect.c2
-rw-r--r--src/nspawn/nspawn.c2
-rw-r--r--src/shared/bus-unit-util.c21
-rw-r--r--src/shared/dissect-image.c37
-rw-r--r--src/shared/dissect-image.h2
-rw-r--r--src/test/test-namespace.c4
-rw-r--r--src/test/test-ns.c4
-rw-r--r--test/fuzz/fuzz-unit-file/directives.service2
17 files changed, 262 insertions, 25 deletions
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index f5db55511f..aa8a3f75bc 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -146,6 +146,43 @@
</varlistentry>
<varlistentry>
+ <term><varname>RootHash=</varname></term>
+
+ <listitem><para>Takes a data integrity (dm-verity) root hash specified in hexadecimal, or the path to a file
+ containing a root hash in ASCII hexadecimal format. This option enables data integrity checks using dm-verity,
+ if the used image contains the appropriate integrity data (see above) or if <varname>RootVerity=</varname> is used.
+ The specified hash must match the root hash of integrity data, and is usually at least 256 bits (and hence 64
+ formatted hexadecimal characters) long (in case of SHA256 for example). If this option is not specified, but
+ the image file carries the <literal>user.verity.roothash</literal> extended file attribute (see <citerefentry
+ 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
+ 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 (except if the image has the
+ <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>
+
+ <xi:include href="system-only.xml" xpointer="singular"/></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>RootVerity=</varname></term>
+
+ <listitem><para>Takes the path to a data integrity (dm-verity) file. This option enables data integrity checks
+ using dm-verity, if <varname>RootImage=</varname> is used and 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>
+
+ <para>This option is supported only for disk images that contain a single file system, without an enveloping partition
+ table. Images that contain a GPT partition table should instead include both root file system and matching Verity
+ data in the same image, implementing the
+ [Discoverable Partition Specification](https://systemd.io/DISCOVERABLE_PARTITIONS)</para>
+
+ <xi:include href="system-only.xml" xpointer="singular"/></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>MountAPIVFS=</varname></term>
<listitem><para>Takes a boolean argument. If on, a private mount namespace for the unit's processes is created
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 06b6b95d69..a584895ea9 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -746,6 +746,25 @@ static int property_get_log_extra_fields(
return sd_bus_message_close_container(reply);
}
+static int property_get_root_hash(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ExecContext *c = userdata;
+
+ assert(bus);
+ assert(c);
+ assert(property);
+ assert(reply);
+
+ return sd_bus_message_append_array(reply, 'y', c->root_hash, c->root_hash_size);
+}
+
const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -788,6 +807,9 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootImage", "s", NULL, offsetof(ExecContext, root_image), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RootHash", "ay", property_get_root_hash, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RootHashPath", "s", NULL, offsetof(ExecContext, root_hash_path), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RootVerity", "s", NULL, offsetof(ExecContext, root_verity), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CoredumpFilter", "t", property_get_coredump_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1258,6 +1280,55 @@ int bus_exec_context_set_transient_property(
if (streq(name, "RootImage"))
return bus_set_transient_path(u, name, &c->root_image, message, flags, error);
+ if (streq(name, "RootHash")) {
+ const void *roothash_decoded;
+ size_t roothash_decoded_size;
+
+ r = sd_bus_message_read_array(message, 'y', &roothash_decoded, &roothash_decoded_size);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ _cleanup_free_ char *encoded = NULL;
+
+ if (roothash_decoded_size == 0) {
+ c->root_hash_path = mfree(c->root_hash_path);
+ c->root_hash = mfree(c->root_hash);
+ c->root_hash_size = 0;
+
+ unit_write_settingf(u, flags, name, "RootHash=");
+ } else {
+ _cleanup_free_ void *p;
+
+ encoded = hexmem(roothash_decoded, roothash_decoded_size);
+ if (!encoded)
+ return -ENOMEM;
+
+ p = memdup(roothash_decoded, roothash_decoded_size);
+ if (!p)
+ return -ENOMEM;
+
+ free_and_replace(c->root_hash, p);
+ c->root_hash_size = roothash_decoded_size;
+ c->root_hash_path = mfree(c->root_hash_path);
+
+ unit_write_settingf(u, flags, name, "RootHash=%s", encoded);
+ }
+ }
+
+ return 1;
+ }
+
+ if (streq(name, "RootHashPath")) {
+ c->root_hash_size = 0;
+ c->root_hash = mfree(c->root_hash);
+
+ return bus_set_transient_path(u, "RootHash", &c->root_hash_path, message, flags, error);
+ }
+
+ if (streq(name, "RootVerity"))
+ return bus_set_transient_path(u, name, &c->root_verity, message, flags, error);
+
if (streq(name, "RootDirectory"))
return bus_set_transient_path(u, name, &c->root_directory, message, flags, error);
diff --git a/src/core/execute.c b/src/core/execute.c
index aa253a5ddf..e0835f9b92 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -54,6 +54,7 @@
#include "format-util.h"
#include "fs-util.h"
#include "glob-util.h"
+#include "hexdecoct.h"
#include "io-util.h"
#include "ioprio.h"
#include "label.h"
@@ -2666,6 +2667,7 @@ static int apply_mount_namespace(
needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
context->mount_flags,
+ context->root_hash, context->root_hash_size, context->root_hash_path, context->root_verity,
DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
error_path);
@@ -4195,6 +4197,10 @@ void exec_context_done(ExecContext *c) {
c->working_directory = mfree(c->working_directory);
c->root_directory = mfree(c->root_directory);
c->root_image = mfree(c->root_image);
+ c->root_hash = mfree(c->root_hash);
+ c->root_hash_size = 0;
+ c->root_hash_path = mfree(c->root_hash_path);
+ c->root_verity = mfree(c->root_verity);
c->tty_path = mfree(c->tty_path);
c->syslog_identifier = mfree(c->syslog_identifier);
c->user = mfree(c->user);
@@ -4599,6 +4605,19 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
if (c->root_image)
fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
+ if (c->root_hash) {
+ _cleanup_free_ char *encoded = NULL;
+ encoded = hexmem(c->root_hash, c->root_hash_size);
+ if (encoded)
+ fprintf(f, "%sRootHash: %s\n", prefix, encoded);
+ }
+
+ if (c->root_hash_path)
+ fprintf(f, "%sRootHash: %s\n", prefix, c->root_hash_path);
+
+ if (c->root_verity)
+ fprintf(f, "%sRootVerity: %s\n", prefix, c->root_verity);
+
STRV_FOREACH(e, c->environment)
fprintf(f, "%sEnvironment: %s\n", prefix, *e);
diff --git a/src/core/execute.h b/src/core/execute.h
index 7e1015631f..7c9d63c5e4 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -155,7 +155,9 @@ struct ExecContext {
char **unset_environment;
struct rlimit *rlimit[_RLIMIT_MAX];
- char *working_directory, *root_directory, *root_image;
+ char *working_directory, *root_directory, *root_image, *root_verity, *root_hash_path;
+ void *root_hash;
+ size_t root_hash_size;
bool working_directory_missing_ok:1;
bool working_directory_home:1;
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 69598e8430..9cf959edd5 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -23,6 +23,8 @@ m4_define(`EXEC_CONTEXT_CONFIG_ITEMS',
`$1.WorkingDirectory, config_parse_working_directory, 0, offsetof($1, exec_context)
$1.RootDirectory, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_directory)
$1.RootImage, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_image)
+$1.RootHash, config_parse_exec_root_hash, 0, offsetof($1, exec_context)
+$1.RootVerity, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_verity)
$1.User, config_parse_user_group_compat, 0, offsetof($1, exec_context.user)
$1.Group, config_parse_user_group_compat, 0, offsetof($1, exec_context.group)
$1.SupplementaryGroups, config_parse_user_group_strv_compat, 0, offsetof($1, exec_context.supplementary_groups)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index c1a4eb96cb..54b3514924 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -29,6 +29,7 @@
#include "errno-list.h"
#include "escape.h"
#include "fd-util.h"
+#include "fileio.h"
#include "fs-util.h"
#include "hexdecoct.h"
#include "io-util.h"
@@ -1413,6 +1414,64 @@ int config_parse_exec_cpu_sched_prio(const char *unit,
return 0;
}
+int config_parse_exec_root_hash(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_free_ void *roothash_decoded = NULL;
+ ExecContext *c = data;
+ size_t roothash_decoded_size = 0;
+ int r;
+
+ assert(data);
+ assert(filename);
+ assert(line);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ /* Reset if the empty string is assigned */
+ c->root_hash_path = mfree(c->root_hash_path);
+ c->root_hash = mfree(c->root_hash);
+ c->root_hash_size = 0;
+ return 0;
+ }
+
+ if (path_is_absolute(rvalue)) {
+ /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
+ _cleanup_free_ char *p = NULL;
+
+ p = strdup(rvalue);
+ if (!p)
+ return -ENOMEM;
+
+ free_and_replace(c->root_hash_path, p);
+ c->root_hash = mfree(c->root_hash);
+ c->root_hash_size = 0;
+ return 0;
+ }
+
+ /* We have a roothash to decode, eg: RootHash=012345789abcdef */
+ r = unhexmem(rvalue, strlen(rvalue), &roothash_decoded, &roothash_decoded_size);
+ if (r < 0)
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode RootHash=, ignoring: %s", rvalue);
+ if (roothash_decoded_size < sizeof(sd_id128_t))
+ return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "RootHash= is too short, ignoring: %s", rvalue);
+
+ free_and_replace(c->root_hash, roothash_decoded);
+ c->root_hash_size = roothash_decoded_size;
+ c->root_hash_path = mfree(c->root_hash_path);
+
+ return 0;
+}
+
int config_parse_exec_cpu_affinity(const char *unit,
const char *filename,
unsigned line,
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 9c30b6f882..f0e109da3a 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -44,6 +44,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_policy);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_prio);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_affinity);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_secure_bits);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_root_hash);
CONFIG_PARSER_PROTOTYPE(config_parse_capability_set);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_mount_flags);
CONFIG_PARSER_PROTOTYPE(config_parse_timer);
diff --git a/src/core/namespace.c b/src/core/namespace.c
index 6bfc266dc0..423a47c7b8 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -1257,16 +1257,20 @@ int setup_namespace(
ProtectHome protect_home,
ProtectSystem protect_system,
unsigned long mount_flags,
+ const void *root_hash,
+ size_t root_hash_size,
+ const char *root_hash_path,
+ const char *root_verity,
DissectImageFlags dissect_image_flags,
char **error_path) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
- _cleanup_free_ void *root_hash = NULL;
+ _cleanup_free_ void *root_hash_decoded = NULL;
_cleanup_free_ char *verity_data = NULL;
MountEntry *m = NULL, *mounts = NULL;
- size_t n_mounts, root_hash_size = 0;
+ size_t n_mounts;
bool require_prefix = false;
const char *root;
int r = 0;
@@ -1295,16 +1299,16 @@ int setup_namespace(
if (r < 0)
return log_debug_errno(r, "Failed to create loop device for root image: %m");
- r = verity_metadata_load(root_image, &root_hash, &root_hash_size, &verity_data);
+ r = verity_metadata_load(root_image, root_hash_path, root_hash ? NULL : &root_hash_decoded, root_hash ? NULL : &root_hash_size, root_verity ? NULL : &verity_data);
if (r < 0)
return log_debug_errno(r, "Failed to load root hash: %m");
- dissect_image_flags |= verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
+ dissect_image_flags |= root_verity || verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
- r = dissect_image(loop_device->fd, root_hash, root_hash_size, verity_data, dissect_image_flags, &dissected_image);
+ r = dissect_image(loop_device->fd, root_hash ?: root_hash_decoded, root_hash_size, root_verity ?: verity_data, dissect_image_flags, &dissected_image);
if (r < 0)
return log_debug_errno(r, "Failed to dissect image: %m");
- r = dissected_image_decrypt(dissected_image, NULL, root_hash, root_hash_size, verity_data, dissect_image_flags, &decrypted_image);
+ r = dissected_image_decrypt(dissected_image, NULL, root_hash ?: root_hash_decoded, root_hash_size, root_verity ?: verity_data, dissect_image_flags, &decrypted_image);
if (r < 0)
return log_debug_errno(r, "Failed to decrypt dissected image: %m");
}
diff --git a/src/core/namespace.h b/src/core/namespace.h
index ef6c9bdc9b..a687be5bfd 100644
--- a/src/core/namespace.h
+++ b/src/core/namespace.h
@@ -88,6 +88,10 @@ int setup_namespace(
ProtectHome protect_home,
ProtectSystem protect_system,
unsigned long mount_flags,
+ const void *root_hash,
+ size_t root_hash_size,
+ const char *root_hash_path,
+ const char *root_verity,
DissectImageFlags dissected_image_flags,
char **error_path);
diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c
index 9ae632f226..2a8eaca5bd 100644
--- a/src/dissect/dissect.c
+++ b/src/dissect/dissect.c
@@ -201,7 +201,7 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to set up loopback device: %m");
- r = verity_metadata_load(arg_image, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
+ r = verity_metadata_load(arg_image, NULL, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
arg_verity_data ? NULL : &arg_verity_data);
if (r < 0)
return log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index f3a3ee8a17..ae6828f2bf 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -5141,7 +5141,7 @@ static int run(int argc, char *argv[]) {
goto finish;
}
- r = verity_metadata_load(arg_image, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
+ r = verity_metadata_load(arg_image, NULL, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
arg_verity_data ? NULL : &arg_verity_data);
if (r < 0) {
log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 4b1145a6ba..e539d03149 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -13,6 +13,7 @@
#include "escape.h"
#include "exec-util.h"
#include "exit-status.h"
+#include "fileio.h"
#include "hexdecoct.h"
#include "hostname-util.h"
#include "in-addr-util.h"
@@ -24,6 +25,7 @@
#include "nsflags.h"
#include "numa-util.h"
#include "parse-util.h"
+#include "path-util.h"
#include "process-util.h"
#include "rlimit-util.h"
#include "securebits-util.h"
@@ -849,6 +851,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
"ProtectHome",
"SELinuxContext",
"RootImage",
+ "RootVerity",
"RuntimeDirectoryPreserve",
"Personality",
"KeyringMode",
@@ -1415,6 +1418,24 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
return 1;
}
+ if (streq(field, "RootHash")) {
+ _cleanup_free_ void *roothash_decoded = NULL;
+ size_t roothash_decoded_size = 0;
+
+ /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
+ if (path_is_absolute(eq))
+ return bus_append_string(m, "RootHashPath", eq);
+
+ /* We have a roothash to decode, eg: RootHash=012345789abcdef */
+ r = unhexmem(eq, strlen(eq), &roothash_decoded, &roothash_decoded_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
+ if (roothash_decoded_size < sizeof(sd_id128_t))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short: %m", eq);
+
+ return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
+ }
+
return 0;
}
diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c
index 2c8a5d85bf..e576518c6b 100644
--- a/src/shared/dissect-image.c
+++ b/src/shared/dissect-image.c
@@ -1421,7 +1421,7 @@ int decrypted_image_relinquish(DecryptedImage *d) {
return 0;
}
-int verity_metadata_load(const char *image, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data) {
+int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data) {
_cleanup_free_ char *verity_filename = NULL;
_cleanup_free_ void *roothash_decoded = NULL;
size_t roothash_decoded_size = 0;
@@ -1465,24 +1465,31 @@ int verity_metadata_load(const char *image, void **ret_roothash, size_t *ret_roo
_cleanup_free_ char *text = NULL;
assert(ret_roothash_size);
- r = getxattr_malloc(image, "user.verity.roothash", &text, true);
- if (r < 0) {
- char *fn, *e, *n;
-
- if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT))
+ if (root_hash_path) {
+ /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
+ r = read_one_line_file(root_hash_path, &text);
+ if (r < 0)
return r;
+ } else {
+ r = getxattr_malloc(image, "user.verity.roothash", &text, true);
+ 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;
+ fn = newa(char, strlen(image) + STRLEN(".roothash") + 1);
+ n = stpcpy(fn, image);
+ e = endswith(fn, ".raw");
+ if (e)
+ n = e;
- strcpy(n, ".roothash");
+ strcpy(n, ".roothash");
- r = read_one_line_file(fn, &text);
- if (r < 0 && r != -ENOENT)
- return r;
+ r = read_one_line_file(fn, &text);
+ if (r < 0 && r != -ENOENT)
+ return r;
+ }
}
if (text) {
diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h
index 92d223cfec..6a53b94948 100644
--- a/src/shared/dissect-image.h
+++ b/src/shared/dissect-image.h
@@ -100,6 +100,6 @@ int decrypted_image_relinquish(DecryptedImage *d);
const char* partition_designator_to_string(int i) _const_;
int partition_designator_from_string(const char *name) _pure_;
-int verity_metadata_load(const char *image, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data);
+int verity_metadata_load(const char *image, const char *root_hash_path, 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);
diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c
index f2bfc6c62b..d0b4ec2764 100644
--- a/src/test/test-namespace.c
+++ b/src/test/test-namespace.c
@@ -152,6 +152,10 @@ static void test_protect_kernel_logs(void) {
PROTECT_HOME_NO,
PROTECT_SYSTEM_NO,
0,
+ NULL,
+ 0,
+ NULL,
+ NULL,
0,
NULL);
assert_se(r == 0);
diff --git a/src/test/test-ns.c b/src/test/test-ns.c
index cf8b08ba9b..ba2c2ed53b 100644
--- a/src/test/test-ns.c
+++ b/src/test/test-ns.c
@@ -76,6 +76,10 @@ int main(int argc, char *argv[]) {
PROTECT_HOME_NO,
PROTECT_SYSTEM_NO,
0,
+ NULL,
+ 0,
+ NULL,
+ NULL,
0,
NULL);
if (r < 0) {
diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service
index 7435d7abec..492d2a033b 100644
--- a/test/fuzz/fuzz-unit-file/directives.service
+++ b/test/fuzz/fuzz-unit-file/directives.service
@@ -196,6 +196,8 @@ ReusePort=
RootDirectory=
RootDirectoryStartOnly=
RootImage=
+RootHash=
+RootVerity=
RuntimeMaxSec=
SELinuxContextFromNet=
SecureBits=