diff --git a/man/os-release.xml b/man/os-release.xml index fc880c4765..168c1675a9 100644 --- a/man/os-release.xml +++ b/man/os-release.xml @@ -411,6 +411,18 @@ determines the fallback hostname. + + ARCHITECTURE= + A string that specifies which CPU architecture the userspace binaries require. + The architecture identifiers are the same as for ConditionArchitecture= + described in systemd.unit5. + The field is optional and should only be used when just single architecture is supported. + It may provide redundant information when used in a GPT partition with a GUID type that already + encodes the architecture. If this is not the case, the architecture should be specified in + e.g., an extension image, to prevent an incompatible host from loading it. + + + SYSEXT_LEVEL= diff --git a/man/systemd-sysext.xml b/man/systemd-sysext.xml index c2cf87c9cb..8da6bd26ad 100644 --- a/man/systemd-sysext.xml +++ b/man/systemd-sysext.xml @@ -118,10 +118,14 @@ file: the contained ID= fields have to match unless _any is set for the extension. If the extension ID= is not _any, the SYSEXT_LEVEL= field (if defined) has to match. If the latter is not defined, the - VERSION_ID= field has to match instead. System extensions should not ship a - /usr/lib/os-release file (as that would be merged into the host - /usr/ tree, overriding the host OS version data, which is not desirable). The - extension-release file follows the same format and semantics, and carries the same + VERSION_ID= field has to match instead. If the extension defines the + ARCHITECTURE= field and the value is not _any it has to match the kernel's + architecture reported by uname2 + but the used architecture identifiers are the same as for ConditionArchitecture= + described in systemd.unit5. + System extensions should not ship a /usr/lib/os-release file (as that would be merged + into the host /usr/ tree, overriding the host OS version data, which is not desirable). + The extension-release file follows the same format and semantics, and carries the same content, as the os-release file of the OS, but it describes the resources carried in the extension image. diff --git a/src/shared/extension-release.c b/src/shared/extension-release.c index 681dcbf7f8..2da8e7ea94 100644 --- a/src/shared/extension-release.c +++ b/src/shared/extension-release.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "alloc-util.h" +#include "architecture.h" #include "env-util.h" #include "extension-release.h" #include "log.h" @@ -15,7 +16,7 @@ int extension_release_validate( const char *host_sysext_scope, char **extension_release) { - const char *extension_release_id = NULL, *extension_release_sysext_level = NULL; + const char *extension_release_id = NULL, *extension_release_sysext_level = NULL, *extension_architecture = NULL; assert(name); assert(!isempty(host_os_release_id)); @@ -48,6 +49,16 @@ int extension_release_validate( } } + /* When the architecture field is present and not '_any' it must match the host - for now just look at uname but in + * the future we could check if the kernel also supports 32 bit or binfmt has a translator set up for the architecture */ + extension_architecture = strv_env_pairs_get(extension_release, "ARCHITECTURE"); + if (!isempty(extension_architecture) && !streq(extension_architecture, "_any") && + !streq(architecture_to_string(uname_architecture()), extension_architecture)) { + log_debug("Extension '%s' is for architecture '%s', but deployed on top of '%s'.", + name, extension_architecture, architecture_to_string(uname_architecture())); + return 0; + } + extension_release_id = strv_env_pairs_get(extension_release, "ID"); if (isempty(extension_release_id)) { log_debug("Extension '%s' does not contain ID in extension-release but requested to match '%s' or be '_any'", diff --git a/test/test-functions b/test/test-functions index f7f467dfca..5dec5e28de 100644 --- a/test/test-functions +++ b/test/test-functions @@ -715,7 +715,8 @@ EOF export initdir="$TESTDIR/app-nodistro" mkdir -p "$initdir/usr/lib/extension-release.d" "$initdir/usr/lib/systemd/system" - ( echo "ID=_any" ) >"$initdir/usr/lib/extension-release.d/extension-release.app-nodistro" + ( echo "ID=_any" + echo "ARCHITECTURE=_any" ) >"$initdir/usr/lib/extension-release.d/extension-release.app-nodistro" echo MARKER=1 >"$initdir/usr/lib/systemd/system/some_file" mksquashfs "$initdir" "$oldinitdir/usr/share/app-nodistro.raw" -noappend )