mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
dissect/nspawn: add support for dm-verity root hash signature
Since cryptsetup 2.3.0 a new API to verify dm-verity volumes by a pkcs7 signature, with the public key in the kernel keyring, is available. Use it if libcryptsetup supports it.
This commit is contained in:
parent
035e8e50d7
commit
c2923fdcd7
6
README
6
README
@ -35,6 +35,7 @@ LICENSE:
|
|||||||
REQUIREMENTS:
|
REQUIREMENTS:
|
||||||
Linux kernel >= 3.13
|
Linux kernel >= 3.13
|
||||||
Linux kernel >= 4.2 for unified cgroup hierarchy support
|
Linux kernel >= 4.2 for unified cgroup hierarchy support
|
||||||
|
Linux kernel >= 5.4 for signed Verity images support
|
||||||
|
|
||||||
Kernel Config Options:
|
Kernel Config Options:
|
||||||
CONFIG_DEVTMPFS
|
CONFIG_DEVTMPFS
|
||||||
@ -102,6 +103,9 @@ REQUIREMENTS:
|
|||||||
CONFIG_EFIVAR_FS
|
CONFIG_EFIVAR_FS
|
||||||
CONFIG_EFI_PARTITION
|
CONFIG_EFI_PARTITION
|
||||||
|
|
||||||
|
Required for signed Verity images support:
|
||||||
|
CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG
|
||||||
|
|
||||||
We recommend to turn off Real-Time group scheduling in the
|
We recommend to turn off Real-Time group scheduling in the
|
||||||
kernel when using systemd. RT group scheduling effectively
|
kernel when using systemd. RT group scheduling effectively
|
||||||
makes RT scheduling unavailable for most userspace, since it
|
makes RT scheduling unavailable for most userspace, since it
|
||||||
@ -144,7 +148,7 @@ REQUIREMENTS:
|
|||||||
libblkid >= 2.24 (from util-linux) (optional)
|
libblkid >= 2.24 (from util-linux) (optional)
|
||||||
libkmod >= 15 (optional)
|
libkmod >= 15 (optional)
|
||||||
PAM >= 1.1.2 (optional)
|
PAM >= 1.1.2 (optional)
|
||||||
libcryptsetup (optional)
|
libcryptsetup (optional), >= 2.3.0 required for signed Verity images support
|
||||||
libaudit (optional)
|
libaudit (optional)
|
||||||
libacl (optional)
|
libacl (optional)
|
||||||
libselinux (optional)
|
libselinux (optional)
|
||||||
|
@ -304,7 +304,7 @@
|
|||||||
|
|
||||||
<para>Single file system images (i.e. file systems without a surrounding partition table) can be opened using
|
<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
|
dm-verity if the integrity data is passed using the <option>--root-hash=</option> and
|
||||||
<option>--verity-data=</option> options.</para>
|
<option>--verity-data=</option> (and optionally <option>--root-hash-sig=</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>
|
||||||
@ -399,6 +399,18 @@
|
|||||||
is read from it and automatically used, also as formatted hexadecimal characters.</para></listitem>
|
is read from it and automatically used, also as formatted hexadecimal characters.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--root-hash-sig=</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Takes a PKCS7 formatted binary signature of the <option>--root-hash=</option> option as a path
|
||||||
|
to a DER encoded signature file or as an ASCII base64 string encoding of the DER encoded signature, prefixed
|
||||||
|
by <literal>base64:</literal>. The dm-verity volume will only be opened if the signature of the root hash hex
|
||||||
|
string is valid and done by a public key present in the kernel keyring. If this option is not specified, but a
|
||||||
|
file with the <filename>.roothash.p7s</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 signature file must
|
||||||
|
not have it in its name), the signature is read from it and automatically used.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--verity-data=</option></term>
|
<term><option>--verity-data=</option></term>
|
||||||
|
|
||||||
|
@ -1035,6 +1035,8 @@ if want_libcryptsetup != 'false' and not skip_deps
|
|||||||
|
|
||||||
conf.set10('HAVE_CRYPT_SET_METADATA_SIZE',
|
conf.set10('HAVE_CRYPT_SET_METADATA_SIZE',
|
||||||
have and cc.has_function('crypt_set_metadata_size', dependencies : libcryptsetup))
|
have and cc.has_function('crypt_set_metadata_size', dependencies : libcryptsetup))
|
||||||
|
conf.set10('HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY',
|
||||||
|
have and cc.has_function('crypt_activate_by_signed_key', dependencies : libcryptsetup))
|
||||||
else
|
else
|
||||||
have = false
|
have = false
|
||||||
libcryptsetup = []
|
libcryptsetup = []
|
||||||
|
@ -71,7 +71,7 @@ _systemd_nspawn() {
|
|||||||
--pivot-root --property --private-users --network-namespace-path --network-ipvlan
|
--pivot-root --property --private-users --network-namespace-path --network-ipvlan
|
||||||
--network-veth-extra --network-zone -p --port --system-call-filter --overlay --overlay-ro
|
--network-veth-extra --network-zone -p --port --system-call-filter --overlay --overlay-ro
|
||||||
--settings --rlimit --hostname --no-new-privileges --oom-score-adjust --cpu-affinity
|
--settings --rlimit --hostname --no-new-privileges --oom-score-adjust --cpu-affinity
|
||||||
--resolv-conf --timezone'
|
--resolv-conf --timezone --root-hash-sig'
|
||||||
)
|
)
|
||||||
|
|
||||||
_init_completion || return
|
_init_completion || return
|
||||||
@ -183,6 +183,10 @@ _systemd_nspawn() {
|
|||||||
--timezone)
|
--timezone)
|
||||||
comps=$( systemd-nspawn --timezone=help 2>/dev/null )
|
comps=$( systemd-nspawn --timezone=help 2>/dev/null )
|
||||||
;;
|
;;
|
||||||
|
--root-hash-sig)
|
||||||
|
compopt -o nospace
|
||||||
|
comps=$( compgen -A file -- "$cur" )
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
||||||
return 0
|
return 0
|
||||||
|
@ -1268,7 +1268,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_decoded = NULL;
|
_cleanup_free_ void *root_hash_decoded = NULL;
|
||||||
_cleanup_free_ char *verity_data = NULL;
|
_cleanup_free_ char *verity_data = NULL, *hash_sig_path = NULL;
|
||||||
MountEntry *m = NULL, *mounts = NULL;
|
MountEntry *m = NULL, *mounts = NULL;
|
||||||
size_t n_mounts;
|
size_t n_mounts;
|
||||||
bool require_prefix = false;
|
bool require_prefix = false;
|
||||||
@ -1299,7 +1299,7 @@ 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 = 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);
|
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, &hash_sig_path);
|
||||||
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 |= root_verity || verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
|
dissect_image_flags |= root_verity || verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
|
||||||
@ -1308,7 +1308,7 @@ int setup_namespace(
|
|||||||
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_decoded, root_hash_size, root_verity ?: 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, hash_sig_path, NULL, 0, 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");
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,14 @@ static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DI
|
|||||||
static void *arg_root_hash = NULL;
|
static void *arg_root_hash = NULL;
|
||||||
static char *arg_verity_data = 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_root_hash_sig_path = NULL;
|
||||||
|
static void *arg_root_hash_sig = NULL;
|
||||||
|
static size_t arg_root_hash_sig_size = 0;
|
||||||
|
|
||||||
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_verity_data, freep);
|
||||||
|
STATIC_DESTRUCTOR_REGISTER(arg_root_hash_sig_path, freep);
|
||||||
|
STATIC_DESTRUCTOR_REGISTER(arg_root_hash_sig, freep);
|
||||||
|
|
||||||
static void help(void) {
|
static void help(void) {
|
||||||
printf("%s [OPTIONS...] IMAGE\n"
|
printf("%s [OPTIONS...] IMAGE\n"
|
||||||
@ -43,6 +48,10 @@ static void help(void) {
|
|||||||
" --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"
|
||||||
|
" --root-hash-sig=SIG Specify pkcs7 signature of root hash for verity\n"
|
||||||
|
" as a DER encoded PKCS7, either as a path to a file\n"
|
||||||
|
" or as an ASCII base64 encoded string prefixed by\n"
|
||||||
|
" 'base64:'\n"
|
||||||
" --verity-data=PATH Specify data file with hash tree for verity if it is\n"
|
" --verity-data=PATH Specify data file with hash tree for verity if it is\n"
|
||||||
" not embedded in IMAGE\n",
|
" not embedded in IMAGE\n",
|
||||||
program_invocation_short_name,
|
program_invocation_short_name,
|
||||||
@ -57,6 +66,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
ARG_ROOT_HASH,
|
ARG_ROOT_HASH,
|
||||||
ARG_FSCK,
|
ARG_FSCK,
|
||||||
ARG_VERITY_DATA,
|
ARG_VERITY_DATA,
|
||||||
|
ARG_ROOT_HASH_SIG,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
@ -68,6 +78,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
{ "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 },
|
{ "verity-data", required_argument, NULL, ARG_VERITY_DATA },
|
||||||
|
{ "root-hash-sig", required_argument, NULL, ARG_ROOT_HASH_SIG },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -140,6 +151,31 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
return r;
|
return r;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARG_ROOT_HASH_SIG: {
|
||||||
|
char *value;
|
||||||
|
|
||||||
|
if ((value = startswith(optarg, "base64:"))) {
|
||||||
|
void *p;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
|
r = unbase64mem(value, strlen(value), &p, &l);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", optarg);
|
||||||
|
|
||||||
|
free_and_replace(arg_root_hash_sig, p);
|
||||||
|
arg_root_hash_sig_size = l;
|
||||||
|
arg_root_hash_sig_path = mfree(arg_root_hash_sig_path);
|
||||||
|
} else {
|
||||||
|
r = parse_path_argument_and_warn(optarg, false, &arg_root_hash_sig_path);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
arg_root_hash_sig = mfree(arg_root_hash_sig);
|
||||||
|
arg_root_hash_sig_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ARG_FSCK:
|
case ARG_FSCK:
|
||||||
r = parse_boolean(optarg);
|
r = parse_boolean(optarg);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -202,7 +238,8 @@ static int run(int argc, char *argv[]) {
|
|||||||
return log_error_errno(r, "Failed to set up loopback device: %m");
|
return log_error_errno(r, "Failed to set up loopback device: %m");
|
||||||
|
|
||||||
r = verity_metadata_load(arg_image, NULL, 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);
|
arg_verity_data ? NULL : &arg_verity_data,
|
||||||
|
arg_root_hash_sig_path || arg_root_hash_sig ? NULL : &arg_root_hash_sig_path);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read verity artefacts 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;
|
arg_flags |= arg_verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
|
||||||
@ -279,7 +316,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_verity_data, arg_flags, &di);
|
r = dissected_image_decrypt_interactively(m, NULL, arg_root_hash, arg_root_hash_size, arg_verity_data, arg_root_hash_sig_path, arg_root_hash_sig, arg_root_hash_sig_size, arg_flags, &di);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -200,6 +200,9 @@ 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 char *arg_verity_data = NULL;
|
||||||
|
static char *arg_root_hash_sig_path = NULL;
|
||||||
|
static void *arg_root_hash_sig = NULL;
|
||||||
|
static size_t arg_root_hash_sig_size = 0;
|
||||||
static size_t arg_root_hash_size = 0;
|
static size_t arg_root_hash_size = 0;
|
||||||
static char **arg_syscall_allow_list = NULL;
|
static char **arg_syscall_allow_list = NULL;
|
||||||
static char **arg_syscall_deny_list = NULL;
|
static char **arg_syscall_deny_list = NULL;
|
||||||
@ -244,6 +247,8 @@ 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_verity_data, freep);
|
||||||
|
STATIC_DESTRUCTOR_REGISTER(arg_root_hash_sig_path, freep);
|
||||||
|
STATIC_DESTRUCTOR_REGISTER(arg_root_hash_sig, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_syscall_allow_list, strv_freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_syscall_allow_list, strv_freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_syscall_deny_list, strv_freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_syscall_deny_list, strv_freep);
|
||||||
#if HAVE_SECCOMP
|
#if HAVE_SECCOMP
|
||||||
@ -305,6 +310,10 @@ 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"
|
||||||
|
" --root-hash-sig=SIG Specify pkcs7 signature of root hash for verity\n"
|
||||||
|
" as a DER encoded PKCS7, either as a path to a file\n"
|
||||||
|
" or as an ASCII base64 encoded string prefixed by\n"
|
||||||
|
" 'base64:'\n"
|
||||||
" --verity-data=PATH Specify hash device for verity\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"
|
||||||
@ -667,6 +676,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
ARG_OCI_BUNDLE,
|
ARG_OCI_BUNDLE,
|
||||||
ARG_NO_PAGER,
|
ARG_NO_PAGER,
|
||||||
ARG_VERITY_DATA,
|
ARG_VERITY_DATA,
|
||||||
|
ARG_ROOT_HASH_SIG,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
@ -733,6 +743,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
{ "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 },
|
{ "verity-data", required_argument, NULL, ARG_VERITY_DATA },
|
||||||
|
{ "root-hash-sig", required_argument, NULL, ARG_ROOT_HASH_SIG },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1327,6 +1338,31 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
return r;
|
return r;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARG_ROOT_HASH_SIG: {
|
||||||
|
char *value;
|
||||||
|
|
||||||
|
if ((value = startswith(optarg, "base64:"))) {
|
||||||
|
void *p;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
|
r = unbase64mem(value, strlen(value), &p, &l);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", optarg);
|
||||||
|
|
||||||
|
free_and_replace(arg_root_hash_sig, p);
|
||||||
|
arg_root_hash_sig_size = l;
|
||||||
|
arg_root_hash_sig_path = mfree(arg_root_hash_sig_path);
|
||||||
|
} else {
|
||||||
|
r = parse_path_argument_and_warn(optarg, false, &arg_root_hash_sig_path);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
arg_root_hash_sig = mfree(arg_root_hash_sig);
|
||||||
|
arg_root_hash_sig_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ARG_SYSTEM_CALL_FILTER: {
|
case ARG_SYSTEM_CALL_FILTER: {
|
||||||
bool negative;
|
bool negative;
|
||||||
const char *items;
|
const char *items;
|
||||||
@ -5143,7 +5179,8 @@ static int run(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
r = verity_metadata_load(arg_image, NULL, 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);
|
arg_verity_data ? NULL : &arg_verity_data,
|
||||||
|
arg_root_hash_sig_path || arg_root_hash_sig ? NULL : &arg_root_hash_sig_path);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
|
log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
|
||||||
goto finish;
|
goto finish;
|
||||||
@ -5193,7 +5230,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, arg_verity_data, 0, &decrypted_image);
|
r = dissected_image_decrypt_interactively(dissected_image, NULL, arg_root_hash, arg_root_hash_size, arg_verity_data, arg_root_hash_sig_path, arg_root_hash_sig, arg_root_hash_sig_size, 0, &decrypted_image);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
|
@ -1223,6 +1223,9 @@ static int verity_partition(
|
|||||||
const void *root_hash,
|
const void *root_hash,
|
||||||
size_t root_hash_size,
|
size_t root_hash_size,
|
||||||
const char *verity_data,
|
const char *verity_data,
|
||||||
|
const char *root_hash_sig_path,
|
||||||
|
const void *root_hash_sig,
|
||||||
|
size_t root_hash_sig_size,
|
||||||
DissectImageFlags flags,
|
DissectImageFlags flags,
|
||||||
DecryptedImage *d) {
|
DecryptedImage *d) {
|
||||||
|
|
||||||
@ -1267,6 +1270,24 @@ static int verity_partition(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
if (root_hash_sig || root_hash_sig_path) {
|
||||||
|
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
|
||||||
|
if (root_hash_sig)
|
||||||
|
r = crypt_activate_by_signed_key(cd, name, root_hash, root_hash_size, root_hash_sig, root_hash_sig_size, CRYPT_ACTIVATE_READONLY);
|
||||||
|
else {
|
||||||
|
_cleanup_free_ char *hash_sig = NULL;
|
||||||
|
size_t hash_sig_size;
|
||||||
|
|
||||||
|
r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, &hash_sig, &hash_sig_size);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = crypt_activate_by_signed_key(cd, name, root_hash, root_hash_size, hash_sig, hash_sig_size, CRYPT_ACTIVATE_READONLY);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
r = log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "activation of verity device with signature requested, but not supported by cryptsetup due to missing crypt_activate_by_signed_key()");
|
||||||
|
#endif
|
||||||
|
} else
|
||||||
r = crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY);
|
r = crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -1287,6 +1308,9 @@ int dissected_image_decrypt(
|
|||||||
const void *root_hash,
|
const void *root_hash,
|
||||||
size_t root_hash_size,
|
size_t root_hash_size,
|
||||||
const char *verity_data,
|
const char *verity_data,
|
||||||
|
const char *root_hash_sig_path,
|
||||||
|
const void *root_hash_sig,
|
||||||
|
size_t root_hash_sig_size,
|
||||||
DissectImageFlags flags,
|
DissectImageFlags flags,
|
||||||
DecryptedImage **ret) {
|
DecryptedImage **ret) {
|
||||||
|
|
||||||
@ -1333,7 +1357,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, verity_data, flags, d);
|
r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, verity_data, root_hash_sig_path, root_hash_sig, root_hash_sig_size, flags, d);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -1359,6 +1383,9 @@ int dissected_image_decrypt_interactively(
|
|||||||
const void *root_hash,
|
const void *root_hash,
|
||||||
size_t root_hash_size,
|
size_t root_hash_size,
|
||||||
const char *verity_data,
|
const char *verity_data,
|
||||||
|
const char *root_hash_sig_path,
|
||||||
|
const void *root_hash_sig,
|
||||||
|
size_t root_hash_sig_size,
|
||||||
DissectImageFlags flags,
|
DissectImageFlags flags,
|
||||||
DecryptedImage **ret) {
|
DecryptedImage **ret) {
|
||||||
|
|
||||||
@ -1369,7 +1396,7 @@ int dissected_image_decrypt_interactively(
|
|||||||
n--;
|
n--;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
r = dissected_image_decrypt(m, passphrase, root_hash, root_hash_size, verity_data, flags, ret);
|
r = dissected_image_decrypt(m, passphrase, root_hash, root_hash_size, verity_data, root_hash_sig_path, root_hash_sig, root_hash_sig_size, flags, ret);
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
return r;
|
return r;
|
||||||
if (r == -EKEYREJECTED)
|
if (r == -EKEYREJECTED)
|
||||||
@ -1421,8 +1448,8 @@ int decrypted_image_relinquish(DecryptedImage *d) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int verity_metadata_load(const char *image, const char *root_hash_path, 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, char **ret_roothashsig) {
|
||||||
_cleanup_free_ char *verity_filename = NULL;
|
_cleanup_free_ char *verity_filename = NULL, *roothashsig_filename = NULL;
|
||||||
_cleanup_free_ void *roothash_decoded = NULL;
|
_cleanup_free_ void *roothash_decoded = NULL;
|
||||||
size_t roothash_decoded_size = 0;
|
size_t roothash_decoded_size = 0;
|
||||||
int r;
|
int r;
|
||||||
@ -1437,6 +1464,8 @@ int verity_metadata_load(const char *image, const char *root_hash_path, void **r
|
|||||||
*ret_roothash_size = 0;
|
*ret_roothash_size = 0;
|
||||||
if (ret_verity_data)
|
if (ret_verity_data)
|
||||||
*ret_verity_data = NULL;
|
*ret_verity_data = NULL;
|
||||||
|
if (ret_roothashsig)
|
||||||
|
*ret_roothashsig = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1461,6 +1490,29 @@ int verity_metadata_load(const char *image, const char *root_hash_path, void **r
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret_roothashsig) {
|
||||||
|
char *e;
|
||||||
|
|
||||||
|
/* Follow naming convention recommended by the relevant RFC:
|
||||||
|
* https://tools.ietf.org/html/rfc5751#section-3.2.1 */
|
||||||
|
roothashsig_filename = new(char, strlen(image) + STRLEN(".roothash.p7s") + 1);
|
||||||
|
if (!roothashsig_filename)
|
||||||
|
return -ENOMEM;
|
||||||
|
strcpy(roothashsig_filename, image);
|
||||||
|
e = endswith(roothashsig_filename, ".raw");
|
||||||
|
if (e)
|
||||||
|
strcpy(e, ".roothash.p7s");
|
||||||
|
else
|
||||||
|
strcat(roothashsig_filename, ".roothash.p7s");
|
||||||
|
|
||||||
|
r = access(roothashsig_filename, R_OK);
|
||||||
|
if (r < 0) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
return -errno;
|
||||||
|
roothashsig_filename = mfree(roothashsig_filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ret_roothash) {
|
if (ret_roothash) {
|
||||||
_cleanup_free_ char *text = NULL;
|
_cleanup_free_ char *text = NULL;
|
||||||
assert(ret_roothash_size);
|
assert(ret_roothash_size);
|
||||||
@ -1507,6 +1559,8 @@ int verity_metadata_load(const char *image, const char *root_hash_path, void **r
|
|||||||
}
|
}
|
||||||
if (ret_verity_data)
|
if (ret_verity_data)
|
||||||
*ret_verity_data = TAKE_PTR(verity_filename);
|
*ret_verity_data = TAKE_PTR(verity_filename);
|
||||||
|
if (roothashsig_filename)
|
||||||
|
*ret_roothashsig = TAKE_PTR(roothashsig_filename);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -87,8 +87,8 @@ int dissect_image_and_warn(int fd, const char *name, const void *root_hash, size
|
|||||||
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, const char *verity_data, 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, const char *root_hash_sig_path, const void *root_hash_sig, size_t root_hash_sig_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_decrypt_interactively(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, const char *verity_data, const char *root_hash_sig_path, const void *root_hash_sig, size_t root_hash_sig_size, 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);
|
||||||
@ -100,6 +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 verity_metadata_load(const char *image, const char *root_hash_path, 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, char **ret_roothashsig);
|
||||||
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator);
|
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator);
|
||||||
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator);
|
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator);
|
||||||
|
Loading…
Reference in New Issue
Block a user