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
)