summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS24
-rw-r--r--man/crypttab.xml8
-rw-r--r--man/loader.conf.xml7
-rw-r--r--man/systemd-cryptenroll.xml28
-rw-r--r--meson_options.txt2
-rw-r--r--src/analyze/test-verify.c8
-rw-r--r--src/basic/hmac.h2
-rw-r--r--src/boot/efi/boot.c5
-rw-r--r--src/boot/efi/cpio.c20
-rw-r--r--src/boot/efi/cpio.h4
-rw-r--r--src/boot/efi/measure.c20
-rw-r--r--src/boot/efi/measure.h20
-rw-r--r--src/boot/efi/meson.build1
-rw-r--r--src/boot/efi/stub.c9
-rw-r--r--src/boot/efi/test-bcd.c3
-rw-r--r--src/boot/efi/util.h7
-rw-r--r--src/busctl/test-busctl-introspect.c12
-rw-r--r--src/cryptenroll/cryptenroll-tpm2.c85
-rw-r--r--src/cryptenroll/cryptenroll-tpm2.h4
-rw-r--r--src/cryptenroll/cryptenroll.c15
-rw-r--r--src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c18
-rw-r--r--src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c32
-rw-r--r--src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h6
-rw-r--r--src/cryptsetup/cryptsetup-tpm2.c108
-rw-r--r--src/cryptsetup/cryptsetup-tpm2.h16
-rw-r--r--src/cryptsetup/cryptsetup.c27
-rw-r--r--src/fundamental/sha256.h2
-rw-r--r--src/journal/test-journal-config.c9
-rw-r--r--src/journal/test-journal-interleaving.c29
-rw-r--r--src/journal/test-journal-syslog.c69
-rw-r--r--src/journal/test-journal.c28
-rw-r--r--src/libsystemd-network/test-dhcp6-client.c37
-rw-r--r--src/libsystemd-network/test-ndisc-ra.c24
-rw-r--r--src/libsystemd-network/test-ndisc-rs.c20
-rw-r--r--src/libsystemd-network/test-sd-dhcp-lease.c23
-rw-r--r--src/libsystemd/sd-bus/test-bus-address.c14
-rw-r--r--src/libsystemd/sd-bus/test-bus-error.c24
-rw-r--r--src/libsystemd/sd-bus/test-bus-gvariant.c24
-rw-r--r--src/libsystemd/sd-bus/test-bus-introspect.c18
-rw-r--r--src/libsystemd/sd-device/test-device-util.c11
-rw-r--r--src/libsystemd/sd-device/test-sd-device.c28
-rw-r--r--src/libsystemd/sd-event/test-event.c57
-rw-r--r--src/libsystemd/sd-journal/test-audit-type.c8
-rw-r--r--src/libsystemd/sd-journal/test-journal-send.c15
-rw-r--r--src/libsystemd/sd-login/test-login.c23
-rw-r--r--src/locale/test-keymap-util.c35
-rw-r--r--src/login/test-login-shared.c12
-rw-r--r--src/network/test-networkd-address.c12
-rw-r--r--src/network/test-networkd-conf.c27
-rw-r--r--src/partition/repart.c4
-rw-r--r--src/resolve/test-dnssec.c39
-rw-r--r--src/resolve/test-resolved-etc-hosts.c25
-rw-r--r--src/resolve/test-resolved-packet.c10
-rw-r--r--src/shared/creds-util.c2
-rw-r--r--src/shared/tpm2-util.c81
-rw-r--r--src/shared/tpm2-util.h14
-rw-r--r--src/shutdown/test-umount.c26
-rw-r--r--src/timesync/test-timesync.c10
-rw-r--r--src/udev/fido_id/test-fido-id-desc.c15
-rw-r--r--src/udev/test-udev-builtin.c10
-rw-r--r--src/udev/test-udev-netlink.c12
-rw-r--r--src/udev/test-udev-node.c10
-rw-r--r--src/xdg-autostart-generator/test-xdg-autostart.c19
-rw-r--r--test/TEST-70-TPM2/Makefile6
-rwxr-xr-xtest/TEST-70-TPM2/test.sh40
-rw-r--r--test/test-functions2
-rw-r--r--test/units/testsuite-70.service7
-rwxr-xr-xtest/units/testsuite-70.sh48
68 files changed, 853 insertions, 567 deletions
diff --git a/NEWS b/NEWS
index 248cc0fdb4..a1d9447bad 100644
--- a/NEWS
+++ b/NEWS
@@ -52,6 +52,17 @@ CHANGES WITH 251:
or ID field of /etc/os-release or another suitable identifier before
deploying the image.
+ * sd-boot gained a new *experimental* setting "reboot-for-bitlocker" in
+ loader.conf that implements booting Microsoft Windows from the
+ sd-boot in a way that first reboots the system, to reset the TPM
+ PCRs. This improves compatibility with BitLocker's TPM use, as the
+ PCRs will only record the Windows boot process, and not sd-boot
+ itself, thus retaining the PCR measurements not involving
+ sd-boot. Note that this feature is experimental for now, and is
+ likely going to be generalized, renamed and removed in its current
+ form in a future release, without retaining compatibility with its
+ current implementation.
+
* The --make-machine-id-directory= switch to bootctl has been replaced
by --make-entry-directory=, given that the entry directory is not
necessarily named after the machine ID, but after some other suitable
@@ -109,6 +120,19 @@ CHANGES WITH 251:
250. For newer kernels, non-x86 systems, or older x86 systems,
there should be no visible changes.
+ * sd-boot will now measure the kernel command line into TPM PCR 12
+ rather than PCR 8. This improves usefulness of the measurements on
+ sytems where sd-boot is chainloaded from Grub. Grub measures all
+ commands its executes into PCR 8, which makes it very hard to use
+ reasonably, hence separate ourselves from that and use PCR 12
+ instead, which is already what certain Ubuntu editions use it for. To
+ retain compatibility with systems running older systemd systems a new
+ Meson option 'efi-tpm-pcr-compat' has been added (which defaults to
+ false). If enabled, the measurement is done twice: into the new-style
+ PCR 12 *and* the old-style PCR 8. It's strongly advised to migrate
+ all users to PCR 12 for this purpose in the long run, as we intend to
+ remove this compatibility feature again in two year's time.
+
CHANGES WITH 250:
* Support for encrypted and authenticated credentials has been added.
diff --git a/man/crypttab.xml b/man/crypttab.xml
index ac5c6ef666..22411166a8 100644
--- a/man/crypttab.xml
+++ b/man/crypttab.xml
@@ -678,6 +678,14 @@
</varlistentry>
<varlistentry>
+ <term><option>tpm2-pin=</option></term>
+
+ <listitem><para>Takes a boolean argument, defaults to <literal>false</literal>. Controls whether
+ TPM2 volume unlocking is bound to a PIN in addition to PCRs. Similarly, this option is only useful
+ when TPM2 enrollment metadata is not available.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>token-timeout=</option></term>
<listitem><para>Specifies how long to wait at most for configured security devices (i.e. FIDO2,
diff --git a/man/loader.conf.xml b/man/loader.conf.xml
index caff44aa1e..e5453c7dcd 100644
--- a/man/loader.conf.xml
+++ b/man/loader.conf.xml
@@ -206,8 +206,11 @@
<varlistentry>
<term>reboot-for-bitlocker</term>
- <listitem><para>Work around BitLocker requiring a recovery key when the boot loader was
- updated (enabled by default).</para>
+ <listitem><para>Caveat: This feature is experimental, and is likely to be changed (or removed in its
+ current form) in a future version of systemd.</para>
+
+ <para>Work around BitLocker requiring a recovery key when the boot loader was
+ updated (disabled by default).</para>
<para>Try to detect BitLocker encrypted drives along with an active TPM. If both are found
and Windows Boot Manager is selected in the boot menu, set the <literal>BootNext</literal>
diff --git a/man/systemd-cryptenroll.xml b/man/systemd-cryptenroll.xml
index d5fdb54cdd..02f932edfb 100644
--- a/man/systemd-cryptenroll.xml
+++ b/man/systemd-cryptenroll.xml
@@ -214,6 +214,8 @@
<!-- See: https://github.com/rhboot/shim/blob/main/README.tpm -->
<!-- See: https://www.gnu.org/software/grub/manual/grub/html_node/Measured-Boot.html -->
<!-- See: https://sourceforge.net/p/linux-ima/wiki/Home/ -->
+ <!-- See: https://github.com/tianocore-docs/edk2-TrustedBootChain/blob/main/4_Other_Trusted_Boot_Chains.md -->
+ <!-- See: https://wiki.archlinux.org/title/Trusted_Platform_Module#Accessing_PCR_registers -->
<tgroup cols='2' align='left' colsep='1' rowsep='1'>
<colspec colname="pcr" />
@@ -267,14 +269,14 @@
<entry>Secure boot state; changes when UEFI SecureBoot mode is enabled/disabled, or firmware certificates (PK, KEK, db, dbx, …) changes. The shim project will measure most of its (non-MOK) certificates and SBAT data into this PCR.</entry>
</row>
+ <!-- Grub measures all its commands and the kernel command line into PCR 8… -->
+ <!-- Grub measures all files it reads (including kernel image, initrd, …) into PCR 9… -->
+
<row>
- <entry>8</entry>
+ <entry>12</entry>
<entry><citerefentry><refentrytitle>sd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> measures the kernel command line into this PCR.</entry>
- <!-- Grub measures all its commands and the kernel command line into PCR 8 too… -->
</row>
- <!-- Grub measures all files it reads (including kernel image, initrd, …) into PCR 9… -->
-
<row>
<entry>10</entry>
<entry>The IMA project measures its runtime state into this PCR.</entry>
@@ -300,6 +302,24 @@
</varlistentry>
<varlistentry>
+ <term><option>--tpm2-with-pin=</option><replaceable>BOOL</replaceable></term>
+
+ <listitem><para>When enrolling a TPM2 device, controls whether to require the user to enter a PIN
+ when unlocking the volume in addition to PCR binding, based on TPM2 policy authentication. Defaults
+ to <literal>no</literal>. Despite being called PIN, any character can be used, not just numbers.
+ </para>
+
+ <para>Note that incorrect PIN entry when unlocking increments the
+ TPM dictionary attack lockout mechanism, and may lock out users for a prolonged time, depending on
+ its configuration. The lockout mechanism is a global property of the TPM,
+ <command>systemd-cryptenroll</command> does not control or configure the lockout mechanism. You may
+ use tpm2-tss tools to inspect or configure the dictionary attack lockout, with
+ <citerefentry><refentrytitle>tpm2_getcap</refentrytitle><manvolnum>1</manvolnum></citerefentry> and
+ <citerefentry><refentrytitle>tpm2_dictionarylockout</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ commands, respectively.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--wipe-slot=</option><arg rep="repeat">SLOT</arg></term>
<listitem><para>Wipes one or more LUKS2 key slots. Takes a comma separated list of numeric slot
diff --git a/meson_options.txt b/meson_options.txt
index 5d635748d5..284109cadf 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -426,6 +426,8 @@ option('efi-libdir', type : 'string',
description : 'path to the EFI lib directory')
option('efi-includedir', type : 'string', value : '/usr/include/efi',
description : 'path to the EFI header directory')
+option('efi-tpm-pcr-compat', type : 'boolean', value : 'false',
+ description : 'Measure kernel command line also into TPM PCR 8 (in addition to 12)')
option('sbat-distro', type : 'string', value : 'auto',
description : 'SBAT distribution ID, e.g. fedora, or auto for autodetection')
option('sbat-distro-generation', type : 'integer', value : 1,
diff --git a/src/analyze/test-verify.c b/src/analyze/test-verify.c
index f8c0bd9786..d37e54bca6 100644
--- a/src/analyze/test-verify.c
+++ b/src/analyze/test-verify.c
@@ -3,7 +3,7 @@
#include "analyze-verify-util.h"
#include "tests.h"
-static void test_verify_nonexistent(void) {
+TEST(verify_nonexistent) {
/* Negative cases */
assert_se(verify_executable(NULL, &(ExecCommand) {.flags = EXEC_COMMAND_IGNORE_FAILURE, .path = (char*) "/non/existent"}, NULL) == 0);
assert_se(verify_executable(NULL, &(ExecCommand) {.path = (char*) "/non/existent"}, NULL) < 0);
@@ -13,8 +13,4 @@ static void test_verify_nonexistent(void) {
assert_se(verify_executable(NULL, &(ExecCommand) {.flags = EXEC_COMMAND_IGNORE_FAILURE, .path = (char*) "/bin/echo"}, NULL) == 0);
}
-int main(int argc, char *argv[]) {
- test_setup_logging(LOG_DEBUG);
-
- test_verify_nonexistent();
-}
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/basic/hmac.h b/src/basic/hmac.h
index a5682c439f..e58c1838a3 100644
--- a/src/basic/hmac.h
+++ b/src/basic/hmac.h
@@ -4,7 +4,7 @@
#include <stdint.h>
#include <stdlib.h>
-#define SHA256_DIGEST_SIZE 32
+#include "sha256.h"
/* Unoptimized implementation based on FIPS 198. 'res' has to be allocated by
* the caller. Prefer external OpenSSL functions, and use this only when
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index f6706c68fc..82954ddac1 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -1549,7 +1549,7 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
.editor = TRUE,
.auto_entries = TRUE,
.auto_firmware = TRUE,
- .reboot_for_bitlocker = TRUE,
+ .reboot_for_bitlocker = FALSE,
.random_seed_mode = RANDOM_SEED_WITH_SYSTEM_TOKEN,
.idx_default_efivar = IDX_INVALID,
.console_mode = CONSOLE_MODE_KEEP,
@@ -1983,6 +1983,9 @@ static EFI_STATUS boot_windows_bitlocker(void) {
UINTN n_handles;
EFI_STATUS err;
+ // FIXME: Experimental for now. Should be generalized, and become a per-entry option that can be
+ // enabled independently of BitLocker, and without a BootXXXX entry pre-existing.
+
/* BitLocker key cannot be sealed without a TPM present. */
if (!tpm_present())
return EFI_NOT_FOUND;
diff --git a/src/boot/efi/cpio.c b/src/boot/efi/cpio.c
index 2855c4119b..14957130be 100644
--- a/src/boot/efi/cpio.c
+++ b/src/boot/efi/cpio.c
@@ -311,7 +311,8 @@ EFI_STATUS pack_cpio(
const CHAR8 *target_dir_prefix,
UINT32 dir_mode,
UINT32 access_mode,
- UINTN tpm_pcr,
+ const UINT32 tpm_pcr[],
+ UINTN n_tpm_pcr,
const CHAR16 *tpm_description,
void **ret_buffer,
UINTN *ret_buffer_size) {
@@ -328,6 +329,7 @@ EFI_STATUS pack_cpio(
assert(loaded_image);
assert(target_dir_prefix);
+ assert(tpm_pcr || n_tpm_pcr == 0);
assert(ret_buffer);
assert(ret_buffer_size);
@@ -449,13 +451,15 @@ EFI_STATUS pack_cpio(
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to pack cpio trailer: %r");
- err = tpm_log_event(
- tpm_pcr,
- POINTER_TO_PHYSICAL_ADDRESS(buffer),
- buffer_size,
- tpm_description);
- if (EFI_ERROR(err))
- log_error_stall(L"Unable to add initrd TPM measurement for PCR %u (%s), ignoring: %r", tpm_pcr, tpm_description, err);
+ for (UINTN i = 0; i < n_tpm_pcr; i++) {
+ err = tpm_log_event(
+ tpm_pcr[i],
+ POINTER_TO_PHYSICAL_ADDRESS(buffer),
+ buffer_size,
+ tpm_description);
+ if (EFI_ERROR(err))
+ log_error_stall(L"Unable to add initrd TPM measurement for PCR %u (%s), ignoring: %r", tpm_pcr[i], tpm_description, err);
+ }
*ret_buffer = TAKE_PTR(buffer);
*ret_buffer_size = buffer_size;
diff --git a/src/boot/efi/cpio.h b/src/boot/efi/cpio.h
index a272d28929..5f6698fd12 100644
--- a/src/boot/efi/cpio.h
+++ b/src/boot/efi/cpio.h
@@ -10,8 +10,8 @@ EFI_STATUS pack_cpio(
const CHAR8 *target_dir_prefix,
UINT32 dir_mode,
UINT32 access_mode,
- UINTN tpm_pcr,
+ const UINT32 tpm_pcr[],
+ UINTN n_tpm_pcr,
const CHAR16 *tpm_description,
void **ret_buffer,
UINTN *ret_buffer_size);
-
diff --git a/src/boot/efi/measure.c b/src/boot/efi/measure.c
index 992acde527..da4fd18ea8 100644
--- a/src/boot/efi/measure.c
+++ b/src/boot/efi/measure.c
@@ -139,12 +139,16 @@ BOOLEAN tpm_present(void) {
return tcg2_interface_check() || tcg1_interface_check();
}
-EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) {
+EFI_STATUS tpm_log_event(UINT32 pcrindex, EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) {
EFI_TCG *tpm1;
EFI_TCG2 *tpm2;
assert(description);
+ /* PCR disabled */
+ if (pcrindex == UINT32_MAX)
+ return EFI_SUCCESS;
+
tpm2 = tcg2_interface_check();
if (tpm2)
return tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description);
@@ -162,11 +166,15 @@ EFI_STATUS tpm_log_load_options(const CHAR16 *load_options) {
/* Measures a load options string into the TPM2, i.e. the kernel command line */
- err = tpm_log_event(TPM_PCR_INDEX_KERNEL_PARAMETERS,
- POINTER_TO_PHYSICAL_ADDRESS(load_options),
- StrSize(load_options), load_options);
- if (EFI_ERROR(err))
- return log_error_status_stall(err, L"Unable to add load options (i.e. kernel command) line measurement: %r", err);
+ for (UINTN i = 0; i < 2; i++) {
+ UINT32 pcr = i == 0 ? TPM_PCR_INDEX_KERNEL_PARAMETERS : TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT;
+
+ err = tpm_log_event(pcr,
+ POINTER_TO_PHYSICAL_ADDRESS(load_options),
+ StrSize(load_options), load_options);
+ if (EFI_ERROR(err))
+ return log_error_status_stall(err, L"Unable to add load options (i.e. kernel command) line measurement to PCR %u: %r", pcr, err);
+ }
return EFI_SUCCESS;
}
diff --git a/src/boot/efi/measure.h b/src/boot/efi/measure.h
index ffa4924562..7a817b22d8 100644
--- a/src/boot/efi/measure.h
+++ b/src/boot/efi/measure.h
@@ -3,10 +3,24 @@
#include <efi.h>
+/* This TPM PCR is where we extend the kernel command line and any passed credentials here. */
+#define TPM_PCR_INDEX_KERNEL_PARAMETERS 12U
+
+/* We used to write the the kernel command line/credentials into PCR 8, in systemd <= 250. Let's provide for
+ * some compatibility. (Remove in 2023!) */
+#if EFI_TPM_PCR_COMPAT
+#define TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT 8U
+#else
+#define TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT UINT32_MAX
+#endif
+
+/* This TPM PCR is where most Linux infrastructure extends the initrd binary images into, and so do we. */
+#define TPM_PCR_INDEX_INITRD 4U
+
#if ENABLE_TPM
BOOLEAN tpm_present(void);
-EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description);
+EFI_STATUS tpm_log_event(UINT32 pcrindex, EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description);
EFI_STATUS tpm_log_load_options(const CHAR16 *cmdline);
#else
@@ -14,9 +28,11 @@ EFI_STATUS tpm_log_load_options(const CHAR16 *cmdline);
static inline BOOLEAN tpm_present(void) {
return FALSE;
}
-static inline EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) {
+
+static inline EFI_STATUS tpm_log_event(UINT32 pcrindex, EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) {
return EFI_SUCCESS;
}
+
static inline EFI_STATUS tpm_log_load_options(const CHAR16 *cmdline) {
return EFI_SUCCESS;
}
diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build
index f6004e47ec..ffee98bbb8 100644
--- a/src/boot/efi/meson.build
+++ b/src/boot/efi/meson.build
@@ -104,6 +104,7 @@ conf.set_quoted('EFI_MACHINE_TYPE_NAME', efi_arch[0])
efi_conf = configuration_data()
efi_conf.set_quoted('EFI_MACHINE_TYPE_NAME', efi_arch[0])
efi_conf.set10('ENABLE_TPM', get_option('tpm'))
+efi_conf.set10('EFI_TPM_PCR_COMPAT', get_option('efi-tpm-pcr-compat'))
foreach ctype : ['color-normal', 'color-entry', 'color-highlight', 'color-edit']
c = get_option('efi-' + ctype).split(',')
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index 22554a4860..73d06de7f1 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -234,7 +234,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
(const CHAR8*) ".extra/credentials",
/* dir_mode= */ 0500,
/* access_mode= */ 0400,
- /* tpm_pcr= */ TPM_PCR_INDEX_KERNEL_PARAMETERS,
+ /* tpm_pcr= */ (UINT32[]) { TPM_PCR_INDEX_KERNEL_PARAMETERS, TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT },
+ /* n_tpm_pcr= */ 2,
L"Credentials initrd",
&credential_initrd,
&credential_initrd_size);
@@ -245,7 +246,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
(const CHAR8*) ".extra/global_credentials",
/* dir_mode= */ 0500,
/* access_mode= */ 0400,
- /* tpm_pcr= */ TPM_PCR_INDEX_KERNEL_PARAMETERS,
+ /* tpm_pcr= */ (UINT32[]) { TPM_PCR_INDEX_KERNEL_PARAMETERS, TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT },
+ /* n_tpm_pcr= */ 2,
L"Global credentials initrd",
&global_credential_initrd,
&global_credential_initrd_size);
@@ -256,7 +258,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
(const CHAR8*) ".extra/sysext",
/* dir_mode= */ 0555,
/* access_mode= */ 0444,
- /* tpm_pcr= */ TPM_PCR_INDEX_INITRD,
+ /* tpm_pcr= */ (UINT32[]) { TPM_PCR_INDEX_INITRD },
+ /* n_tpm_pcr= */ 1,
L"System extension initrd",
&sysext_initrd,
&sysext_initrd_size);
diff --git a/src/boot/efi/test-bcd.c b/src/boot/efi/test-bcd.c
index 5d3d6c2c40..d04d1ee45a 100644
--- a/src/boot/efi/test-bcd.c
+++ b/src/boot/efi/test-bcd.c
@@ -39,8 +39,7 @@ static void test_get_bcd_title_one(
}
TEST(get_bcd_title) {
- const char16_t win10[] = { 'W', 'i', 'n', 'd', 'o', 'w', 's', ' ', '1', '0', '\0' };
- test_get_bcd_title_one("test-bcd/win10.bcd.zst", win10, sizeof(win10));
+ test_get_bcd_title_one("test-bcd/win10.bcd.zst", u"Windows 10", sizeof(u"Windows 10"));
test_get_bcd_title_one("test-bcd/description-bad-type.bcd.zst", NULL, 0);
test_get_bcd_title_one("test-bcd/description-empty.bcd.zst", NULL, 0);
diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h
index 33b17d04fb..93dd2da566 100644
--- a/src/boot/efi/util.h
+++ b/src/boot/efi/util.h
@@ -6,13 +6,6 @@
#include "string-util-fundamental.h"
-/* This TPM PCR is where most Linux infrastructure extends the kernel command line into, and so do we. We also extend
- * any passed credentials here. */
-#define TPM_PCR_INDEX_KERNEL_PARAMETERS 8
-
-/* This TPM PCR is where most Linux infrastructure extends the initrd binary images into, and so do we. */
-#define TPM_PCR_INDEX_INITRD 4
-
#define offsetof(type, member) __builtin_offsetof(type, member)
#define UINTN_MAX (~(UINTN)0)
diff --git a/src/busctl/test-busctl-introspect.c b/src/busctl/test-busctl-introspect.c
index 216a9a3c3b..d0800d2360 100644
--- a/src/busctl/test-busctl-introspect.c
+++ b/src/busctl/test-busctl-introspect.c
@@ -313,7 +313,7 @@ static int on_path(const char *path, void *userdata) {
return 0;
}
-static void test_introspect_on_path(void) {
+TEST(introspect_on_path) {
static const XMLIntrospectOps ops = {
.on_path = on_path,
};
@@ -321,8 +321,6 @@ static void test_introspect_on_path(void) {
_cleanup_set_free_ Set *paths = NULL;
_cleanup_free_ char **l = NULL;
- log_info("/* %s */", __func__);
-
assert_se(set_put_strdup(&paths, "/") > 0);
log_debug("/* parse_xml_introspect(\"/\") */");
@@ -363,10 +361,4 @@ static void test_introspect_on_path(void) {
assert_se(strv_equal(l, expected));
}
-int main(int argc, char *argv[]) {
- test_setup_logging(LOG_DEBUG);
-
- test_introspect_on_path();
-
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/cryptenroll/cryptenroll-tpm2.c b/src/cryptenroll/cryptenroll-tpm2.c
index 801014af11..e8c64dd753 100644
--- a/src/cryptenroll/cryptenroll-tpm2.c
+++ b/src/cryptenroll/cryptenroll-tpm2.c
@@ -1,7 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
+#include "ask-password-api.h"
#include "cryptenroll-tpm2.h"
+#include "env-util.h"
#include "hexdecoct.h"
#include "json.h"
#include "memory-util.h"
@@ -58,11 +60,78 @@ static int search_policy_hash(
return -ENOENT; /* Not found */
}
+static int get_pin(char **ret_pin_str, TPM2Flags *ret_flags) {
+ _cleanup_free_ char *pin_str = NULL;
+ int r;
+ TPM2Flags flags = 0;
+
+ assert(ret_pin_str);
+ assert(ret_flags);
+
+ r = getenv_steal_erase("NEWPIN", &pin_str);
+ if (r < 0)
+ return log_error_errno(r, "Failed to acquire PIN from environment: %m");
+ if (r > 0)
+ flags |= TPM2_FLAGS_USE_PIN;
+ else {
+ for (size_t i = 5;; i--) {
+ _cleanup_strv_free_erase_ char **pin = NULL, **pin2 = NULL;
+
+ if (i <= 0)
+ return log_error_errno(
+ SYNTHETIC_ERRNO(ENOKEY), "Too many attempts, giving up.");
+
+ pin = strv_free_erase(pin);
+ r = ask_password_auto(
+ "Please enter TPM2 PIN:",
+ "drive-harddisk",
+ NULL,
+ "tpm2-pin",
+ "cryptenroll.tpm2-pin",
+ USEC_INFINITY,
+ 0,
+ &pin);
+ if (r < 0)
+ return log_error_errno(r, "Failed to ask for user pin: %m");
+ assert(strv_length(pin) == 1);
+
+ r = ask_password_auto(
+ "Please enter TPM2 PIN (repeat):",
+ "drive-harddisk",
+ NULL,
+ "tpm2-pin",
+ "cryptenroll.tpm2-pin",
+ USEC_INFINITY,
+ 0,
+ &pin2);
+ if (r < 0)
+ return log_error_errno(r, "Failed to ask for user pin: %m");
+ assert(strv_length(pin) == 1);
+
+ if (strv_equal(pin, pin2)) {
+ pin_str = strdup(*pin);
+ if (!pin_str)
+ return log_oom();
+ flags |= TPM2_FLAGS_USE_PIN;
+ break;
+ }
+
+ log_error("PINs didn't match, please try again!");
+ }
+ }
+
+ *ret_flags = flags;
+ *ret_pin_str = TAKE_PTR(pin_str);
+
+ return 0;
+}
+
int enroll_tpm2(struct crypt_device *cd,
const void *volume_key,
size_t volume_key_size,
const char *device,
- uint32_t pcr_mask) {
+ uint32_t pcr_mask,
+ bool use_pin) {
_cleanup_(erase_and_freep) void *secret = NULL, *secret2 = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
@@ -71,7 +140,9 @@ int enroll_tpm2(struct crypt_device *cd,
_cleanup_free_ void *blob = NULL, *hash = NULL;
uint16_t pcr_bank, primary_alg;
const char *node;
+ _cleanup_(erase_and_freep) char *pin_str = NULL;
int r, keyslot;
+ TPM2Flags flags = 0;
assert(cd);
assert(volume_key);
@@ -80,7 +151,13 @@ int enroll_tpm2(struct crypt_device *cd,
assert_se(node = crypt_get_device_name(cd));
- r = tpm2_seal(device, pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank, &primary_alg);
+ if (use_pin) {
+ r = get_pin(&pin_str, &flags);
+ if (r < 0)
+ return r;
+ }
+
+ r = tpm2_seal(device, pcr_mask, pin_str, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank, &primary_alg);
if (r < 0)
return r;
@@ -97,7 +174,7 @@ int enroll_tpm2(struct crypt_device *cd,
/* Quick verification that everything is in order, we are not in a hurry after all. */
log_debug("Unsealing for verification...");
- r = tpm2_unseal(device, pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, &secret2, &secret2_size);
+ r = tpm2_unseal(device, pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, pin_str, &secret2, &secret2_size);
if (r < 0)
return r;
@@ -123,7 +200,7 @@ int enroll_tpm2(struct crypt_device *cd,
if (keyslot < 0)
return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node);
- r = tpm2_make_luks2_json(keyslot, pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, &v);
+ r = tpm2_make_luks2_json(keyslot, pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, flags, &v);
if (r < 0)
return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m");
diff --git a/src/cryptenroll/cryptenroll-tpm2.h b/src/cryptenroll/cryptenroll-tpm2.h
index d5dd1b0003..742f49b8d5 100644
--- a/src/cryptenroll/cryptenroll-tpm2.h
+++ b/src/cryptenroll/cryptenroll-tpm2.h
@@ -7,9 +7,9 @@
#include "log.h"
#if HAVE_TPM2
-int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t pcr_mask);
+int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t pcr_mask, bool use_pin);
#else
-static inline int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t pcr_mask) {
+static inline int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t pcr_mask, bool use_pin) {
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"TPM2 key enrollment not supported.");
}
diff --git a/src/cryptenroll/cryptenroll.c b/src/cryptenroll/cryptenroll.c
index e13f5b7ac8..2fd6d9080e 100644
--- a/src/cryptenroll/cryptenroll.c
+++ b/src/cryptenroll/cryptenroll.c
@@ -32,6 +32,7 @@ static char *arg_pkcs11_token_uri = NULL;
static char *arg_fido2_device = NULL;
static char *arg_tpm2_device = NULL;
static uint32_t arg_tpm2_pcr_mask = UINT32_MAX;
+static bool arg_tpm2_pin = false;
static char *arg_node = NULL;
static int *arg_wipe_slots = NULL;
static size_t arg_n_wipe_slots = 0;
@@ -100,6 +101,8 @@ static int help(void) {
" Enroll a TPM2 device\n"
" --tpm2-pcrs=PCR1+PCR2+PCR3+…\n"
" Specify TPM2 PCRs to seal against\n"
+ " --tpm2-with-pin=BOOL\n"
+ " Whether to require entering a PIN to unlock the volume\n"
" --wipe-slot=SLOT1,SLOT2,…\n"
" Wipe specified slots\n"
"\nSee the %s for details.\n",
@@ -121,6 +124,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_FIDO2_DEVICE,
ARG_TPM2_DEVICE,
ARG_TPM2_PCRS,
+ ARG_TPM2_PIN,
ARG_WIPE_SLOT,
ARG_FIDO2_WITH_PIN,
ARG_FIDO2_WITH_UP,
@@ -139,6 +143,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "fido2-with-user-verification", required_argument, NULL, ARG_FIDO2_WITH_UV },
{ "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE },
{ "tpm2-pcrs", required_argument, NULL, ARG_TPM2_PCRS },
+ { "tpm2-with-pin", required_argument, NULL, ARG_TPM2_PIN },
{ "wipe-slot", required_argument, NULL, ARG_WIPE_SLOT },
{}
};
@@ -301,6 +306,14 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
+ case ARG_TPM2_PIN: {
+ r = parse_boolean_argument("--tpm2-with-pin=", optarg, &arg_tpm2_pin);
+ if (r < 0)
+ return r;
+
+ break;
+ }
+
case ARG_WIPE_SLOT: {
const char *p = optarg;
@@ -558,7 +571,7 @@ static int run(int argc, char *argv[]) {
break;
case ENROLL_TPM2:
- slot = enroll_tpm2(cd, vk, vks, arg_tpm2_device, arg_tpm2_pcr_mask);
+ slot = enroll_tpm2(cd, vk, vks, arg_tpm2_device, arg_tpm2_pcr_mask, arg_tpm2_pin);
break;
case _ENROLL_TYPE_INVALID:
diff --git a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c
index e2d28a5dda..23df974999 100644
--- a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c
+++ b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c
@@ -6,8 +6,10 @@
#include "cryptsetup-token.h"
#include "cryptsetup-token-util.h"
#include "hexdecoct.h"
+#include "json.h"
#include "luks2-tpm2.h"
#include "memory-util.h"
+#include "strv.h"
#include "tpm2-util.h"
#include "version.h"
@@ -78,7 +80,8 @@ _public_ int cryptsetup_token_open(
if (usrptr)
params = *(systemd_tpm2_plugin_params *)usrptr;
- r = parse_luks2_tpm2_data(json, params.search_pcr_mask, &pcr_mask, &pcr_bank, &primary_alg, &base64_blob, &hex_policy_hash);
+ TPM2Flags flags = 0;
+ r = parse_luks2_tpm2_data(json, params.search_pcr_mask, &pcr_mask, &pcr_bank, &primary_alg, &base64_blob, &hex_policy_hash, &flags);
if (r < 0)
return log_debug_open_error(cd, r);
@@ -101,6 +104,7 @@ _public_ int cryptsetup_token_open(
blob_size,
policy_hash,
policy_hash_size,
+ flags,
&decrypted_key,
&decrypted_key_size);
if (r < 0)
@@ -135,6 +139,7 @@ _public_ void cryptsetup_token_dump(
const char *json /* validated 'systemd-tpm2' token if cryptsetup_token_validate is defined */) {
int r;
+ TPM2Flags flags = 0;
uint32_t pcr_mask;
uint16_t pcr_bank, primary_alg;
size_t decoded_blob_size;
@@ -144,7 +149,7 @@ _public_ void cryptsetup_token_dump(
assert(json);
- r = parse_luks2_tpm2_data(json, UINT32_MAX, &pcr_mask, &pcr_bank, &primary_alg, &base64_blob, &hex_policy_hash);
+ r = parse_luks2_tpm2_data(json, UINT32_MAX, &pcr_mask, &pcr_bank, &primary_alg, &base64_blob, &hex_policy_hash, &flags);
if (r < 0)
return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " metadata: %m.");
@@ -171,6 +176,7 @@ _public_ void cryptsetup_token_dump(
crypt_log(cd, "\ttpm2-primary-alg: %s\n", strna(tpm2_primary_alg_to_string(primary_alg)));
crypt_log(cd, "\ttpm2-blob: %s\n", blob_str);
crypt_log(cd, "\ttpm2-policy-hash:" CRYPT_DUMP_LINE_SEP "%s\n", policy_hash_str);
+ crypt_log(cd, "\ttpm2-pin: %s\n", true_false(flags & TPM2_FLAGS_USE_PIN));
}
/*
@@ -268,5 +274,13 @@ _public_ int cryptsetup_token_validate(
if (r < 0)
return crypt_log_debug_errno(cd, r, "Invalid base64 data in 'tpm2-policy-hash' field: %m");
+ w = json_variant_by_key(v, "tpm2-pin");
+ if (w) {
+ if (!json_variant_is_boolean(w)) {
+ crypt_log_debug(cd, "TPM2 PIN policy is not a boolean.");
+ return 1;
+ }
+ }
+
return 0;
}
diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
index 3d39dfa884..0d6e4bc0f8 100644
--- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
+++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
@@ -1,11 +1,15 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
+#include "ask-password-api.h"
+#include "env-util.h"
#include "hexdecoct.h"
#include "json.h"
+#include "log.h"
#include "luks2-tpm2.h"
#include "parse-util.h"
#include "random-util.h"
+#include "strv.h"
#include "tpm2-util.h"
int acquire_luks2_key(
@@ -17,10 +21,12 @@ int acquire_luks2_key(
size_t key_data_size,
const void *policy_hash,
size_t policy_hash_size,
+ TPM2Flags flags,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size) {
_cleanup_free_ char *auto_device = NULL;
+ _cleanup_(erase_and_freep) char *pin_str = NULL;
int r;
assert(ret_decrypted_key);
@@ -36,12 +42,22 @@ int acquire_luks2_key(
device = auto_device;
}
+ r = getenv_steal_erase("PIN", &pin_str);
+ if (r < 0)
+ return log_error_errno(r, "Failed to acquire PIN from environment: %m");
+ if (!r) {
+ /* PIN entry is not supported by plugin, let it fallback, possibly to sd-cryptsetup's
+ * internal handling. */
+ if (flags & TPM2_FLAGS_USE_PIN)
+ return -EOPNOTSUPP;
+ }
+
return tpm2_unseal(
device,
pcr_mask, pcr_bank,
primary_alg,
key_data, key_data_size,
- policy_hash, policy_hash_size,
+ policy_hash, policy_hash_size, pin_str,
ret_decrypted_key, ret_decrypted_key_size);
}
@@ -53,7 +69,8 @@ int parse_luks2_tpm2_data(
uint16_t *ret_pcr_bank,
uint16_t *ret_primary_alg,
char **ret_base64_blob,
- char **ret_hex_policy_hash) {
+ char **ret_hex_policy_hash,
+ TPM2Flags *ret_flags) {
int r;
JsonVariant *w, *e;
@@ -61,6 +78,7 @@ int parse_luks2_tpm2_data(
uint16_t pcr_bank = UINT16_MAX, primary_alg = TPM2_ALG_ECC;
_cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+ TPM2Flags flags = 0;
assert(json);
assert(ret_pcr_mask);
@@ -138,11 +156,21 @@ int parse_luks2_tpm2_data(
if (!hex_policy_hash)
return -ENOMEM;
+ w = json_variant_by_key(v, "tpm2-pin");
+ if (w) {
+ if (!json_variant_is_boolean(w))
+ return -EINVAL;
+
+ if (json_variant_boolean(w))
+ flags |= TPM2_FLAGS_USE_PIN;
+ }
+
*ret_pcr_mask = pcr_mask;
*ret_pcr_bank = pcr_bank;
*ret_primary_alg = primary_alg;
*ret_base64_blob = TAKE_PTR(base64_blob);
*ret_hex_policy_hash = TAKE_PTR(hex_policy_hash);
+ *ret_flags = flags;
return 0;
}
diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h
index 0c93ea82cc..34c93216ee 100644
--- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h
+++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h
@@ -2,6 +2,8 @@
#pragma once
+#include "tpm2-util.h"
+
struct crypt_device;
int acquire_luks2_key(
@@ -13,6 +15,7 @@ int acquire_luks2_key(
size_t key_data_size,
const void *policy_hash,
size_t policy_hash_size,
+ TPM2Flags flags,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size);
@@ -23,4 +26,5 @@ int parse_luks2_tpm2_data(
uint16_t *ret_pcr_bank,
uint16_t *ret_primary_alg,
char **ret_base64_blob,
- char **ret_hex_policy_hash);
+ char **ret_hex_policy_hash,
+ TPM2Flags *ret_flags);
diff --git a/src/cryptsetup/cryptsetup-tpm2.c b/src/cryptsetup/cryptsetup-tpm2.c
index cb139518a7..b84d64def8 100644
--- a/src/cryptsetup/cryptsetup-tpm2.c
+++ b/src/cryptsetup/cryptsetup-tpm2.c
@@ -1,7 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
+#include "ask-password-api.h"
#include "cryptsetup-tpm2.h"
+#include "env-util.h"
#include "fileio.h"
#include "hexdecoct.h"
#include "json.h"
@@ -9,6 +11,47 @@
#include "random-util.h"
#include "tpm2-util.h"
+static int get_pin(usec_t until, AskPasswordFlags ask_password_flags, bool headless, char **ret_pin_str) {
+ _cleanup_free_ char *pin_str = NULL;
+ _cleanup_strv_free_erase_ char **pin = NULL;
+ int r;
+
+ assert(ret_pin_str);
+
+ r = getenv_steal_erase("PIN", &pin_str);
+ if (r < 0)
+ return log_error_errno(r, "Failed to acquire PIN from environment: %m");
+ if (!r) {
+ if (headless)
+ return log_error_errno(
+ SYNTHETIC_ERRNO(ENOPKG),
+ "PIN querying disabled via 'headless' option. "
+ "Use the '$PIN' environment variable.");
+
+ pin = strv_free_erase(pin);
+ r = ask_password_auto(
+ "Please enter TPM2 PIN:",
+ "drive-harddisk",
+ NULL,
+ "tpm2-pin",
+ "cryptsetup.tpm2-pin",
+ until,
+ ask_password_flags,
+ &pin);
+ if (r < 0)
+ return log_error_errno(r, "Failed to ask for user pin: %m");
+ assert(strv_length(pin) == 1);
+
+ pin_str = strdup(pin[0]);
+ if (!pin_str)
+ return log_oom();
+ }
+
+ *ret_pin_str = TAKE_PTR(pin_str);
+
+ return r;
+}
+
int acquire_tpm2_key(
const char *volume_name,
const char *device,
@@ -22,6 +65,10 @@ int acquire_tpm2_key(
size_t key_data_size,
const void *policy_hash,
size_t policy_hash_size,
+ TPM2Flags flags,
+ usec_t until,
+ bool headless,
+ AskPasswordFlags ask_password_flags,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size) {
@@ -64,7 +111,51 @@ int acquire_tpm2_key(
blob = loaded_blob;
}
- return tpm2_unseal(device, pcr_mask, pcr_bank, primary_alg, blob, blob_size, policy_hash, policy_hash_size, ret_decrypted_key, ret_decrypted_key_size);
+ if (!(flags & TPM2_FLAGS_USE_PIN))
+ return tpm2_unseal(
+ device,
+ pcr_mask,
+ pcr_bank,
+ primary_alg,
+ blob,
+ blob_size,
+ policy_hash,
+ policy_hash_size,
+ NULL,
+ ret_decrypted_key,
+ ret_decrypted_key_size);
+
+ for (int i = 5;; i--) {
+ _cleanup_(erase_and_freep) char *pin_str = NULL;
+
+ if (i <= 0)
+ return -EACCES;
+
+ r = get_pin(until, ask_password_flags, headless, &pin_str);
+ if (r < 0)
+ return r;
+
+ r = tpm2_unseal(
+ device,
+ pcr_mask,
+ pcr_bank,
+ primary_alg,
+ blob,
+ blob_size,
+ policy_hash,
+ policy_hash_size,
+ pin_str,
+ ret_decrypted_key,
+ ret_decrypted_key_size);
+ /* We get this error in case there is an authentication policy mismatch. This should
+ * not happen, but this avoids confusing behavior, just in case. */
+ if (IN_SET(r, -EPERM, -ENOLCK))
+ return r;
+ if (r < 0)
+ continue;
+
+ return r;
+ }
}
int find_tpm2_auto_data(
@@ -79,11 +170,13 @@ int find_tpm2_auto_data(
void **ret_policy_hash,
size_t *ret_policy_hash_size,
int *ret_keyslot,
- int *ret_token) {
+ int *ret_token,
+ TPM2Flags *ret_flags) {
_cleanup_free_ void *blob = NULL, *policy_hash = NULL;
size_t blob_size = 0, policy_hash_size = 0;
int r, keyslot = -1, token = -1;
+ TPM2Flags flags = 0;
uint32_t pcr_mask = 0;
uint16_t pcr_bank = UINT16_MAX; /* default: pick automatically */
uint16_t primary_alg = TPM2_ALG_ECC; /* ECC was the only supported algorithm in systemd < 250, use that as implied default, for compatibility */
@@ -196,6 +289,16 @@ int find_tpm2_auto_data(
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid base64 data in 'tpm2-policy-hash' field.");
+ w = json_variant_by_key(v, "tpm2-pin");
+ if (w) {
+ if (!json_variant_is_boolean(w))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "TPM2 PIN policy is not a boolean.");
+
+ if (json_variant_boolean(w))
+ flags |= TPM2_FLAGS_USE_PIN;
+ }
+
break;
}
@@ -215,6 +318,7 @@ int find_tpm2_auto_data(
*ret_token = token;
*ret_pcr_bank = pcr_bank;
*ret_primary_alg = primary_alg;
+ *ret_flags = flags;
return 0;
}
diff --git a/src/cryptsetup/cryptsetup-tpm2.h b/src/cryptsetup/cryptsetup-tpm2.h
index bd04620462..ab16d0a18f 100644
--- a/src/cryptsetup/cryptsetup-tpm2.h
+++ b/src/cryptsetup/cryptsetup-tpm2.h
@@ -3,9 +3,11 @@
#include <sys/types.h>
+#include "ask-password-api.h"
#include "cryptsetup-util.h"
#include "log.h"
#include "time-util.h"
+#include "tpm2-util.h"
#if HAVE_TPM2
@@ -22,6 +24,10 @@ int acquire_tpm2_key(
size_t key_data_size,
const void *policy_hash,
size_t policy_hash_size,
+ TPM2Flags flags,
+ usec_t until,
+ bool headless,
+ AskPasswordFlags ask_password_flags,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size);
@@ -37,7 +43,8 @@ int find_tpm2_auto_data(
void **ret_policy_hash,
size_t *ret_policy_hash_size,
int *ret_keyslot,
- int *ret_token);
+ int *ret_token,
+ TPM2Flags *ret_flags);
#else
@@ -54,6 +61,10 @@ static inline int acquire_tpm2_key(
size_t key_data_size,
const void *policy_hash,
size_t policy_hash_size,
+ TPM2Flags flags,
+ usec_t until,
+ bool headless,
+ AskPasswordFlags ask_password_flags,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size) {
@@ -73,7 +84,8 @@ static inline int find_tpm2_auto_data(
void **ret_policy_hash,
size_t *ret_policy_hash_size,
int *ret_keyslot,
- int *ret_token) {
+ int *ret_token,
+ TPM2Flags *ret_flags) {
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"TPM2 support not available.");
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 56a3eedacc..c2075f53fd 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -82,6 +82,7 @@ static char *arg_fido2_rp_id = NULL;
static char *arg_tpm2_device = NULL;
static bool arg_tpm2_device_auto = false;
static uint32_t arg_tpm2_pcr_mask = UINT32_MAX;
+static bool arg_tpm2_pin = false;
static bool arg_headless = false;
static usec_t arg_token_timeout_usec = 30*USEC_PER_SEC;
@@ -387,6 +388,16 @@ static int parse_one_option(const char *option) {
arg_tpm2_pcr_mask |= mask;
}
+ } else if ((val = startswith(option, "tpm2-pin="))) {
+
+ r = parse_boolean(val);
+ if (r < 0) {
+ log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
+ return 0;
+ }
+
+ arg_tpm2_pin = r;
+
} else if ((val = startswith(option, "try-empty-password="))) {
r = parse_boolean(val);
@@ -1301,9 +1312,15 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
key_file, arg_keyfile_size, arg_keyfile_offset,
key_data, key_data_size,
NULL, 0, /* we don't know the policy hash */
+ arg_tpm2_pin,
+ until,
+ arg_headless,
+ arg_ask_password_flags,
&decrypted_key, &decrypted_key_size);
if (r >= 0)
break;
+ if (IN_SET(r, -EACCES, -ENOLCK))
+ return log_error_errno(SYNTHETIC_ERRNO(EAGAIN), "TPM2 PIN unlock failed, falling back to traditional unlocking.");
if (ERRNO_IS_NOT_SUPPORTED(r)) /* TPM2 support not compiled in? */
return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), "TPM2 support not available, falling back to traditional unlocking.");
if (r != -EAGAIN) /* EAGAIN means: no tpm2 chip found */
@@ -1335,6 +1352,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
for (;;) {
uint32_t pcr_mask;
uint16_t pcr_bank, primary_alg;
+ TPM2Flags tpm2_flags;
r = find_tpm2_auto_data(
cd,
@@ -1346,7 +1364,8 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
&blob, &blob_size,
&policy_hash, &policy_hash_size,
&keyslot,
- &token);
+ &token,
+ &tpm2_flags);
if (r == -ENXIO)
/* No further TPM2 tokens found in the LUKS2 header. */
return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
@@ -1369,7 +1388,13 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
NULL, 0, 0, /* no key file */
blob, blob_size,
policy_hash, policy_hash_size,
+ tpm2_flags,
+ until,
+ arg_headless,
+ arg_ask_password_flags,
&decrypted_key, &decrypted_key_size);
+ if (IN_SET(r, -EACCES, -ENOLCK))
+ return log_error_errno(SYNTHETIC_ERRNO(EAGAIN), "TPM2 PIN unlock failed, falling back to traditional unlocking.");
if (r != -EPERM)
break;
diff --git a/src/fundamental/sha256.h b/src/fundamental/sha256.h
index abc4167628..e53197f2ef 100644
--- a/src/fundamental/sha256.h
+++ b/src/fundamental/sha256.h
@@ -8,6 +8,8 @@
#include "types-fundamental.h"
+#define SHA256_DIGEST_SIZE 32
+
struct sha256_ctx {
uint32_t H[8];
diff --git a/src/journal/test-journal-config.c b/src/journal/test-journal-config.c
index bd0de9600a..1a6c531f4e 100644
--- a/src/journal/test-journal-config.c
+++ b/src/journal/test-journal-config.c
@@ -3,6 +3,7 @@
#include <stdbool.h>
#include "journald-server.h"
+#include "tests.h"
#define _COMPRESS_PARSE_CHECK(str, enab, thresh, varname) \
do { \
@@ -17,7 +18,7 @@
#define COMPRESS_PARSE_CHECK(str, enabled, threshold) \
_COMPRESS_PARSE_CHECK(str, enabled, threshold, conf##__COUNTER__)
-static void test_config_compress(void) {
+TEST(config_compress) {
COMPRESS_PARSE_CHECK("yes", true, 111);
COMPRESS_PARSE_CHECK("no", false, 111);
COMPRESS_PARSE_CHECK("y", true, 111);
@@ -46,8 +47,4 @@ static void test_config_compress(void) {
COMPRESS_PARSE_CHECK("", true, UINT64_MAX);
}
-int main(int argc, char *argv[]) {
- test_config_compress();
-
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_INFO);
diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c
index 2d86e2a5a1..bbb83d0824 100644
--- a/src/journal/test-journal-interleaving.c
+++ b/src/journal/test-journal-interleaving.c
@@ -70,7 +70,7 @@ static void append_number(ManagedJournalFile *f, int n, uint64_t *seqnum) {
free(p);
}
-static void test_check_number (sd_journal *j, int n) {
+static void test_check_number(sd_journal *j, int n) {
const void *d;
_cleanup_free_ char *k;
size_t l;
@@ -84,7 +84,7 @@ static void test_check_number (sd_journal *j, int n) {
assert_se(n == x);
}
-static void test_check_numbers_down (sd_journal *j, int count) {
+static void test_check_numbers_down(sd_journal *j, int count) {
int i;
for (i = 1; i <= count; i++) {
@@ -99,7 +99,7 @@ static void test_check_numbers_down (sd_journal *j, int count) {
}
-static void test_check_numbers_up (sd_journal *j, int count) {
+static void test_check_numbers_up(sd_journal *j, int count) {
for (int i = count; i >= 1; i--) {
int r;
test_check_number(j, i);
@@ -145,7 +145,7 @@ static void mkdtemp_chdir_chattr(char *path) {
(void) chattr_path(path, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
}
-static void test_skip(void (*setup)(void)) {
+static void test_skip_one(void (*setup)(void)) {
char t[] = "/var/tmp/journal-skip-XXXXXX";
sd_journal *j;
int r;
@@ -201,8 +201,12 @@ static void test_skip(void (*setup)(void)) {
puts("------------------------------------------------------------");
}
-static void test_sequence_numbers(void) {
+TEST(skip) {
+ test_skip_one(setup_sequential);
+ test_skip_one(setup_interleaved);
+}
+TEST(sequence_numbers) {
_cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
char t[] = "/var/tmp/journal-seq-XXXXXX";
ManagedJournalFile *one, *two;
@@ -287,19 +291,14 @@ static void test_sequence_numbers(void) {
}
}
-int main(int argc, char *argv[]) {
- test_setup_logging(LOG_DEBUG);
-
+static int intro(void) {
/* managed_journal_file_open requires a valid machine id */
if (access("/etc/machine-id", F_OK) != 0)
return log_tests_skipped("/etc/machine-id not found");
- arg_keep = argc > 1;
-
- test_skip(setup_sequential);
- test_skip(setup_interleaved);
+ arg_keep = saved_argc > 1;
- test_sequence_numbers();
-
- return 0;
+ return EXIT_SUCCESS;
}
+
+DEFINE_TEST_MAIN_WITH_INTRO(LOG_DEBUG, intro);
diff --git a/src/journal/test-journal-syslog.c b/src/journal/test-journal-syslog.c
index 33f412956b..84cfcefc3a 100644
--- a/src/journal/test-journal-syslog.c
+++ b/src/journal/test-journal-syslog.c
@@ -5,8 +5,9 @@
#include "macro.h"
#include "string-util.h"
#include "syslog-util.h"
+#include "tests.h"
-static void test_syslog_parse_identifier(const char *str,
+static void test_syslog_parse_identifier_one(const char *str,
const char *ident, const char *pid, const char *rest, int ret) {
const char *buf = str;
_cleanup_free_ char *ident2 = NULL, *pid2 = NULL;
@@ -20,40 +21,50 @@ static void test_syslog_parse_identifier(const char *str,
assert_se(streq(buf, rest));
}
-static void test_syslog_parse_priority(const char *str, int priority, int ret) {
- const char *buf = str;
+static void test_syslog_parse_priority_one(const char *str, bool with_facility, int priority, int ret) {
int priority2 = 0, ret2;
- ret2 = syslog_parse_priority(&buf, &priority2, false);
+ ret2 = syslog_parse_priority(&str, &priority2, with_facility);
assert_se(ret == ret2);
if (ret2 == 1)
assert_se(priority == priority2);
}
-int main(void) {
- test_syslog_parse_identifier("pidu[111]: xxx", "pidu", "111", "xxx", 11);
- test_syslog_parse_identifier("pidu: xxx", "pidu", NULL, "xxx", 6);
- test_syslog_parse_identifier("pidu: xxx", "pidu", NULL, " xxx", 6);
- test_syslog_parse_identifier("pidu xxx", NULL, NULL, "pidu xxx", 0);
- test_syslog_parse_identifier(" pidu xxx", NULL, NULL, " pidu xxx", 0);
- test_syslog_parse_identifier("", NULL, NULL, "", 0);
- test_syslog_parse_identifier(" ", NULL, NULL, " ", 0);
- test_syslog_parse_identifier(":", "", NULL, "", 1);
- test_syslog_parse_identifier(": ", "", NULL, " ", 2);
- test_syslog_parse_identifier(" :", "", NULL, "", 2);
- test_syslog_parse_identifier(" pidu:", "pidu", NULL, "", 8);
- test_syslog_parse_identifier("pidu:", "pidu", NULL, "", 5);
- test_syslog_parse_identifier("pidu: ", "pidu", NULL, "", 6);
- test_syslog_parse_identifier("pidu : ", NULL, NULL, "pidu : ", 0);
-
- test_syslog_parse_priority("<>", 0, 0);
- test_syslog_parse_priority("<>aaa", 0, 0);
- test_syslog_parse_priority("<aaaa>", 0, 0);
- test_syslog_parse_priority("<aaaa>aaa", 0, 0);
- test_syslog_parse_priority(" <aaaa>", 0, 0);
- test_syslog_parse_priority(" <aaaa>aaa", 0, 0);
- /* TODO: add test cases of valid priorities */
-
- return 0;
+TEST(syslog_parse_identifier) {
+ test_syslog_parse_identifier_one("pidu[111]: xxx", "pidu", "111", "xxx", 11);
+ test_syslog_parse_identifier_one("pidu: xxx", "pidu", NULL, "xxx", 6);
+ test_syslog_parse_identifier_one("pidu: xxx", "pidu", NULL, " xxx", 6);
+ test_syslog_parse_identifier_one("pidu xxx", NULL, NULL, "pidu xxx", 0);
+ test_syslog_parse_identifier_one(" pidu xxx", NULL, NULL, " pidu xxx", 0);
+ test_syslog_parse_identifier_one("", NULL, NULL, "", 0);
+ test_syslog_parse_identifier_one(" ", NULL, NULL, " ", 0);
+ test_syslog_parse_identifier_one(":", "", NULL, "", 1);
+ test_syslog_parse_identifier_one(": ", "", NULL, " ", 2);
+ test_syslog_parse_identifier_one(" :", "", NULL, "", 2);
+ test_syslog_parse_identifier_one(" pidu:", "pidu", NULL, "", 8);
+ test_syslog_parse_identifier_one("pidu:", "pidu", NULL, "", 5);
+ test_syslog_parse_identifier_one("pidu: ", "pidu", NULL, "", 6);
+ test_syslog_parse_identifier_one("pidu : ", NULL, NULL, "pidu : ", 0);
+}
+
+TEST(syslog_parse_priority) {
+ test_syslog_parse_priority_one("", false, 0, 0);
+ test_syslog_parse_priority_one("<>", false, 0, 0);
+ test_syslog_parse_priority_one("<>aaa", false, 0, 0);
+ test_syslog_parse_priority_one("<aaaa>", false, 0, 0);
+ test_syslog_parse_priority_one("<aaaa>aaa", false, 0, 0);
+ test_syslog_parse_priority_one(" <aaaa>", false, 0, 0);
+ test_syslog_parse_priority_one(" <aaaa>aaa", false, 0, 0);
+ test_syslog_parse_priority_one(" <aaaa>aaa", false, 0, 0);
+ test_syslog_parse_priority_one(" <1>", false, 0, 0);
+ test_syslog_parse_priority_one("<1>", false, 1, 1);
+ test_syslog_parse_priority_one("<7>", false, 7, 1);
+ test_syslog_parse_priority_one("<8>", false, 0, 0);
+ test_syslog_parse_priority_one("<9>", true, 9, 1);
+ test_syslog_parse_priority_one("<22>", true, 22, 1);
+ test_syslog_parse_priority_one("<111>", false, 0, 0);
+ test_syslog_parse_priority_one("<111>", true, 111, 1);
}
+
+DEFINE_TEST_MAIN(LOG_INFO);
diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c
index bfc1cf2960..07c476559c 100644
--- a/src/journal/test-journal.c
+++ b/src/journal/test-journal.c
@@ -23,7 +23,7 @@ static void mkdtemp_chdir_chattr(char *path) {
(void) chattr_path(path, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
}
-static void test_non_empty(void) {
+TEST(non_empty) {
_cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
dual_timestamp ts;
ManagedJournalFile *f;
@@ -34,8 +34,6 @@ static void test_non_empty(void) {
sd_id128_t fake_boot_id;
char t[] = "/var/tmp/journal-XXXXXX";
- test_setup_logging(LOG_DEBUG);
-
m = mmap_cache_new();
assert_se(m != NULL);
@@ -120,13 +118,11 @@ static void test_non_empty(void) {
puts("------------------------------------------------------------");
}
-static void test_empty(void) {
+TEST(empty) {
_cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
ManagedJournalFile *f1, *f2, *f3, *f4;
char t[] = "/var/tmp/journal-XXXXXX";
- test_setup_logging(LOG_DEBUG);
-
m = mmap_cache_new();
assert_se(m != NULL);
@@ -177,8 +173,6 @@ static bool check_compressed(uint64_t compress_threshold, uint64_t data_size) {
assert_se(data_size <= sizeof(data));
- test_setup_logging(LOG_DEBUG);
-
m = mmap_cache_new();
assert_se(m != NULL);
@@ -228,7 +222,7 @@ static bool check_compressed(uint64_t compress_threshold, uint64_t data_size) {
return is_compressed;
}
-static void test_min_compress_size(void) {
+TEST(min_compress_size) {
/* Note that XZ will actually fail to compress anything under 80 bytes, so you have to choose the limits
* carefully */
@@ -249,20 +243,14 @@ static void test_min_compress_size(void) {
}
#endif
-int main(int argc, char *argv[]) {
- arg_keep = argc > 1;
-
- test_setup_logging(LOG_INFO);
+static int intro(void) {
+ arg_keep = saved_argc > 1;
/* managed_journal_file_open requires a valid machine id */
if (access("/etc/machine-id", F_OK) != 0)
return log_tests_skipped("/etc/machine-id not found");
- test_non_empty();
- test_empty();
-#if HAVE_COMPRESSION
- test_min_compress_size();
-#endif
-
- return 0;
+ return EXIT_SUCCESS;
}
+
+DEFINE_TEST_MAIN_WITH_INTRO(LOG_DEBUG, intro);
diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c
index f53e093d77..dfd9042c29 100644
--- a/src/libsystemd-network/test-dhcp6-client.c
+++ b/src/libsystemd-network/test-dhcp6-client.c
@@ -78,12 +78,10 @@ static int test_ifindex = 42;
static unsigned test_client_sent_message_count = 0;
static sd_dhcp6_client *client_ref = NULL;
-static void test_client_basic(void) {
+TEST(client_basic) {
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
int v;
- log_debug("/* %s */", __func__);
-
assert_se(sd_dhcp6_client_new(&client) >= 0);
assert_se(client);
@@ -144,13 +142,11 @@ static void test_client_basic(void) {
assert_se(sd_dhcp6_client_detach_event(client) >= 0);
}
-static void test_parse_domain(void) {
+TEST(parse_domain) {
_cleanup_free_ char *domain = NULL;
_cleanup_strv_free_ char **list = NULL;
uint8_t *data;
- log_debug("/* %s */", __func__);
-
data = (uint8_t []) { 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0 };
assert_se(dhcp6_option_parse_domainname(data, 13, &domain) >= 0);
assert_se(domain);
@@ -182,7 +178,7 @@ static void test_parse_domain(void) {
assert_se(dhcp6_option_parse_domainname_list(data, 2, &list) < 0);
}
-static void test_option(void) {
+TEST(option) {
uint8_t packet[] = {
'F', 'O', 'O', 'H', 'O', 'G', 'E',
0x00, SD_DHCP6_OPTION_ORO, 0x00, 0x07,
@@ -204,8 +200,6 @@ static void test_option(void) {
uint16_t optcode;
uint8_t *out;
- log_debug("/* %s */", __func__);
-
assert_se(sizeof(packet) == sizeof(result));
offset = 0;
@@ -258,7 +252,7 @@ static void test_option(void) {
assert_se(memcmp(packet, result, sizeof(packet)) == 0);
}
-static void test_option_status(void) {
+TEST(option_status) {
uint8_t option1[] = {
/* IA NA */
0x00, 0x03, 0x00, 0x12, 0x1a, 0x1d, 0x1a, 0x1d,
@@ -330,8 +324,6 @@ static void test_option_status(void) {
be32_t iaid;
int r;
- log_debug("/* %s */", __func__);
-
memcpy(&iaid, option1 + 4, sizeof(iaid));
option = (DHCP6Option*) option1;
@@ -384,7 +376,7 @@ static void test_option_status(void) {
ia = dhcp6_ia_free(ia);
}
-static void test_client_parse_message_issue_22099(void) {
+TEST(client_parse_message_issue_22099) {
static const uint8_t msg[] = {
/* Message type */
DHCP6_MESSAGE_REPLY,
@@ -444,8 +436,6 @@ static void test_client_parse_message_issue_22099(void) {
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
_cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
- log_debug("/* %s */", __func__);
-
assert_se(sd_dhcp6_client_new(&client) >= 0);
assert_se(sd_dhcp6_client_set_iaid(client, 0xcc59117b) >= 0);
assert_se(sd_dhcp6_client_set_duid(client, 2, duid, sizeof(duid)) >= 0);
@@ -970,12 +960,10 @@ int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *a) {
return TAKE_FD(test_fd[0]);
}
-static void test_dhcp6_client(void) {
+TEST(dhcp6_client) {
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
- log_debug("/* %s */", __func__);
-
assert_se(sd_event_new(&e) >= 0);
assert_se(sd_event_add_time_relative(e, NULL, clock_boottime_or_monotonic(),
2 * USEC_PER_SEC, 0,
@@ -1006,15 +994,4 @@ static void test_dhcp6_client(void) {
test_fd[1] = safe_close(test_fd[1]);
}
-int main(int argc, char *argv[]) {
- test_setup_logging(LOG_DEBUG);
-
- test_client_basic();
- test_parse_domain();
- test_option();
- test_option_status();
- test_client_parse_message_issue_22099();
- test_dhcp6_client();
-
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/libsystemd-network/test-ndisc-ra.c b/src/libsystemd-network/test-ndisc-ra.c
index 83186a97bb..cbf065d4fb 100644
--- a/src/libsystemd-network/test-ndisc-ra.c
+++ b/src/libsystemd-network/test-ndisc-ra.c
@@ -100,11 +100,9 @@ static const struct in6_addr test_rdnss = { { { 0x20, 0x01, 0x0d, 0xb8,
static const char *test_dnssl[] = { "lab.intra",
NULL };
-static void test_radv_prefix(void) {
+TEST(radv_prefix) {
sd_radv_prefix *p;
- printf("* %s\n", __func__);
-
assert_se(sd_radv_prefix_new(&p) >= 0);
assert_se(sd_radv_prefix_set_onlink(NULL, true) < 0);
@@ -142,11 +140,9 @@ static void test_radv_prefix(void) {
assert_se(!p);
}
-static void test_radv(void) {
+TEST(radv) {
sd_radv *ra;
- printf("* %s\n", __func__);
-
assert_se(sd_radv_new(&ra) >= 0);
assert_se(ra);
@@ -284,13 +280,11 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat
return 0;
}
-static void test_ra(void) {
+TEST(ra) {
sd_event *e;
sd_radv *ra;
unsigned i;
- printf("* %s\n", __func__);
-
assert_se(socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) >= 0);
assert_se(sd_event_new(&e) >= 0);
@@ -349,14 +343,4 @@ static void test_ra(void) {
sd_event_unref(e);
}
-int main(int argc, char *argv[]) {
-
- test_setup_logging(LOG_DEBUG);
-
- test_radv_prefix();
- test_radv();
- test_ra();
-
- printf("* done\n");
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/libsystemd-network/test-ndisc-rs.c b/src/libsystemd-network/test-ndisc-rs.c
index 10915e1d4c..2c27d12b09 100644
--- a/src/libsystemd-network/test-ndisc-rs.c
+++ b/src/libsystemd-network/test-ndisc-rs.c
@@ -257,13 +257,10 @@ static void test_callback(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router
sd_event_exit(e, 0);
}
-static void test_rs(void) {
+TEST(rs) {
sd_event *e;
sd_ndisc *nd;
- if (verbose)
- printf("* %s\n", __func__);
-
send_ra_function = send_ra;
assert_se(sd_event_new(&e) >= 0);
@@ -347,13 +344,10 @@ static int test_timeout_value(uint8_t flags) {
return 0;
}
-static void test_timeout(void) {
+TEST(timeout) {
sd_event *e;
sd_ndisc *nd;
- if (verbose)
- printf("* %s\n", __func__);
-
send_ra_function = test_timeout_value;
assert_se(sd_event_new(&e) >= 0);
@@ -381,12 +375,4 @@ static void test_timeout(void) {
sd_event_unref(e);
}
-int main(int argc, char *argv[]) {
-
- test_setup_logging(LOG_DEBUG);
-
- test_rs();
- test_timeout();
-
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/libsystemd-network/test-sd-dhcp-lease.c b/src/libsystemd-network/test-sd-dhcp-lease.c
index 9f13226889..3eea1b0d9b 100644
--- a/src/libsystemd-network/test-sd-dhcp-lease.c
+++ b/src/libsystemd-network/test-sd-dhcp-lease.c
@@ -6,13 +6,14 @@
#include "macro.h"
#include "string-util.h"
#include "strv.h"
+#include "tests.h"
/* According to RFC1035 section 4.1.4, a domain name in a message can be either:
* - a sequence of labels ending in a zero octet
* - a pointer
* - a sequence of labels ending with a pointer
*/
-static void test_dhcp_lease_parse_search_domains_basic(void) {
+TEST(dhcp_lease_parse_search_domains_basic) {
int r;
_cleanup_strv_free_ char **domains = NULL;
static const uint8_t optionbuf[] = {
@@ -26,7 +27,7 @@ static void test_dhcp_lease_parse_search_domains_basic(void) {
assert_se(streq(domains[1], "ABCD.EFG"));
}
-static void test_dhcp_lease_parse_search_domains_ptr(void) {
+TEST(dhcp_lease_parse_search_domains_ptr) {
int r;
_cleanup_strv_free_ char **domains = NULL;
static const uint8_t optionbuf[] = {
@@ -39,7 +40,7 @@ static void test_dhcp_lease_parse_search_domains_ptr(void) {
assert_se(streq(domains[1], "FOO"));
}
-static void test_dhcp_lease_parse_search_domains_labels_and_ptr(void) {
+TEST(dhcp_lease_parse_search_domains_labels_and_ptr) {
int r;
_cleanup_strv_free_ char **domains = NULL;
static const uint8_t optionbuf[] = {
@@ -55,7 +56,7 @@ static void test_dhcp_lease_parse_search_domains_labels_and_ptr(void) {
/* Tests for exceptions. */
-static void test_dhcp_lease_parse_search_domains_no_data(void) {
+TEST(dhcp_lease_parse_search_domains_no_data) {
_cleanup_strv_free_ char **domains = NULL;
static const uint8_t optionbuf[3] = {0, 0, 0};
@@ -63,7 +64,7 @@ static void test_dhcp_lease_parse_search_domains_no_data(void) {
assert_se(dhcp_lease_parse_search_domains(optionbuf, 0, &domains) == -ENODATA);
}
-static void test_dhcp_lease_parse_search_domains_loops(void) {
+TEST(dhcp_lease_parse_search_domains_loops) {
_cleanup_strv_free_ char **domains = NULL;
static const uint8_t optionbuf[] = {
0x03, 'F', 'O', 'O', 0x00, 0x03, 'B', 'A', 'R', 0xC0, 0x06,
@@ -72,7 +73,7 @@ static void test_dhcp_lease_parse_search_domains_loops(void) {
assert_se(dhcp_lease_parse_search_domains(optionbuf, sizeof(optionbuf), &domains) == -EBADMSG);
}
-static void test_dhcp_lease_parse_search_domains_wrong_len(void) {
+TEST(dhcp_lease_parse_search_domains_wrong_len) {
_cleanup_strv_free_ char **domains = NULL;
static const uint8_t optionbuf[] = {
0x03, 'F', 'O', 'O', 0x03, 'B', 'A', 'R', 0x00,
@@ -82,12 +83,4 @@ static void test_dhcp_lease_parse_search_domains_wrong_len(void) {
assert_se(dhcp_lease_parse_search_domains(optionbuf, sizeof(optionbuf) - 5, &domains) == -EBADMSG);
}
-int main(int argc, char *argv[]) {
- test_dhcp_lease_parse_search_domains_basic();
- test_dhcp_lease_parse_search_domains_ptr();
- test_dhcp_lease_parse_search_domains_labels_and_ptr();
- test_dhcp_lease_parse_search_domains_no_data();
- test_dhcp_lease_parse_search_domains_loops();
- test_dhcp_lease_parse_search_domains_wrong_len();
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_INFO);
diff --git a/src/libsystemd/sd-bus/test-bus-address.c b/src/libsystemd/sd-bus/test-bus-address.c
index 59421094c5..00d3c15a8f 100644
--- a/src/libsystemd/sd-bus/test-bus-address.c
+++ b/src/libsystemd/sd-bus/test-bus-address.c
@@ -22,13 +22,13 @@ static void test_one_address(sd_bus *b,
}
}
-static void test_bus_set_address_system_remote(char **args) {
+TEST(bus_set_address_system_remote) {
_cleanup_(sd_bus_unrefp) sd_bus *b = NULL;
assert_se(sd_bus_new(&b) >= 0);
- if (!strv_isempty(args)) {
+ if (!strv_isempty(saved_argv + 1)) {
char **a;
- STRV_FOREACH(a, args)
+ STRV_FOREACH(a, saved_argv + 1)
test_one_address(b, *a, 0, NULL);
return;
};
@@ -61,10 +61,4 @@ static void test_bus_set_address_system_remote(char **args) {
-EINVAL, NULL);
}
-int main(int argc, char *argv[]) {
- test_setup_logging(LOG_INFO);
-
- test_bus_set_address_system_remote(argv + 1);
-
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_INFO);
diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c
index 84728e4e84..952455255d 100644
--- a/src/libsystemd/sd-bus/test-bus-error.c
+++ b/src/libsystemd/sd-bus/test-bus-error.c
@@ -8,8 +8,9 @@
#include "errno-list.h"
#include "errno-util.h"
#include "string-util.h"
+#include "tests.h"
-static void test_error(void) {
+TEST(error) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL, second = SD_BUS_ERROR_NULL;
const sd_bus_error const_error = SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS, "const error");
const sd_bus_error temporarily_const_error = {
@@ -126,7 +127,7 @@ static void test_error(void) {
extern const sd_bus_error_map __start_SYSTEMD_BUS_ERROR_MAP[];
extern const sd_bus_error_map __stop_SYSTEMD_BUS_ERROR_MAP[];
-static void dump_mapping_table(void) {
+static int dump_mapping_table(void) {
const sd_bus_error_map *m;
printf("----- errno mappings ------\n");
@@ -142,9 +143,11 @@ static void dump_mapping_table(void) {
m++;
}
printf("---------------------------\n");
+
+ return EXIT_SUCCESS;
}
-static void test_errno_mapping_standard(void) {
+TEST(errno_mapping_standard) {
assert_se(sd_bus_error_set(NULL, "System.Error.EUCLEAN", NULL) == -EUCLEAN);
assert_se(sd_bus_error_set(NULL, "System.Error.EBUSY", NULL) == -EBUSY);
assert_se(sd_bus_error_set(NULL, "System.Error.EINVAL", NULL) == -EINVAL);
@@ -186,7 +189,7 @@ static const sd_bus_error_map test_errors_bad2[] = {
SD_BUS_ERROR_MAP_END
};
-static void test_errno_mapping_custom(void) {
+TEST(errno_mapping_custom) {
assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error", NULL) == -5);
assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-2", NULL) == -52);
assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-x", NULL) == -EIO);
@@ -214,7 +217,7 @@ static void test_errno_mapping_custom(void) {
assert_se(sd_bus_error_add_map(test_errors_bad2) == -EINVAL);
}
-static void test_sd_bus_error_set_errnof(void) {
+TEST(sd_bus_error_set_errnof) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *str = NULL;
@@ -288,13 +291,4 @@ static void test_sd_bus_error_set_errnof(void) {
assert_se(error._need_free == 1);
}
-int main(int argc, char *argv[]) {
- dump_mapping_table();
-
- test_error();
- test_errno_mapping_standard();
- test_errno_mapping_custom();
- test_sd_bus_error_set_errnof();
-
- return 0;
-}
+DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, dump_mapping_table);
diff --git a/src/libsystemd/sd-bus/test-bus-gvariant.c b/src/libsystemd/sd-bus/test-bus-gvariant.c
index edd8301d45..47b1752360 100644
--- a/src/libsystemd/sd-bus/test-bus-gvariant.c
+++ b/src/libsystemd/sd-bus/test-bus-gvariant.c
@@ -15,9 +15,7 @@
#include "tests.h"
#include "util.h"
-static void test_bus_gvariant_is_fixed_size(void) {
- log_info("/* %s */", __func__);
-
+TEST(bus_gvariant_is_fixed_size) {
assert_se(bus_gvariant_is_fixed_size("") > 0);
assert_se(bus_gvariant_is_fixed_size("()") == -EINVAL);
assert_se(bus_gvariant_is_fixed_size("y") > 0);
@@ -42,9 +40,7 @@ static void test_bus_gvariant_is_fixed_size(void) {
assert_se(bus_gvariant_is_fixed_size("((u)yyy(b(iiivi)))") == 0);
}
-static void test_bus_gvariant_get_size(void) {
- log_info("/* %s */", __func__);
-
+TEST(bus_gvariant_get_size) {
assert_se(bus_gvariant_get_size("") == 0);
assert_se(bus_gvariant_get_size("()") == -EINVAL);
assert_se(bus_gvariant_get_size("y") == 1);
@@ -76,9 +72,7 @@ static void test_bus_gvariant_get_size(void) {
assert_se(bus_gvariant_get_size("((t)(t))") == 16);
}
-static void test_bus_gvariant_get_alignment(void) {
- log_info("/* %s */", __func__);
-
+TEST(bus_gvariant_get_alignment) {
assert_se(bus_gvariant_get_alignment("") == 1);
assert_se(bus_gvariant_get_alignment("()") == -EINVAL);
assert_se(bus_gvariant_get_alignment("y") == 1);
@@ -119,7 +113,7 @@ static void test_bus_gvariant_get_alignment(void) {
assert_se(bus_gvariant_get_alignment("((t)(t))") == 8);
}
-static int test_marshal(void) {
+TEST_RET(marshal) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *n = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_free_ void *blob = NULL;
@@ -209,12 +203,4 @@ static int test_marshal(void) {
return EXIT_SUCCESS;
}
-int main(int argc, char *argv[]) {
- test_setup_logging(LOG_DEBUG);
-
- test_bus_gvariant_is_fixed_size();
- test_bus_gvariant_get_size();
- test_bus_gvariant_get_alignment();
-
- return test_marshal();
-}
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/libsystemd/sd-bus/test-bus-introspect.c b/src/libsystemd/sd-bus/test-bus-introspect.c
index fb247c4d14..3c026aedb9 100644
--- a/src/libsystemd/sd-bus/test-bus-introspect.c
+++ b/src/libsystemd/sd-bus/test-bus-introspect.c
@@ -6,7 +6,7 @@
#include "test-vtable-data.h"
-static void test_manual_introspection(const sd_bus_vtable vtable[]) {
+static void test_manual_introspection_one(const sd_bus_vtable vtable[]) {
struct introspect intro = {};
_cleanup_free_ char *s = NULL;
@@ -23,13 +23,11 @@ static void test_manual_introspection(const sd_bus_vtable vtable[]) {
fputs("\n", stdout);
}
-int main(int argc, char *argv[]) {
- test_setup_logging(LOG_DEBUG);
-
- test_manual_introspection(test_vtable_1);
- test_manual_introspection(test_vtable_2);
- test_manual_introspection(test_vtable_deprecated);
- test_manual_introspection((const sd_bus_vtable *) vtable_format_221);
-
- return 0;
+TEST(manual_introspection) {
+ test_manual_introspection_one(test_vtable_1);
+ test_manual_introspection_one(test_vtable_2);
+ test_manual_introspection_one(test_vtable_deprecated);
+ test_manual_introspection_one((const sd_bus_vtable *) vtable_format_221);
}
+
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/libsystemd/sd-device/test-device-util.c b/src/libsystemd/sd-device/test-device-util.c
index 93fc105d98..bc8ab66716 100644
--- a/src/libsystemd/sd-device/test-device-util.c
+++ b/src/libsystemd/sd-device/test-device-util.c
@@ -3,11 +3,9 @@
#include "device-util.h"
#include "tests.h"
-static void test_log_device_full(void) {
+TEST(log_device_full) {
int r;
- log_info("/* %s */", __func__);
-
for (int level = LOG_ERR; level <= LOG_DEBUG; level++) {
log_device_full(NULL, level, "test level=%d: %m", level);
@@ -22,9 +20,4 @@ static void test_log_device_full(void) {
}
}
-int main(int argc, char **argv) {
- test_setup_logging(LOG_INFO);
-
- test_log_device_full();
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_INFO);
diff --git a/src/libsystemd/sd-device/test-sd-device.c b/src/libsystemd/sd-device/test-sd-device.c
index aaa16f740d..2d2157ba70 100644
--- a/src/libsystemd/sd-device/test-sd-device.c
+++ b/src/libsystemd/sd-device/test-sd-device.c
@@ -60,24 +60,20 @@ static void test_sd_device_one(sd_device *d) {
log_info("syspath:%s subsystem:%s initialized:%s", syspath, strna(subsystem), yes_no(i));
}
-static void test_sd_device_enumerator_devices(void) {
+TEST(sd_device_enumerator_devices) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
sd_device *d;
- log_info("/* %s */", __func__);
-
assert_se(sd_device_enumerator_new(&e) >= 0);
assert_se(sd_device_enumerator_allow_uninitialized(e) >= 0);
FOREACH_DEVICE(e, d)
test_sd_device_one(d);
}
-static void test_sd_device_enumerator_subsystems(void) {
+TEST(sd_device_enumerator_subsystems) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
sd_device *d;
- log_info("/* %s */", __func__);
-
assert_se(sd_device_enumerator_new(&e) >= 0);
assert_se(sd_device_enumerator_allow_uninitialized(e) >= 0);
FOREACH_SUBSYSTEM(e, d)
@@ -113,7 +109,7 @@ static unsigned test_sd_device_enumerator_filter_subsystem_one(const char *subsy
return n_new_dev;
}
-static void test_sd_device_enumerator_filter_subsystem(void) {
+TEST(sd_device_enumerator_filter_subsystem) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
_cleanup_(hashmap_freep) Hashmap *subsystems;
unsigned n_new_dev = 0;
@@ -121,8 +117,6 @@ static void test_sd_device_enumerator_filter_subsystem(void) {
Hashmap *h;
char *s;
- log_info("/* %s */", __func__);
-
assert_se(subsystems = hashmap_new(&string_hash_ops));
assert_se(sd_device_enumerator_new(&e) >= 0);
@@ -164,7 +158,7 @@ static void test_sd_device_enumerator_filter_subsystem(void) {
assert_se(n_new_dev <= 10);
}
-static void test_sd_device_new_from_nulstr(void) {
+TEST(sd_device_new_from_nulstr) {
const char *devlinks =
"/dev/disk/by-partuuid/1290d63a-42cc-4c71-b87c-xxxxxxxxxxxx\0"
"/dev/disk/by-path/pci-0000:00:0f.0-scsi-0:0:0:0-part3\0"
@@ -179,8 +173,6 @@ static void test_sd_device_new_from_nulstr(void) {
const uint8_t *nulstr;
size_t len;
- log_info("/* %s */", __func__);
-
assert_se(sd_device_new_from_syspath(&device, "/sys/class/net/lo") >= 0);
/* Yeah, of course, setting devlink to the loopback interface is nonsense. But this is just a
@@ -205,14 +197,4 @@ static void test_sd_device_new_from_nulstr(void) {
}
}
-int main(int argc, char **argv) {
- test_setup_logging(LOG_INFO);
-
- test_sd_device_enumerator_devices();
- test_sd_device_enumerator_subsystems();
- test_sd_device_enumerator_filter_subsystem();
-
- test_sd_device_new_from_nulstr();
-
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_INFO);
diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c
index 0ac23c1118..f902c4e3ff 100644
--- a/src/libsystemd/sd-event/test-event.c
+++ b/src/libsystemd/sd-event/test-event.c
@@ -195,7 +195,7 @@ static int post_handler(sd_event_source *s, void *userdata) {
return 2;
}
-static void test_basic(bool with_pidfd) {
+static void test_basic_one(bool with_pidfd) {
sd_event *e = NULL;
sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL;
static const char ch = 'x';
@@ -302,12 +302,15 @@ static void test_basic(bool with_pidfd) {
assert_se(unsetenv("SYSTEMD_PIDFD") >= 0);
}
-static void test_sd_event_now(void) {
+TEST(basic) {
+ test_basic_one(true); /* test with pidfd */
+ test_basic_one(false); /* test without pidfd */
+}
+
+TEST(sd_event_now) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
uint64_t event_now;
- log_info("/* %s */", __func__);
-
assert_se(sd_event_new(&e) >= 0);
assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) > 0);
assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) > 0);
@@ -341,12 +344,10 @@ static int rtqueue_handler(sd_event_source *s, const struct signalfd_siginfo *si
return 0;
}
-static void test_rtqueue(void) {
+TEST(rtqueue) {
sd_event_source *u = NULL, *v = NULL, *s = NULL;
sd_event *e = NULL;
- log_info("/* %s */", __func__);
-
assert_se(sd_event_default(&e) >= 0);
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+2, SIGRTMIN+3, SIGUSR2, -1) >= 0);
@@ -476,7 +477,7 @@ static int delete_self_handler(sd_event_source *s, const struct inotify_event *e
return 1;
}
-static void test_inotify(unsigned n_create_events) {
+static void test_inotify_one(unsigned n_create_events) {
_cleanup_(rm_rf_physical_and_freep) char *p = NULL;
sd_event_source *a = NULL, *b = NULL, *c = NULL, *d = NULL;
struct inotify_context context = {
@@ -529,6 +530,11 @@ static void test_inotify(unsigned n_create_events) {
sd_event_unref(e);
}
+TEST(inotify) {
+ test_inotify_one(100); /* should work without overflow */
+ test_inotify_one(33000); /* should trigger a q overflow */
+}
+
static int pidfd_handler(sd_event_source *s, const siginfo_t *si, void *userdata) {
assert_se(s);
assert_se(si);
@@ -548,14 +554,12 @@ static int pidfd_handler(sd_event_source *s, const siginfo_t *si, void *userdata
return 0;
}
-static void test_pidfd(void) {
+TEST(pidfd) {
sd_event_source *s = NULL, *t = NULL;
sd_event *e = NULL;
int pidfd;
pid_t pid, pid2;
- log_info("/* %s */", __func__);
-
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
pid = fork();
@@ -628,15 +632,13 @@ static int ratelimit_expired(sd_event_source *s, void *userdata) {
return ++expired;
}
-static void test_ratelimit(void) {
+TEST(ratelimit) {
_cleanup_close_pair_ int p[2] = {-1, -1};
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
_cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
uint64_t interval;
unsigned count, burst;
- log_info("/* %s */", __func__);
-
assert_se(sd_event_default(&e) >= 0);
assert_se(pipe2(p, O_CLOEXEC|O_NONBLOCK) >= 0);
@@ -706,7 +708,7 @@ static void test_ratelimit(void) {
assert_se(expired == 0);
}
-static void test_simple_timeout(void) {
+TEST(simple_timeout) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
usec_t f, t, some_time;
@@ -741,7 +743,7 @@ static int inotify_self_destroy_handler(sd_event_source *s, const struct inotify
return 1;
}
-static void test_inotify_self_destroy(void) {
+TEST(inotify_self_destroy) {
_cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
char path[] = "/tmp/inotifyXXXXXX";
@@ -759,25 +761,4 @@ static void test_inotify_self_destroy(void) {
assert_se(sd_event_loop(e) >= 0);
}
-int main(int argc, char *argv[]) {
- test_setup_logging(LOG_DEBUG);
-
- test_simple_timeout();
-
- test_basic(true); /* test with pidfd */
- test_basic(false); /* test without pidfd */
-
- test_sd_event_now();
- test_rtqueue();
-
- test_inotify(100); /* should work without overflow */
- test_inotify(33000); /* should trigger a q overflow */
-
- test_pidfd();
-
- test_ratelimit();
-
- test_inotify_self_destroy();
-
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/libsystemd/sd-journal/test-audit-type.c b/src/libsystemd/sd-journal/test-audit-type.c
index 5adbf0d5b6..1d5003bd9b 100644
--- a/src/libsystemd/sd-journal/test-audit-type.c
+++ b/src/libsystemd/sd-journal/test-audit-type.c
@@ -4,6 +4,7 @@
#include <linux/audit.h>
#include "audit-type.h"
+#include "tests.h"
static void print_audit_label(int i) {
const char *name;
@@ -13,14 +14,11 @@ static void print_audit_label(int i) {
printf("%i → %s → %s\n", i, audit_type_to_string(i), name);
}
-static void test_audit_type(void) {
+TEST(audit_type) {
int i;
for (i = 0; i <= AUDIT_KERNEL; i++)
print_audit_label(i);
}
-int main(int argc, char **argv) {
- test_audit_type();
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_INFO);
diff --git a/src/libsystemd/sd-journal/test-journal-send.c b/src/libsystemd/sd-journal/test-journal-send.c
index 533b8d91e6..8f9d9c4a30 100644
--- a/src/libsystemd/sd-journal/test-journal-send.c
+++ b/src/libsystemd/sd-journal/test-journal-send.c
@@ -10,8 +10,9 @@
#include "journal-send.h"
#include "macro.h"
#include "memory-util.h"
+#include "tests.h"
-static void test_journal_print(void) {
+TEST(journal_print) {
assert_se(sd_journal_print(LOG_INFO, "XXX") == 0);
assert_se(sd_journal_print(LOG_INFO, "%s", "YYY") == 0);
assert_se(sd_journal_print(LOG_INFO, "X%4094sY", "ZZZ") == 0);
@@ -19,7 +20,7 @@ static void test_journal_print(void) {
assert_se(sd_journal_print(LOG_INFO, "X%*sY", LONG_LINE_MAX - 8 - 2, "ZZZ") == -ENOBUFS);
}
-static void test_journal_send(void) {
+TEST(journal_send) {
_cleanup_free_ char *huge = NULL;
#define HUGE_SIZE (4096*1024)
@@ -98,13 +99,13 @@ static void test_journal_send(void) {
closelog();
}
-int main(int argc, char *argv[]) {
- test_journal_print();
- test_journal_send();
-
+static int outro(void) {
/* Sleep a bit to make it easy for journald to collect metadata. */
sleep(1);
close_journal_fd();
- return 0;
+
+ return EXIT_SUCCESS;
}
+
+DEFINE_TEST_MAIN_FULL(LOG_INFO, NULL, outro);
diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c
index 3fc394d5ee..f7cef6e304 100644
--- a/src/libsystemd/sd-login/test-login.c
+++ b/src/libsystemd/sd-login/test-login.c
@@ -11,6 +11,7 @@
#include "log.h"
#include "string-util.h"
#include "strv.h"
+#include "tests.h"
#include "time-util.h"
#include "user-util.h"
@@ -35,7 +36,7 @@ static const char *e(int r) {
return r == 0 ? "OK" : errno_to_name(r);
}
-static void test_login(void) {
+TEST(login) {
_cleanup_close_pair_ int pair[2] = { -1, -1 };
_cleanup_free_ char *pp = NULL, *qq = NULL,
*display_session = NULL, *cgroup = NULL,
@@ -259,10 +260,13 @@ static void test_login(void) {
}
}
-static void test_monitor(void) {
+TEST(monitor) {
sd_login_monitor *m = NULL;
int r;
+ if (!streq_ptr(saved_argv[1], "-m"))
+ return;
+
assert_se(sd_login_monitor_new("session", &m) == 0);
for (unsigned n = 0; n < 5; n++) {
@@ -290,16 +294,9 @@ static void test_monitor(void) {
sd_login_monitor_unref(m);
}
-int main(int argc, char* argv[]) {
- log_parse_environment();
- log_open();
-
+static int intro(void) {
log_info("/* Information printed is from the live system */");
-
- test_login();
-
- if (streq_ptr(argv[1], "-m"))
- test_monitor();
-
- return 0;
+ return EXIT_SUCCESS;
}
+
+DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);
diff --git a/src/locale/test-keymap-util.c b/src/locale/test-keymap-util.c
index f726e8e524..668f94ec80 100644
--- a/src/locale/test-keymap-util.c
+++ b/src/locale/test-keymap-util.c
@@ -6,11 +6,9 @@
#include "string-util.h"
#include "tests.h"
-static void test_find_language_fallback(void) {
+TEST(find_language_fallback) {
_cleanup_free_ char *ans = NULL, *ans2 = NULL;
- log_info("/*** %s ***/", __func__);
-
assert_se(find_language_fallback("foobar", &ans) == 0);
assert_se(ans == NULL);
@@ -24,12 +22,10 @@ static void test_find_language_fallback(void) {
assert_se(streq(ans2, "szl:pl"));
}
-static void test_find_converted_keymap(void) {
+TEST(find_converted_keymap) {
_cleanup_free_ char *ans = NULL, *ans2 = NULL;
int r;
- log_info("/*** %s ***/", __func__);
-
assert_se(find_converted_keymap("pl", "foobar", &ans) == 0);
assert_se(ans == NULL);
@@ -46,12 +42,10 @@ static void test_find_converted_keymap(void) {
assert_se(streq(ans2, "pl-dvorak"));
}
-static void test_find_legacy_keymap(void) {
+TEST(find_legacy_keymap) {
Context c = {};
_cleanup_free_ char *ans = NULL, *ans2 = NULL;
- log_info("/*** %s ***/", __func__);
-
c.x11_layout = (char*) "foobar";
assert_se(find_legacy_keymap(&c, &ans) == 0);
assert_se(ans == NULL);
@@ -65,11 +59,9 @@ static void test_find_legacy_keymap(void) {
assert_se(streq(ans, "pl2"));
}
-static void test_vconsole_convert_to_x11(void) {
+TEST(vconsole_convert_to_x11) {
_cleanup_(context_clear) Context c = {};
- log_info("/*** %s ***/", __func__);
-
log_info("/* test emptying first (:) */");
assert_se(free_and_strdup(&c.x11_layout, "foo") >= 0);
assert_se(free_and_strdup(&c.x11_variant, "bar") >= 0);
@@ -119,12 +111,10 @@ static void test_vconsole_convert_to_x11(void) {
assert_se(c.x11_variant == NULL);
}
-static void test_x11_convert_to_vconsole(void) {
+TEST(x11_convert_to_vconsole) {
_cleanup_(context_clear) Context c = {};
int r;
- log_info("/*** %s ***/", __func__);
-
log_info("/* test emptying first (:) */");
assert_se(free_and_strdup(&c.vc_keymap, "foobar") >= 0);
assert_se(x11_convert_to_vconsole(&c) == 1);
@@ -189,20 +179,13 @@ static void test_x11_convert_to_vconsole(void) {
assert_se(streq(c.vc_keymap, "ru"));
}
-int main(int argc, char **argv) {
+static int intro(void) {
_cleanup_free_ char *map = NULL;
- test_setup_logging(LOG_DEBUG);
-
- test_find_language_fallback();
- test_find_converted_keymap();
-
assert_se(get_testdata_dir("test-keymap-util/kbd-model-map", &map) >= 0);
assert_se(setenv("SYSTEMD_KBD_MODEL_MAP", map, 1) == 0);
- test_find_legacy_keymap();
- test_vconsole_convert_to_x11();
- test_x11_convert_to_vconsole();
-
- return 0;
+ return EXIT_SUCCESS;
}
+
+DEFINE_TEST_MAIN_WITH_INTRO(LOG_DEBUG, intro);
diff --git a/src/login/test-login-shared.c b/src/login/test-login-shared.c
index d3de9c4958..17cd479dc9 100644
--- a/src/login/test-login-shared.c
+++ b/src/login/test-login-shared.c
@@ -2,8 +2,9 @@
#include "login-util.h"
#include "macro.h"
+#include "tests.h"
-static void test_session_id_valid(void) {
+TEST(session_id_valid) {
assert_se(session_id_valid("c1"));
assert_se(session_id_valid("1234"));
@@ -12,11 +13,4 @@ static void test_session_id_valid(void) {
assert_se(!session_id_valid("\tid"));
}
-int main(int argc, char* argv[]) {
- log_parse_environment();
- log_open();
-
- test_session_id_valid();
-
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_INFO);
diff --git a/src/network/test-networkd-address.c b/src/network/test-networkd-address.c
index 46e8369abb..e0d85b2b79 100644
--- a/src/network/test-networkd-address.c
+++ b/src/network/test-networkd-address.c
@@ -11,11 +11,9 @@ static void test_FORMAT_LIFETIME_one(usec_t lifetime, const char *expected) {
assert_se(streq(t, expected));
}
-static void test_FORMAT_LIFETIME(void) {
+TEST(FORMAT_LIFETIME) {
usec_t now_usec;
- log_info("/* %s */", __func__);
-
now_usec = now(clock_boottime_or_monotonic());
test_FORMAT_LIFETIME_one(now_usec, "for 0");
@@ -24,10 +22,4 @@ static void test_FORMAT_LIFETIME(void) {
test_FORMAT_LIFETIME_one(USEC_INFINITY, "forever");
}
-int main(int argc, char *argv[]) {
- test_setup_logging(LOG_DEBUG);
-
- test_FORMAT_LIFETIME();
-
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c
index 5f1328e39c..2e4ca0cb5f 100644
--- a/src/network/test-networkd-conf.c
+++ b/src/network/test-networkd-conf.c
@@ -9,6 +9,7 @@
#include "networkd-manager.h"
#include "networkd-network.h"
#include "strv.h"
+#include "tests.h"
static void test_config_parse_duid_type_one(const char *rvalue, int ret, DUIDType expected, usec_t expected_time) {
DUID actual = {};
@@ -22,7 +23,7 @@ static void test_config_parse_duid_type_one(const char *rvalue, int ret, DUIDTyp
assert_se(expected_time == actual.llt_time);
}
-static void test_config_parse_duid_type(void) {
+TEST(config_parse_duid_type) {
test_config_parse_duid_type_one("", 0, 0, 0);
test_config_parse_duid_type_one("link-layer-time", 0, DUID_TYPE_LLT, 0);
test_config_parse_duid_type_one("link-layer-time:2000-01-01 00:00:00 UTC", 0, DUID_TYPE_LLT, (usec_t) 946684800000000);
@@ -86,7 +87,7 @@ static void test_config_parse_ether_addrs_one(const char *rvalue, const struct e
#define BYTES_1_128 {0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80}
-static void test_config_parse_duid_rawdata(void) {
+TEST(config_parse_duid_rawdata) {
test_config_parse_duid_rawdata_one("", 0, &(DUID){});
test_config_parse_duid_rawdata_one("00:11:22:33:44:55:66:77", 0,
&(DUID){0, 8, {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77}});
@@ -102,7 +103,7 @@ static void test_config_parse_duid_rawdata(void) {
test_config_parse_duid_rawdata_one(&BYTES_0_128[2], 0, &(DUID){0, 128, BYTES_1_128});
}
-static void test_config_parse_ether_addr(void) {
+TEST(config_parse_ether_addr) {
const struct ether_addr t[] = {
{ .ether_addr_octet = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff } },
{ .ether_addr_octet = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab } },
@@ -192,7 +193,7 @@ static void test_config_parse_address_one(const char *rvalue, int family, unsign
}
}
-static void test_config_parse_address(void) {
+TEST(config_parse_address) {
test_config_parse_address_one("", AF_INET, 0, NULL, 0);
test_config_parse_address_one("/", AF_INET, 0, NULL, 0);
test_config_parse_address_one("/8", AF_INET, 0, NULL, 0);
@@ -219,7 +220,7 @@ static void test_config_parse_address(void) {
test_config_parse_address_one("::1/-1", AF_INET6, 0, NULL, 0);
}
-static void test_config_parse_match_ifnames(void) {
+TEST(config_parse_match_ifnames) {
_cleanup_strv_free_ char **names = NULL;
assert_se(config_parse_match_ifnames("network", "filename", 1, "section", 1, "Name", 0, "!hoge hogehoge foo", &names, NULL) == 0);
@@ -229,7 +230,7 @@ static void test_config_parse_match_ifnames(void) {
assert_se(strv_equal(names, STRV_MAKE("!hoge", "!hogehoge", "!foo", "!baz", "aaa", "bbb", "ccc")));
}
-static void test_config_parse_match_strv(void) {
+TEST(config_parse_match_strv) {
_cleanup_strv_free_ char **names = NULL;
assert_se(config_parse_match_strv("network", "filename", 1, "section", 1, "Name", 0, "!hoge hogehoge foo", &names, NULL) == 0);
@@ -247,16 +248,4 @@ static void test_config_parse_match_strv(void) {
"KEY3=val with \\quotation\\")));
}
-int main(int argc, char **argv) {
- log_parse_environment();
- log_open();
-
- test_config_parse_duid_type();
- test_config_parse_duid_rawdata();
- test_config_parse_ether_addr();
- test_config_parse_address();
- test_config_parse_match_ifnames();
- test_config_parse_match_strv();
-
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_INFO);
diff --git a/src/partition/repart.c b/src/partition/repart.c
index 91645202fc..8345b6f582 100644
--- a/src/partition/repart.c
+++ b/src/partition/repart.c
@@ -2656,7 +2656,7 @@ static int partition_encrypt(
uint16_t pcr_bank, primary_alg;
int keyslot;
- r = tpm2_seal(arg_tpm2_device, arg_tpm2_pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank, &primary_alg);
+ r = tpm2_seal(arg_tpm2_device, arg_tpm2_pcr_mask, NULL, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank, &primary_alg);
if (r < 0)
return log_error_errno(r, "Failed to seal to TPM2: %m");
@@ -2678,7 +2678,7 @@ static int partition_encrypt(
if (keyslot < 0)
return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node);
- r = tpm2_make_luks2_json(keyslot, arg_tpm2_pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, &v);
+ r = tpm2_make_luks2_json(keyslot, arg_tpm2_pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, 0, &v);
if (r < 0)
return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m");
diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c
index 3263095360..d325b533ea 100644
--- a/src/resolve/test-dnssec.c
+++ b/src/resolve/test-dnssec.c
@@ -9,13 +9,13 @@
#endif
#include "alloc-util.h"
+#include "hexdecoct.h"
#include "resolved-dns-dnssec.h"
#include "resolved-dns-rr.h"
#include "string-util.h"
-#include "hexdecoct.h"
-
-static void test_dnssec_verify_dns_key(void) {
+#include "tests.h"
+TEST(dnssec_verify_dns_key) {
static const uint8_t ds1_fprint[] = {
0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D,
0x80, 0x67, 0x14, 0x01,
@@ -88,7 +88,7 @@ static void test_dnssec_verify_dns_key(void) {
assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0);
}
-static void test_dnssec_verify_rfc8080_ed25519_example1(void) {
+TEST(dnssec_verify_rfc8080_ed25519_example1) {
static const uint8_t dnskey_blob[] = {
0x97, 0x4d, 0x96, 0xa2, 0x2d, 0x22, 0x4b, 0xc0, 0x1a, 0xdb, 0x91, 0x50, 0x91, 0x47, 0x7d,
0x44, 0xcc, 0xd9, 0x1c, 0x9a, 0x41, 0xa1, 0x14, 0x30, 0x01, 0x01, 0x17, 0xd5, 0x2c, 0x59,
@@ -180,7 +180,7 @@ static void test_dnssec_verify_rfc8080_ed25519_example1(void) {
#endif
}
-static void test_dnssec_verify_rfc8080_ed25519_example2(void) {
+TEST(dnssec_verify_rfc8080_ed25519_example2) {
static const uint8_t dnskey_blob[] = {
0xcc, 0xf9, 0xd9, 0xfd, 0x0c, 0x04, 0x7b, 0xb4, 0xbc, 0x0b, 0x94, 0x8f, 0xcf, 0x63, 0x9f,
0x4b, 0x94, 0x51, 0xe3, 0x40, 0x13, 0x93, 0x6f, 0xeb, 0x62, 0x71, 0x3d, 0xc4, 0x72, 0x4,
@@ -272,7 +272,7 @@ static void test_dnssec_verify_rfc8080_ed25519_example2(void) {
#endif
}
-static void test_dnssec_verify_rfc6605_example1(void) {
+TEST(dnssec_verify_rfc6605_example1) {
static const uint8_t signature_blob[] = {
0xab, 0x1e, 0xb0, 0x2d, 0x8a, 0xa6, 0x87, 0xe9, 0x7d, 0xa0, 0x22, 0x93, 0x37, 0xaa, 0x88, 0x73,
0xe6, 0xf0, 0xeb, 0x26, 0xbe, 0x28, 0x9f, 0x28, 0x33, 0x3d, 0x18, 0x3f, 0x5d, 0x3b, 0x7a, 0x95,
@@ -359,7 +359,7 @@ static void test_dnssec_verify_rfc6605_example1(void) {
assert_se(result == DNSSEC_VALIDATED);
}
-static void test_dnssec_verify_rfc6605_example2(void) {
+TEST(dnssec_verify_rfc6605_example2) {
static const uint8_t signature_blob[] = {
0xfc, 0xbe, 0x61, 0x0c, 0xa2, 0x2f, 0x18, 0x3c, 0x88, 0xd5, 0xf7, 0x00, 0x45, 0x7d, 0xf3, 0xeb,
0x9a, 0xab, 0x98, 0xfb, 0x15, 0xcf, 0xbd, 0xd0, 0x0f, 0x53, 0x2b, 0xe4, 0x21, 0x2a, 0x3a, 0x22,
@@ -454,8 +454,7 @@ static void test_dnssec_verify_rfc6605_example2(void) {
assert_se(result == DNSSEC_VALIDATED);
}
-static void test_dnssec_verify_rrset(void) {
-
+TEST(dnssec_verify_rrset) {
static const uint8_t signature_blob[] = {
0x7f, 0x79, 0xdd, 0x5e, 0x89, 0x79, 0x18, 0xd0, 0x34, 0x86, 0x8c, 0x72, 0x77, 0x75, 0x48, 0x4d,
0xc3, 0x7d, 0x38, 0x04, 0xab, 0xcd, 0x9e, 0x4c, 0x82, 0xb0, 0x92, 0xca, 0xe9, 0x66, 0xe9, 0x6e,
@@ -533,8 +532,7 @@ static void test_dnssec_verify_rrset(void) {
assert_se(result == DNSSEC_VALIDATED);
}
-static void test_dnssec_verify_rrset2(void) {
-
+TEST(dnssec_verify_rrset2) {
static const uint8_t signature_blob[] = {
0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11,
0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b,
@@ -625,8 +623,7 @@ static void test_dnssec_verify_rrset2(void) {
assert_se(result == DNSSEC_VALIDATED);
}
-static void test_dnssec_verify_rrset3(void) {
-
+TEST(dnssec_verify_rrset3) {
static const uint8_t signature_blob[] = {
0x41, 0x09, 0x08, 0x67, 0x51, 0x6d, 0x02, 0xf2, 0x17, 0x1e, 0x61, 0x03, 0xc6, 0x80, 0x7a, 0x82,
0x8f, 0x6c, 0x8c, 0x4c, 0x68, 0x6f, 0x1c, 0xaa, 0x4a, 0xe0, 0x9b, 0x72, 0xdf, 0x7f, 0x15, 0xfa,
@@ -755,7 +752,7 @@ static void test_dnssec_verify_rrset3(void) {
assert_se(result == DNSSEC_VALIDATED);
}
-static void test_dnssec_nsec3_hash(void) {
+TEST(dnssec_nsec3_hash) {
static const uint8_t salt[] = { 0xB0, 0x1D, 0xFA, 0xCE };
static const uint8_t next_hashed_name[] = { 0x84, 0x10, 0x26, 0x53, 0xc9, 0xfa, 0x4d, 0x85, 0x6c, 0x97, 0x82, 0xe2, 0x8f, 0xdf, 0x2d, 0x5e, 0x87, 0x69, 0xc4, 0x52 };
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
@@ -787,16 +784,4 @@ static void test_dnssec_nsec3_hash(void) {
assert_se(strcasecmp(b, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0);
}
-int main(int argc, char *argv[]) {
- test_dnssec_verify_dns_key();
- test_dnssec_verify_rfc8080_ed25519_example1();
- test_dnssec_verify_rfc8080_ed25519_example2();
- test_dnssec_verify_rfc6605_example1();
- test_dnssec_verify_rfc6605_example2();
- test_dnssec_verify_rrset();
- test_dnssec_verify_rrset2();
- test_dnssec_verify_rrset3();
- test_dnssec_nsec3_hash();
-
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_INFO);
diff --git a/src/resolve/test-resolved-etc-hosts.c b/src/resolve/test-resolved-etc-hosts.c
index cc55a980ad..e5a20a2b14 100644
--- a/src/resolve/test-resolved-etc-hosts.c
+++ b/src/resolve/test-resolved-etc-hosts.c
@@ -14,11 +14,9 @@
#include "tests.h"
#include "tmpfile-util.h"
-static void test_parse_etc_hosts_system(void) {
+TEST(parse_etc_hosts_system) {
_cleanup_fclose_ FILE *f = NULL;
- log_info("/* %s */", __func__);
-
f = fopen("/etc/hosts", "re");
if (!f) {
assert_se(errno == ENOENT);
@@ -37,12 +35,10 @@ static void test_parse_etc_hosts_system(void) {
((_addr)->family == AF_INET6 && \
!memcmp(&(_addr)->address.in6, &(struct in6_addr) { .s6_addr = __VA_ARGS__}, 16) )
-static void test_parse_etc_hosts(void) {
+TEST(parse_etc_hosts) {
_cleanup_(unlink_tempfilep) char
t[] = "/tmp/test-resolved-etc-hosts.XXXXXX";
- log_info("/* %s */", __func__);
-
int fd;
_cleanup_fclose_ FILE *f;
const char *s;
@@ -128,7 +124,7 @@ static void test_parse_etc_hosts(void) {
assert_se(!set_contains(hosts.no_address, "foobar.foo.foo"));
}
-static void test_parse_file(const char *fname) {
+static void test_parse_file_one(const char *fname) {
_cleanup_(etc_hosts_free) EtcHosts hosts = {};
_cleanup_fclose_ FILE *f;
@@ -138,14 +134,9 @@ static void test_parse_file(const char *fname) {
assert_se(etc_hosts_parse(&hosts, f) == 0);
}
-int main(int argc, char **argv) {
- test_setup_logging(LOG_DEBUG);
-
- if (argc == 1) {
- test_parse_etc_hosts_system();
- test_parse_etc_hosts();
- } else
- test_parse_file(argv[1]);
-
- return 0;
+TEST(parse_file) {
+ for (int i = 1; i < saved_argc; i++)
+ test_parse_file_one(saved_argv[i]);
}
+
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/resolve/test-resolved-packet.c b/src/resolve/test-resolved-packet.c
index cd93b1c23d..dd8c969b14 100644
--- a/src/resolve/test-resolved-packet.c
+++ b/src/resolve/test-resolved-packet.c
@@ -4,7 +4,7 @@
#include "resolved-dns-packet.h"
#include "tests.h"
-static void test_dns_packet_new(void) {
+TEST(dns_packet_new) {
size_t i;
_cleanup_(dns_packet_unrefp) DnsPacket *p2 = NULL;
@@ -23,10 +23,4 @@ static void test_dns_packet_new(void) {
assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, DNS_PACKET_SIZE_MAX + 1, DNS_PACKET_SIZE_MAX) == -EFBIG);
}
-int main(int argc, char **argv) {
- test_setup_logging(LOG_DEBUG);
-
- test_dns_packet_new();
-
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/shared/creds-util.c b/src/shared/creds-util.c
index 4d0681bc10..c4dcc396ac 100644
--- a/src/shared/creds-util.c
+++ b/src/shared/creds-util.c
@@ -534,6 +534,7 @@ int encrypt_credential_and_warn(
r = tpm2_seal(tpm2_device,
tpm2_pcr_mask,
+ NULL,
&tpm2_key,
&tpm2_key_size,
&tpm2_blob,
@@ -803,6 +804,7 @@ int decrypt_credential_and_warn(
le32toh(t->blob_size),
t->policy_hash_and_blob + le32toh(t->blob_size),
le32toh(t->policy_hash_size),
+ NULL,
&tpm2_key,
&tpm2_key_size);
if (r < 0)
diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c
index 70a2929432..44fe899acd 100644
--- a/src/shared/tpm2-util.c
+++ b/src/shared/tpm2-util.c
@@ -14,6 +14,7 @@
#include "hexdecoct.h"
#include "memory-util.h"
#include "random-util.h"
+#include "sha256.h"
#include "time-util.h"
static void *libtss2_esys_dl = NULL;
@@ -30,10 +31,12 @@ TSS2_RC (*sym_Esys_GetRandom)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_
TSS2_RC (*sym_Esys_Initialize)(ESYS_CONTEXT **esys_context, TSS2_TCTI_CONTEXT *tcti, TSS2_ABI_VERSION *abiVersion) = NULL;
TSS2_RC (*sym_Esys_Load)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_PRIVATE *inPrivate, const TPM2B_PUBLIC *inPublic, ESYS_TR *objectHandle) = NULL;
TSS2_RC (*sym_Esys_PCR_Read)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1,ESYS_TR shandle2, ESYS_TR shandle3, const TPML_PCR_SELECTION *pcrSelectionIn, UINT32 *pcrUpdateCounter, TPML_PCR_SELECTION **pcrSelectionOut, TPML_DIGEST **pcrValues);
+TSS2_RC (*sym_Esys_PolicyAuthValue)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3) = NULL;
TSS2_RC (*sym_Esys_PolicyGetDigest)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_DIGEST **policyDigest) = NULL;
TSS2_RC (*sym_Esys_PolicyPCR)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_DIGEST *pcrDigest, const TPML_PCR_SELECTION *pcrs) = NULL;
TSS2_RC (*sym_Esys_StartAuthSession)(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey, ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType, const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash, ESYS_TR *sessionHandle) = NULL;
TSS2_RC (*sym_Esys_Startup)(ESYS_CONTEXT *esysContext, TPM2_SU startupType) = NULL;
+TSS2_RC (*sym_Esys_TR_SetAuth)(ESYS_CONTEXT *esysContext, ESYS_TR handle, TPM2B_AUTH const *authValue) = NULL;
TSS2_RC (*sym_Esys_Unseal)(ESYS_CONTEXT *esysContext, ESYS_TR itemHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_SENSITIVE_DATA **outData) = NULL;
const char* (*sym_Tss2_RC_Decode)(TSS2_RC rc) = NULL;
@@ -58,10 +61,12 @@ int dlopen_tpm2(void) {
DLSYM_ARG(Esys_Initialize),
DLSYM_ARG(Esys_Load),
DLSYM_ARG(Esys_PCR_Read),
+ DLSYM_ARG(Esys_PolicyAuthValue),
DLSYM_ARG(Esys_PolicyGetDigest),
DLSYM_ARG(Esys_PolicyPCR),
DLSYM_ARG(Esys_StartAuthSession),
DLSYM_ARG(Esys_Startup),
+ DLSYM_ARG(Esys_TR_SetAuth),
DLSYM_ARG(Esys_Unseal));
if (r < 0)
return r;
@@ -594,6 +599,7 @@ static int tpm2_make_pcr_session(
ESYS_CONTEXT *c,
uint32_t pcr_mask,
uint16_t pcr_bank, /* If UINT16_MAX, pick best bank automatically, otherwise specify bank explicitly. */
+ bool use_pin,
ESYS_TR *ret_session,
TPM2B_DIGEST **ret_policy_digest,
TPMI_ALG_HASH *ret_pcr_bank) {
@@ -669,6 +675,21 @@ static int tpm2_make_pcr_session(
goto finish;
}
+ if (use_pin) {
+ rc = sym_Esys_PolicyAuthValue(
+ c,
+ session,
+ ESYS_TR_NONE,
+ ESYS_TR_NONE,
+ ESYS_TR_NONE);
+ if (rc != TSS2_RC_SUCCESS) {
+ r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+ "Failed to add authValue policy to TPM: %s",
+ sym_Tss2_RC_Decode(rc));
+ goto finish;
+ }
+ }
+
if (DEBUG_LOGGING || ret_policy_digest) {
log_debug("Acquiring policy digest.");
@@ -717,9 +738,22 @@ finish:
return r;
}
+static void hash_pin(const char *pin, size_t len, uint8_t ret_digest[static SHA256_DIGEST_SIZE]) {
+ struct sha256_ctx hash;
+
+ assert(pin);
+
+ sha256_init_ctx(&hash);
+ sha256_process_bytes(pin, len, &hash);
+ sha256_finish_ctx(&hash, ret_digest);
+
+ explicit_bzero_safe(&hash, sizeof(hash));
+}
+
int tpm2_seal(
const char *device,
uint32_t pcr_mask,
+ const char *pin,
void **ret_secret,
size_t *ret_secret_size,
void **ret_blob,
@@ -782,7 +816,8 @@ int tpm2_seal(
if (r < 0)
return r;
- r = tpm2_make_pcr_session(c.esys_context, pcr_mask, UINT16_MAX, NULL, &policy_digest, &pcr_bank);
+ r = tpm2_make_pcr_session(c.esys_context, pcr_mask, UINT16_MAX, !!pin, NULL, &policy_digest,
+ &pcr_bank);
if (r < 0)
goto finish;
@@ -813,6 +848,10 @@ int tpm2_seal(
.size = sizeof(hmac_sensitive.sensitive),
.sensitive.data.size = 32,
};
+ if (pin) {
+ hash_pin(pin, strlen(pin), hmac_sensitive.sensitive.userAuth.buffer);
+ hmac_sensitive.sensitive.userAuth.size = SHA256_DIGEST_SIZE;
+ }
assert(sizeof(hmac_sensitive.sensitive.data.buffer) >= hmac_sensitive.sensitive.data.size);
(void) tpm2_credit_random(c.esys_context);
@@ -910,6 +949,7 @@ int tpm2_seal(
r = 0;
finish:
+ explicit_bzero_safe(&hmac_sensitive, sizeof(hmac_sensitive));
primary = flush_context_verbose(c.esys_context, primary);
return r;
}
@@ -923,6 +963,7 @@ int tpm2_unseal(
size_t blob_size,
const void *known_policy_hash,
size_t known_policy_hash_size,
+ const char *pin,
void **ret_secret,
size_t *ret_secret_size) {
@@ -978,7 +1019,7 @@ int tpm2_unseal(
if (r < 0)
return r;
- r = tpm2_make_pcr_session(c.esys_context, pcr_mask, pcr_bank, &session, &policy_digest, NULL);
+ r = tpm2_make_pcr_session(c.esys_context, pcr_mask, pcr_bank, !!pin, &session, &policy_digest, NULL);
if (r < 0)
goto finish;
@@ -1005,11 +1046,38 @@ int tpm2_unseal(
&public,
&hmac_key);
if (rc != TSS2_RC_SUCCESS) {
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
- "Failed to load HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc));
+ /* If we're in dictionary attack lockout mode, we should see a lockout error here, which we
+ * need to translate for the caller. */
+ if (rc == TPM2_RC_LOCKOUT)
+ r = log_error_errno(
+ SYNTHETIC_ERRNO(ENOLCK),
+ "TPM2 device is in dictionary attack lockout mode.");
+ else
+ r = log_error_errno(
+ SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+ "Failed to load HMAC key in TPM: %s",
+ sym_Tss2_RC_Decode(rc));
goto finish;
}
+ if (pin) {
+ TPM2B_AUTH auth = {
+ .size = SHA256_DIGEST_SIZE
+ };
+
+ hash_pin(pin, strlen(pin), auth.buffer);
+
+ rc = sym_Esys_TR_SetAuth(c.esys_context, hmac_key, &auth);
+ explicit_bzero_safe(&auth, sizeof(auth));
+ if (rc != TSS2_RC_SUCCESS) {
+ r = log_error_errno(
+ SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+ "Failed to load PIN in TPM: %s",
+ sym_Tss2_RC_Decode(rc));
+ goto finish;
+ }
+ }
+
log_debug("Unsealing HMAC key.");
rc = sym_Esys_Unseal(
@@ -1223,6 +1291,7 @@ int tpm2_make_luks2_json(
size_t blob_size,
const void *policy_hash,
size_t policy_hash_size,
+ TPM2Flags flags,
JsonVariant **ret) {
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *a = NULL;
@@ -1263,7 +1332,9 @@ int tpm2_make_luks2_json(
JSON_BUILD_PAIR("tpm2-pcrs", JSON_BUILD_VARIANT(a)),
JSON_BUILD_PAIR_CONDITION(!!tpm2_pcr_bank_to_string(pcr_bank), "tpm2-pcr-bank", JSON_BUILD_STRING(tpm2_pcr_bank_to_string(pcr_bank))),
JSON_BUILD_PAIR_CONDITION(!!tpm2_primary_alg_to_string(primary_alg), "tpm2-primary-alg", JSON_BUILD_STRING(tpm2_primary_alg_to_string(primary_alg))),
- JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_HEX(policy_hash, policy_hash_size))));
+ JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_HEX(policy_hash, policy_hash_size)),
+ JSON_BUILD_PAIR("tpm2-pin", JSON_BUILD_BOOLEAN(flags & TPM2_FLAGS_USE_PIN)))
+ );
if (r < 0)
return r;
diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h
index cb57a847e2..5a9bcf8c24 100644
--- a/src/shared/tpm2-util.h
+++ b/src/shared/tpm2-util.h
@@ -1,9 +1,15 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include <stdbool.h>
+
#include "json.h"
#include "macro.h"
+typedef enum TPM2Flags {
+ TPM2_FLAGS_USE_PIN = 1 << 0,
+} TPM2Flags;
+
#if HAVE_TPM2
#include <tss2/tss2_esys.h>
@@ -20,10 +26,12 @@ extern TSS2_RC (*sym_Esys_GetRandom)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1
extern TSS2_RC (*sym_Esys_Initialize)(ESYS_CONTEXT **esys_context, TSS2_TCTI_CONTEXT *tcti, TSS2_ABI_VERSION *abiVersion);
extern TSS2_RC (*sym_Esys_Load)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_PRIVATE *inPrivate, const TPM2B_PUBLIC *inPublic, ESYS_TR *objectHandle);
extern TSS2_RC (*sym_Esys_PCR_Read)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1,ESYS_TR shandle2, ESYS_TR shandle3, const TPML_PCR_SELECTION *pcrSelectionIn, UINT32 *pcrUpdateCounter, TPML_PCR_SELECTION **pcrSelectionOut, TPML_DIGEST **pcrValues);
+extern TSS2_RC (*sym_Esys_PolicyAuthValue)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3);
extern TSS2_RC (*sym_Esys_PolicyGetDigest)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_DIGEST **policyDigest);
extern TSS2_RC (*sym_Esys_PolicyPCR)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_DIGEST *pcrDigest, const TPML_PCR_SELECTION *pcrs);
extern TSS2_RC (*sym_Esys_StartAuthSession)(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey, ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType, const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash, ESYS_TR *sessionHandle);
extern TSS2_RC (*sym_Esys_Startup)(ESYS_CONTEXT *esysContext, TPM2_SU startupType);
+extern TSS2_RC (*sym_Esys_TR_SetAuth)(ESYS_CONTEXT *esysContext, ESYS_TR handle, TPM2B_AUTH const *authValue);
extern TSS2_RC (*sym_Esys_Unseal)(ESYS_CONTEXT *esysContext, ESYS_TR itemHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_SENSITIVE_DATA **outData);
extern const char* (*sym_Tss2_RC_Decode)(TSS2_RC rc);
@@ -35,8 +43,8 @@ extern TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal)(uint8_t const buffer[], siz
int dlopen_tpm2(void);
-int tpm2_seal(const char *device, uint32_t pcr_mask, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size, uint16_t *ret_pcr_bank, uint16_t *ret_primary_alg);
-int tpm2_unseal(const char *device, uint32_t pcr_mask, uint16_t pcr_bank, uint16_t primary_alg, const void *blob, size_t blob_size, const void *pcr_hash, size_t pcr_hash_size, void **ret_secret, size_t *ret_secret_size);
+int tpm2_seal(const char *device, uint32_t pcr_mask, const char *pin, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size, uint16_t *ret_pcr_bank, uint16_t *ret_primary_alg);
+int tpm2_unseal(const char *device, uint32_t pcr_mask, uint16_t pcr_bank, uint16_t primary_alg, const void *blob, size_t blob_size, const void *pcr_hash, size_t pcr_hash_size, const char *pin, void **ret_secret, size_t *ret_secret_size);
#endif
@@ -45,7 +53,7 @@ int tpm2_find_device_auto(int log_level, char **ret);
int tpm2_parse_pcrs(const char *s, uint32_t *ret);
-int tpm2_make_luks2_json(int keyslot, uint32_t pcr_mask, uint16_t pcr_bank, uint16_t primary_alg, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, JsonVariant **ret);
+int tpm2_make_luks2_json(int keyslot, uint32_t pcr_mask, uint16_t pcr_bank, uint16_t primary_alg, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, TPM2Flags flags, JsonVariant **ret);
#define TPM2_PCRS_MAX 24
diff --git a/src/shutdown/test-umount.c b/src/shutdown/test-umount.c
index 676c6dd862..56fcff05b1 100644
--- a/src/shutdown/test-umount.c
+++ b/src/shutdown/test-umount.c
@@ -9,7 +9,7 @@
#include "umount.h"
#include "util.h"
-static void test_mount_points_list(const char *fname) {
+static void test_mount_points_list_one(const char *fname) {
_cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head);
_cleanup_free_ char *testdata_fname = NULL;
MountPoint *m;
@@ -33,7 +33,14 @@ static void test_mount_points_list(const char *fname) {
major(m->devnum), minor(m->devnum));
}
-static void test_swap_list(const char *fname) {
+TEST(mount_points_list) {
+ test_mount_points_list_one(NULL);
+ test_mount_points_list_one("/test-umount/empty.mountinfo");
+ test_mount_points_list_one("/test-umount/garbled.mountinfo");
+ test_mount_points_list_one("/test-umount/rhbug-1554943.mountinfo");
+}
+
+static void test_swap_list_one(const char *fname) {
_cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head);
_cleanup_free_ char *testdata_fname = NULL;
MountPoint *m;
@@ -61,14 +68,9 @@ static void test_swap_list(const char *fname) {
major(m->devnum), minor(m->devnum));
}
-int main(int argc, char **argv) {
- test_setup_logging(LOG_DEBUG);
-
- test_mount_points_list(NULL);
- test_mount_points_list("/test-umount/empty.mountinfo");
- test_mount_points_list("/test-umount/garbled.mountinfo");
- test_mount_points_list("/test-umount/rhbug-1554943.mountinfo");
-
- test_swap_list(NULL);
- test_swap_list("/test-umount/example.swaps");
+TEST(swap_list) {
+ test_swap_list_one(NULL);
+ test_swap_list_one("/test-umount/example.swaps");
}
+
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/timesync/test-timesync.c b/src/timesync/test-timesync.c
index 31e91e7b7b..7993e4c12b 100644
--- a/src/timesync/test-timesync.c
+++ b/src/timesync/test-timesync.c
@@ -7,7 +7,7 @@
#include "timesyncd-conf.h"
#include "tests.h"
-static void test_manager_parse_string(void) {
+TEST(manager_parse_string) {
/* Make sure that NTP_SERVERS is configured to something
* that we can actually parse successfully. */
@@ -25,10 +25,4 @@ static void test_manager_parse_string(void) {
assert_se(manager_parse_server_string(m, SERVER_LINK, "time1.foobar.com time2.foobar.com axrfav.,avf..ra 12345..123") == 0);
}
-int main(int argc, char **argv) {
- test_setup_logging(LOG_DEBUG);
-
- test_manager_parse_string();
-
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/udev/fido_id/test-fido-id-desc.c b/src/udev/fido_id/test-fido-id-desc.c
index 6836bca28d..36c777a09e 100644
--- a/src/udev/fido_id/test-fido-id-desc.c
+++ b/src/udev/fido_id/test-fido-id-desc.c
@@ -5,8 +5,9 @@
#include "fido_id_desc.h"
#include "macro.h"
+#include "tests.h"
-static void test_is_fido_security_token_desc__fido(void) {
+TEST(is_fido_security_token_desc__fido) {
static const uint8_t FIDO_HID_DESC_1[] = {
0x06, 0xd0, 0xf1, 0x09, 0x01, 0xa1, 0x01, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75,
0x08, 0x95, 0x40, 0x81, 0x02, 0x09, 0x21, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95,
@@ -27,7 +28,7 @@ static void test_is_fido_security_token_desc__fido(void) {
assert_se(is_fido_security_token_desc(FIDO_HID_DESC_2, sizeof(FIDO_HID_DESC_2)) > 0);
}
-static void test_is_fido_security_token_desc__non_fido(void) {
+TEST(is_fido_security_token_desc__non_fido) {
/* Wrong usage page */
static const uint8_t NON_FIDO_HID_DESC_1[] = {
0x06, 0xd0, 0xf0, 0x09, 0x01, 0xa1, 0x01, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75,
@@ -54,7 +55,7 @@ static void test_is_fido_security_token_desc__non_fido(void) {
assert_se(is_fido_security_token_desc(NON_FIDO_HID_DESC_3, sizeof(NON_FIDO_HID_DESC_3)) == 0);
}
-static void test_is_fido_security_token_desc__invalid(void) {
+TEST(is_fido_security_token_desc__invalid) {
/* Size coded on 1 byte, but no byte given */
static const uint8_t INVALID_HID_DESC_1[] = { 0x01 };
assert_se(is_fido_security_token_desc(INVALID_HID_DESC_1, sizeof(INVALID_HID_DESC_1)) < 0);
@@ -76,10 +77,4 @@ static void test_is_fido_security_token_desc__invalid(void) {
assert_se(is_fido_security_token_desc(INVALID_HID_DESC_5, sizeof(INVALID_HID_DESC_5)) < 0);
}
-int main(int argc, char *argv[]) {
- test_is_fido_security_token_desc__fido();
- test_is_fido_security_token_desc__non_fido();
- test_is_fido_security_token_desc__invalid();
-
- return EXIT_SUCCESS;
-}
+DEFINE_TEST_MAIN(LOG_INFO);
diff --git a/src/udev/test-udev-builtin.c b/src/udev/test-udev-builtin.c
index 21a8ea3fa6..2ce7f196fd 100644
--- a/src/udev/test-udev-builtin.c
+++ b/src/udev/test-udev-builtin.c
@@ -3,9 +3,7 @@
#include "tests.h"
#include "udev-builtin.h"
-static void test_udev_builtin_cmd_to_ptr(void) {
- log_info("/* %s */", __func__);
-
+TEST(udev_builtin_cmd_to_ptr) {
/* Those could have been static asserts, but ({}) is not allowed there. */
#if HAVE_BLKID
assert_se(UDEV_BUILTIN_CMD_TO_PTR(UDEV_BUILTIN_BLKID));
@@ -19,8 +17,4 @@ static void test_udev_builtin_cmd_to_ptr(void) {
assert_se(PTR_TO_UDEV_BUILTIN_CMD((void*) 10000) == _UDEV_BUILTIN_INVALID);
}
-int main(int argc, char *argv[]) {
- test_setup_logging(LOG_DEBUG);
-
- test_udev_builtin_cmd_to_ptr();
-}
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/udev/test-udev-netlink.c b/src/udev/test-udev-netlink.c
index c1213b7ca8..1fddb5efb1 100644
--- a/src/udev/test-udev-netlink.c
+++ b/src/udev/test-udev-netlink.c
@@ -132,12 +132,10 @@ static void test_link_info_one(sd_netlink *rtnl, int ifindex) {
}
}
-static void test_link_info_get(void) {
+TEST(link_info_get) {
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
- log_debug("/* %s */", __func__);
-
assert_se(sd_netlink_open(&rtnl) >= 0);
assert_se(sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0) >= 0);
@@ -156,10 +154,4 @@ static void test_link_info_get(void) {
}
}
-int main(int argc, char *argv[]) {
- test_setup_logging(LOG_DEBUG);
-
- test_link_info_get();
-
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/udev/test-udev-node.c b/src/udev/test-udev-node.c
index 010c19acf5..b5eaa0de58 100644
--- a/src/udev/test-udev-node.c
+++ b/src/udev/test-udev-node.c
@@ -13,7 +13,7 @@ static void test_udev_node_escape_path_one(const char *path, const char *expecte
assert_se(streq(buf, expected));
}
-static void test_udev_node_escape_path(void) {
+TEST(udev_node_escape_path) {
char a[NAME_MAX+1], b[NAME_MAX+1];
test_udev_node_escape_path_one("/disk/by-id/nvme-eui.1922908022470001001b448b44ccb9d6", "\\x2fdisk\\x2fby-id\\x2fnvme-eui.1922908022470001001b448b44ccb9d6");
@@ -47,10 +47,4 @@ static void test_udev_node_escape_path(void) {
test_udev_node_escape_path_one(a, b);
}
-int main(int argc, char *argv[]) {
- test_setup_logging(LOG_INFO);
-
- test_udev_node_escape_path();
-
- return 0;
-}
+DEFINE_TEST_MAIN(LOG_INFO);
diff --git a/src/xdg-autostart-generator/test-xdg-autostart.c b/src/xdg-autostart-generator/test-xdg-autostart.c
index c7a816bc25..841a5606f6 100644
--- a/src/xdg-autostart-generator/test-xdg-autostart.c
+++ b/src/xdg-autostart-generator/test-xdg-autostart.c
@@ -9,7 +9,7 @@
#include "tmpfile-util.h"
#include "xdg-autostart-service.h"
-static void test_translate_name(void) {
+TEST(translate_name) {
_cleanup_free_ char *t;
assert_se(t = xdg_autostart_service_translate_name("a-b.blub.desktop"));
@@ -24,7 +24,7 @@ static void test_xdg_format_exec_start_one(const char *exec, const char *expecte
assert_se(streq(out, expected));
}
-static void test_xdg_format_exec_start(void) {
+TEST(xdg_format_exec_start) {
test_xdg_format_exec_start_one("/bin/sleep 100", "/bin/sleep \"100\"");
/* All standardised % identifiers are stripped. */
@@ -50,7 +50,7 @@ static const char* const xdg_desktop_file[] = {
"Hidden=\t true\n"),
};
-static void test_xdg_desktop_parse(unsigned i, const char *s) {
+static void test_xdg_desktop_parse_one(unsigned i, const char *s) {
_cleanup_(unlink_tempfilep) char name[] = "/tmp/test-xdg-autostart-parser.XXXXXX";
_cleanup_fclose_ FILE *f = NULL;
_cleanup_(xdg_autostart_service_freep) XdgAutostartService *service = NULL;
@@ -80,14 +80,9 @@ static void test_xdg_desktop_parse(unsigned i, const char *s) {
}
}
-int main(int argc, char *argv[]) {
- test_setup_logging(LOG_DEBUG);
-
- test_translate_name();
- test_xdg_format_exec_start();
-
+TEST(xdg_desktop_parse) {
for (size_t i = 0; i < ELEMENTSOF(xdg_desktop_file); i++)
- test_xdg_desktop_parse(i, xdg_desktop_file[i]);
-
- return 0;
+ test_xdg_desktop_parse_one(i, xdg_desktop_file[i]);
}
+
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/test/TEST-70-TPM2/Makefile b/test/TEST-70-TPM2/Makefile
new file mode 100644
index 0000000000..9f65d4ca4f
--- /dev/null
+++ b/test/TEST-70-TPM2/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+all setup run clean clean-again:
+ @TEST_BASE_DIR=../ ./test.sh --$@
+
+.PHONY: all setup run clean clean-again
diff --git a/test/TEST-70-TPM2/test.sh b/test/TEST-70-TPM2/test.sh
new file mode 100755
index 0000000000..d716614bcf
--- /dev/null
+++ b/test/TEST-70-TPM2/test.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -e
+
+TEST_DESCRIPTION="cryptenroll/cryptsetup with TPM2 devices"
+IMAGE_NAME="tpm2"
+TEST_NO_NSPAWN=1
+TEST_REQUIRE_INSTALL_TESTS=0
+
+# shellcheck source=test/test-functions
+. "${TEST_BASE_DIR:?}/test-functions"
+
+command -v swtpm >/dev/null 2>&1 || exit 0
+command -v tpm2_pcrextend >/dev/null 2>&1 || exit 0
+
+test_append_files() {
+ (
+ local workspace="${1:?}"
+
+ instmods tpm tpm_tis tpm_ibmvtpm
+ install_dmevent
+ generate_module_dependencies
+ inst_binary tpm2_pcrextend
+ )
+}
+
+machine="$(uname -m)"
+tpmdevice="tpm-tis"
+if [ "$machine" = "ppc64le" ]; then
+ # tpm-spapr support was introduced in qemu 5.0.0. Skip test for old qemu versions.
+ qemu_min_version "5.0.0" || exit 0
+ tpmdevice="tpm-spapr"
+fi
+
+tpmstate=$(mktemp -d)
+swtpm socket --tpm2 --tpmstate dir="$tpmstate" --ctrl type=unixio,path="$tpmstate/sock" &
+trap 'kill %%; rm -rf $tpmstate' SIGINT EXIT
+QEMU_OPTIONS="-chardev socket,id=chrtpm,path=$tpmstate/sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device $tpmdevice,tpmdev=tpm0"
+
+do_test "$@"
diff --git a/test/test-functions b/test/test-functions
index e815ce1c58..6619a7a44b 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -1213,7 +1213,7 @@ install_missing_libraries() {
local lib path
# A number of dependencies is now optional via dlopen, so the install
# script will not pick them up, since it looks at linkage.
- for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu libfido2 libbpf libelf libdw; do
+ for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu tss2-tcti-device libfido2 libbpf libelf libdw; do
ddebug "Searching for $lib via pkg-config"
if pkg-config --exists "$lib"; then
path="$(pkg-config --variable=libdir "$lib")"
diff --git a/test/units/testsuite-70.service b/test/units/testsuite-70.service
new file mode 100644
index 0000000000..c13c2d51a3
--- /dev/null
+++ b/test/units/testsuite-70.service
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Unit]
+Description=TEST-70-TPM2
+
+[Service]
+Type=oneshot
+ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
diff --git a/test/units/testsuite-70.sh b/test/units/testsuite-70.sh
new file mode 100755
index 0000000000..f395ef4e5e
--- /dev/null
+++ b/test/units/testsuite-70.sh
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -ex
+
+export SYSTEMD_LOG_LEVEL=debug
+
+
+# Prepare fresh disk image
+img="/var/tmp/test.img"
+dd if=/dev/zero of=$img bs=1024k count=20 status=none
+echo -n passphrase >/tmp/passphrase
+cryptsetup luksFormat -q --use-urandom $img /tmp/passphrase
+
+# Enroll unlock with default PCR policy
+env PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto $img
+/usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1
+/usr/lib/systemd/systemd-cryptsetup detach test-volume
+
+# Check with wrong PCR
+tpm2_pcrextend 7:sha256=0000000000000000000000000000000000000000000000000000000000000000
+/usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; }
+
+# Enroll unlock with PCR+PIN policy
+systemd-cryptenroll --wipe-slot=tpm2 $img
+env PASSWORD=passphrase NEWPIN=123456 systemd-cryptenroll --tpm2-device=auto --tpm2-with-pin=true $img
+env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1
+/usr/lib/systemd/systemd-cryptsetup detach test-volume
+
+# Check failure with wrong PIN
+env PIN=123457 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; }
+
+# Check failure with wrong PCR (and correct PIN)
+tpm2_pcrextend 7:sha256=0000000000000000000000000000000000000000000000000000000000000000
+env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; }
+
+# Enroll unlock with PCR 0+7
+systemd-cryptenroll --wipe-slot=tpm2 $img
+env PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 $img
+/usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1
+/usr/lib/systemd/systemd-cryptsetup detach test-volume
+
+# Check with wrong PCR 0
+tpm2_pcrextend 0:sha256=0000000000000000000000000000000000000000000000000000000000000000
+/usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && exit 1
+
+echo OK >/testok
+
+exit 0