r = dissected_image_decrypt(
dissected_image,
+ /* root= */ NULL,
/* passphrase= */ NULL,
p->verity,
p->root_image_policy,
int r;
if (!image->metadata_valid) {
- r = image_read_metadata(image, &image_policy_container, m->runtime_scope);
+ r = image_read_metadata(image, /* root= */ NULL, &image_policy_container, m->runtime_scope);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
}
int r;
if (!image->metadata_valid) {
- r = image_read_metadata(image, &image_policy_container, m->runtime_scope);
+ r = image_read_metadata(image, /* root= */ NULL, &image_policy_container, m->runtime_scope);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
}
int r;
if (!image->metadata_valid) {
- r = image_read_metadata(image, &image_policy_container, m->runtime_scope);
+ r = image_read_metadata(image, /* root= */ NULL, &image_policy_container, m->runtime_scope);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
}
int r;
if (!image->metadata_valid) {
- r = image_read_metadata(image, &image_policy_container, m->runtime_scope);
+ r = image_read_metadata(image, /* root= */ NULL, &image_policy_container, m->runtime_scope);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
}
assert(image);
if (should_acquire_metadata(am) && !image->metadata_valid) {
- r = image_read_metadata(image, &image_policy_container, m->runtime_scope);
+ r = image_read_metadata(image, /* root= */ NULL, &image_policy_container, m->runtime_scope);
if (r < 0 && am != ACQUIRE_METADATA_GRACEFUL)
return log_debug_errno(r, "Failed to read image metadata: %m");
if (r < 0)
r = dissected_image_decrypt(
di,
+ /* root= */ NULL,
p.password,
&verity,
use_policy,
return 1;
if (!image->metadata_valid) {
- r = image_read_metadata(image, &image_policy_service, m->runtime_scope);
+ r = image_read_metadata(image, /* root= */ NULL, &image_policy_service, m->runtime_scope);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
}
return 0;
}
-int image_read_metadata(Image *i, const ImagePolicy *image_policy, RuntimeScope scope) {
+int image_read_metadata(Image *i, const char *root, const ImagePolicy *image_policy, RuntimeScope scope) {
_cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
int r;
r = dissected_image_decrypt(
m,
+ root,
/* passphrase= */ NULL,
&verity,
image_policy,
int image_get_pool_limit(RuntimeScope scope, ImageClass class, uint64_t *ret);
int image_setup_pool(RuntimeScope scope, ImageClass class, bool use_btrfs_subvol, bool use_btrfs_quota);
-int image_read_metadata(Image *i, const ImagePolicy *image_policy, RuntimeScope scope);
+int image_read_metadata(Image *i, const char *root, const ImagePolicy *image_policy, RuntimeScope scope);
bool image_in_search_path(RuntimeScope scope, ImageClass class, const char *root, const char *image);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(char *, dm_deferred_remove_clean);
-static int validate_signature_userspace(const VeritySettings *verity, DissectImageFlags flags) {
+static int validate_signature_userspace(const VeritySettings *verity, const char *root, DissectImageFlags flags) {
int r;
/* Returns > 0 if signature checks out, == 0 if not, < 0 on unexpected errors */
/* Because installing a signature certificate into the kernel chain is so messy, let's optionally do
* userspace validation. */
- r = conf_files_list_nulstr(&certs, ".crt", NULL, CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, CONF_PATHS_NULSTR("verity.d"));
+ r = conf_files_list_nulstr(&certs, ".crt", root, CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, CONF_PATHS_NULSTR("verity.d"));
if (r < 0)
return log_debug_errno(r, "Failed to enumerate certificates: %m");
if (strv_isempty(certs)) {
static int do_crypt_activate_verity(
struct crypt_device *cd,
+ const char *root,
const char *name,
const VeritySettings *verity,
DissectImageFlags flags,
/* Preferably propagate the original kernel error, so that the fallback logic can work,
* as the device-mapper is finicky around concurrent activations of the same volume */
- k = validate_signature_userspace(verity, flags);
+ k = validate_signature_userspace(verity, root, flags);
if (k < 0)
return k;
if (k == 0) {
PartitionDesignator designator,
DissectedPartition *m, /* data partition */
DissectedPartition *v, /* verity partition */
+ const char *root, /* The root to get user verity certs from (for a sysext) */
const VeritySettings *verity,
DissectImageFlags flags,
PartitionPolicyFlags policy_flags,
goto check; /* The device already exists. Let's check it. */
/* The symlink to the device node does not exist yet. Assume not activated, and let's activate it. */
- r = do_crypt_activate_verity(cd, name, verity, flags, policy_flags);
+ r = do_crypt_activate_verity(cd, root, name, verity, flags, policy_flags);
if (r >= 0)
goto try_open; /* The device is activated. Let's open it. */
/* libdevmapper can return EINVAL when the device is already in the activation stage.
*/
sym_crypt_free(cd);
cd = NULL;
- return verity_partition(designator, m, v, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, policy_flags, d);
+ return verity_partition(designator, m, v, root, verity, flags & ~DISSECT_IMAGE_VERITY_SHARE, policy_flags, d);
}
return log_debug_errno(SYNTHETIC_ERRNO(EBUSY), "All attempts to activate verity device %s failed.", name);
int dissected_image_decrypt(
DissectedImage *m,
+ const char *root, /* The root to get user verity certs from (for a sysext) */
const char *passphrase,
const VeritySettings *verity,
const ImagePolicy *policy,
k = partition_verity_hash_of(i);
if (k >= 0) {
- r = verity_partition(i, p, m->partitions + k, verity, flags, fl, d);
+ r = verity_partition(i, p, m->partitions + k, root, verity, flags, fl, d);
if (r < 0)
return r;
}
n--;
for (;;) {
- r = dissected_image_decrypt(m, passphrase, verity, image_policy, flags);
+ r = dissected_image_decrypt(m, /* root= */ NULL, passphrase, verity, image_policy, flags);
if (r >= 0)
return r;
if (r == -EKEYREJECTED)
r = dissected_image_decrypt(
dissected_image,
- NULL,
+ /* root= */ NULL,
+ /* passphrase= */ NULL,
verity,
image_policy,
dissect_image_flags);
DissectedImage* dissected_image_unref(DissectedImage *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
-int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const VeritySettings *verity, const ImagePolicy *image_policy, DissectImageFlags flags);
+int dissected_image_decrypt(DissectedImage *m, const char *root, const char *passphrase, const VeritySettings *verity, const ImagePolicy *image_policy, DissectImageFlags flags);
int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const VeritySettings *verity, const ImagePolicy *image_policy, DissectImageFlags flags);
int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift, uid_t uid_range, int userns_fd, DissectImageFlags flags);
int dissected_image_mount_and_warn(DissectedImage *m, const char *where, uid_t uid_shift, uid_t uid_range, int userns_fd, DissectImageFlags flags);
if (r < 0)
return r;
- r = dissected_image_decrypt(m, /* passphrase= */ NULL, &verity_settings, pick_image_policy(img), flags);
+ r = dissected_image_decrypt(m, arg_root, /* passphrase= */ NULL, &verity_settings, pick_image_policy(img), flags);
if (r < 0)
return r;
return log_error_errno(r, "Failed to discover images: %m");
HASHMAP_FOREACH(img, images) {
- r = image_read_metadata(img, image_class_info[image_class].default_image_policy, RUNTIME_SCOPE_SYSTEM);
+ r = image_read_metadata(img, arg_root, image_class_info[image_class].default_image_policy, RUNTIME_SCOPE_SYSTEM);
if (r < 0)
return log_error_errno(r, "Failed to read metadata for image %s: %m", img->name);
}
prepend_trap "rm -rf ${ext_dir@Q}.raw"
}
+prepare_extension_image_raw_verity() {
+ local root=${1:-}
+ local hierarchy=${2:?}
+ local ext_dir ext_release name tmpcrt
+
+ name="test-extension"
+ ext_dir="$root/var/lib/extensions/$name"
+ ext_release="$ext_dir/usr/lib/extension-release.d/extension-release.$name"
+ tmpcrt=$(mktemp --directory "/tmp/test-sysext.crt.XXXXXXXXXX")
+
+ prepend_trap "rm -rf ${ext_dir@Q} ${ext_dir@Q}.raw '$root/etc/verity.d/test-ext.crt' '$tmpcrt'"
+
+ mkdir -p "${ext_release%/*}"
+ echo "ID=_any" >"$ext_release"
+ mkdir -p "$ext_dir/$hierarchy"
+ touch "$ext_dir$hierarchy/preexisting-file-in-extension-image"
+ tee >"$tmpcrt/verity.openssl.cnf" <<EOF
+[ req ]
+prompt = no
+distinguished_name = req_distinguished_name
+[ req_distinguished_name ]
+C = DE
+ST = Test State
+L = Test Locality
+O = Org Name
+OU = Org Unit Name
+CN = Common Name
+emailAddress = test@email.com
+EOF
+ openssl req \
+ -config "$tmpcrt/verity.openssl.cnf" \
+ -new -x509 \
+ -newkey rsa:1024 \
+ -keyout "$tmpcrt/test-ext.key" \
+ -out "$tmpcrt/test-ext.crt" \
+ -days 365 \
+ -nodes
+ systemd-repart --make-ddi=sysext \
+ --private-key="$tmpcrt/test-ext.key" --certificate="$tmpcrt/test-ext.crt" \
+ --copy-source="$ext_dir" "$ext_dir.raw"
+ rm -rf "$ext_dir"
+ mkdir -p "$root/etc/verity.d"
+ mv "$tmpcrt/test-ext.crt" "$root/etc/verity.d/"
+ rm -rf "$tmpcrt"
+}
+
prepare_extension_mutable_dir() {
local dir=${1:?}
run_systemd_sysext "$fake_root" unmerge
)
+( init_trap
+: "Check if verity user certs get loaded from --root="
+fake_root=${roots_dir:+"$roots_dir/verity-user-cert-from-root"}
+hierarchy=/opt
+
+# On OpenSUSE Tumbleweed EROFS is not supported
+if [ -e /usr/lib/modprobe.d/60-blacklist_fs-erofs.conf ]; then
+ echo >&2 "Skipping test due to missing erofs support"
+ exit 0
+fi
+
+prepare_root "$fake_root" "$hierarchy"
+prepare_extension_image_raw_verity "$fake_root" "$hierarchy"
+prepare_read_only_hierarchy "$fake_root" "$hierarchy"
+
+run_systemd_sysext "$fake_root" merge --image-policy=root=signed+absent:usr=signed+absent
+extension_verify_after_merge "$fake_root" "$hierarchy" -e -h
+
+run_systemd_sysext "$fake_root" unmerge
+extension_verify_after_unmerge "$fake_root" "$hierarchy" -h
+)
+
} # End of run_sysext_tests