sysext: Get verity user certs from given --root=
The verity user certs weren't looked up in the given --root= for systemd-sysext which made it fail to set up extensions with a strict image policy. Look up verity user certs from inside the --root= when we operate on images in it. The main use case where this matters is when the initrd sets up the extensions for the final system and thus systemd-sysext should do the same thing as it would do in the final system.
This commit is contained in:
@@ -2605,6 +2605,7 @@ int setup_namespace(const NamespaceParameters *p, char **reterr_path) {
|
||||
|
||||
r = dissected_image_decrypt(
|
||||
dissected_image,
|
||||
/* root= */ NULL,
|
||||
/* passphrase= */ NULL,
|
||||
p->verity,
|
||||
p->root_image_policy,
|
||||
|
||||
@@ -295,7 +295,7 @@ int bus_image_method_get_hostname(
|
||||
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");
|
||||
}
|
||||
@@ -314,7 +314,7 @@ int bus_image_method_get_machine_id(
|
||||
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");
|
||||
}
|
||||
@@ -343,7 +343,7 @@ int bus_image_method_get_machine_info(
|
||||
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");
|
||||
}
|
||||
@@ -361,7 +361,7 @@ int bus_image_method_get_os_release(
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -627,7 +627,7 @@ static int list_image_one_and_maybe_read_metadata(Manager *m, sd_varlink *link,
|
||||
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)
|
||||
|
||||
@@ -540,6 +540,7 @@ static int vl_method_mount_image(
|
||||
|
||||
r = dissected_image_decrypt(
|
||||
di,
|
||||
/* root= */ NULL,
|
||||
p.password,
|
||||
&verity,
|
||||
use_policy,
|
||||
|
||||
@@ -61,7 +61,7 @@ int bus_image_common_get_os_release(
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -2027,7 +2027,7 @@ int image_setup_pool(RuntimeScope scope, ImageClass class, bool use_btrfs_subvol
|
||||
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;
|
||||
|
||||
@@ -2153,6 +2153,7 @@ int image_read_metadata(Image *i, const ImagePolicy *image_policy, RuntimeScope
|
||||
|
||||
r = dissected_image_decrypt(
|
||||
m,
|
||||
root,
|
||||
/* passphrase= */ NULL,
|
||||
&verity,
|
||||
image_policy,
|
||||
|
||||
@@ -71,7 +71,7 @@ int image_get_pool_usage(RuntimeScope scope, ImageClass class, uint64_t *ret);
|
||||
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);
|
||||
|
||||
|
||||
@@ -3093,7 +3093,7 @@ static char* dm_deferred_remove_clean(char *name) {
|
||||
}
|
||||
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 */
|
||||
@@ -3138,7 +3138,7 @@ static int validate_signature_userspace(const VeritySettings *verity, DissectIma
|
||||
/* 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)) {
|
||||
@@ -3200,6 +3200,7 @@ static int validate_signature_userspace(const VeritySettings *verity, DissectIma
|
||||
|
||||
static int do_crypt_activate_verity(
|
||||
struct crypt_device *cd,
|
||||
const char *root,
|
||||
const char *name,
|
||||
const VeritySettings *verity,
|
||||
DissectImageFlags flags,
|
||||
@@ -3249,7 +3250,7 @@ static int do_crypt_activate_verity(
|
||||
|
||||
/* 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) {
|
||||
@@ -3309,6 +3310,7 @@ static int verity_partition(
|
||||
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,
|
||||
@@ -3394,7 +3396,7 @@ static int verity_partition(
|
||||
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.
|
||||
@@ -3488,7 +3490,7 @@ static int verity_partition(
|
||||
*/
|
||||
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);
|
||||
@@ -3508,6 +3510,7 @@ success:
|
||||
|
||||
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,
|
||||
@@ -3564,7 +3567,7 @@ int dissected_image_decrypt(
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -3597,7 +3600,7 @@ int dissected_image_decrypt_interactively(
|
||||
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)
|
||||
@@ -4862,7 +4865,8 @@ int verity_dissect_and_mount(
|
||||
|
||||
r = dissected_image_decrypt(
|
||||
dissected_image,
|
||||
NULL,
|
||||
/* root= */ NULL,
|
||||
/* passphrase= */ NULL,
|
||||
verity,
|
||||
image_policy,
|
||||
dissect_image_flags);
|
||||
|
||||
@@ -171,7 +171,7 @@ void dissected_image_close(DissectedImage *m);
|
||||
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);
|
||||
|
||||
+2
-2
@@ -1923,7 +1923,7 @@ static int merge_subprocess(
|
||||
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;
|
||||
|
||||
@@ -2199,7 +2199,7 @@ static int image_discover_and_read_metadata(ImageClass image_class, Hashmap **re
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -181,6 +181,52 @@ prepare_extension_image_raw() {
|
||||
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:?}
|
||||
|
||||
@@ -1239,6 +1285,28 @@ extension_verify_after_merge "$fake_root" "$hierarchy" -e -h
|
||||
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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user